From 33318314d8bb727fb187da9a68da89adc3a19607 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 21 Dec 2011 14:21:39 +0100 Subject: [PATCH 001/664] starting implementing assembly --- src/Mod/Assembly/App/AppAssembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index 724a1e17e643..5291e56727e8 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -44,7 +44,7 @@ void AppAssemblyExport initAssembly() // load dependend module try { Base::Interpreter().loadModule("Part"); - //Base::Interpreter().loadModule("Mesh"); + Base::Interpreter().loadModule("PartDesign"); } catch(const Base::Exception& e) { PyErr_SetString(PyExc_ImportError, e.what()); From 95c925976575ad23afde0a394e33b62a14535b0f Mon Sep 17 00:00:00 2001 From: jriegel Date: Mon, 2 Jan 2012 15:56:17 +0100 Subject: [PATCH 002/664] Run arbitrary scripts from Cmd command line --- .kdev4/.kdev4/FCMasterMerge.kdev4 | 10 + .kdev4/FCMasterMerge.kdev4 | 41 + FCMasterMerge.kdev4 | 3 + src/App/Application.cpp | 2 +- src/App/Application.cpp.orig | 2169 +++++++++++++++++++++++++++++ src/Mod/Assembly/DevAssembly.py | 3 + 6 files changed, 2227 insertions(+), 1 deletion(-) create mode 100644 .kdev4/.kdev4/FCMasterMerge.kdev4 create mode 100644 .kdev4/FCMasterMerge.kdev4 create mode 100644 FCMasterMerge.kdev4 create mode 100644 src/App/Application.cpp.orig create mode 100644 src/Mod/Assembly/DevAssembly.py diff --git a/.kdev4/.kdev4/FCMasterMerge.kdev4 b/.kdev4/.kdev4/FCMasterMerge.kdev4 new file mode 100644 index 000000000000..156919bbebc9 --- /dev/null +++ b/.kdev4/.kdev4/FCMasterMerge.kdev4 @@ -0,0 +1,10 @@ +[Buildset] +BuildItems=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x01\x00\x00\x00&\x00F\x00C\x00M\x00a\x00s\x00t\x00e\x00r\x00M\x00e\x00r\x00g\x00e\x00.\x00k\x00d\x00e\x00v\x004) + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Project] +VersionControlSupport=kdevgit diff --git a/.kdev4/FCMasterMerge.kdev4 b/.kdev4/FCMasterMerge.kdev4 new file mode 100644 index 000000000000..819035e25c21 --- /dev/null +++ b/.kdev4/FCMasterMerge.kdev4 @@ -0,0 +1,41 @@ +[CMake] +Build Directory Count=1 +Current Build Directory Index=0 +ProjectRootRelative=./ + +[CMake][CMake Build Directory 0] +Build Directory Path=file:///home/stefan/Projects/FCMasterMerge/build +Build Type=Debug +CMake Binary=file:///usr/bin/cmake +Environment Profile= +Extra Arguments= +Install Directory=file:///usr/local + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Launch] +Launch Configurations=Launch Configuration 0 + +[Launch][Launch Configuration 0] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=FreeCADMain +Type=Native Application + +[Launch][Launch Configuration 0][Data] +Arguments= +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x01\x00\x00\x00\x0b\x00\x00\x00\x00\x04\x00\x00\x00\x1a\x00F\x00C\x00M\x00a\x00s\x00t\x00e\x00r\x00M\x00e\x00r\x00g\x00e\x00\x00\x00\x06\x00s\x00r\x00c\x00\x00\x00\x08\x00M\x00a\x00i\x00n\x00\x00\x00\x16\x00F\x00r\x00e\x00e\x00C\x00A\x00D\x00M\x00a\x00i\x00n) +Dependency Action=Nothing +EnvironmentGroup= +Executable=file:///home/stefan/Projects/FCMasterMerge/build/bin/FreeCAD +External Terminal=konsole --noclose --workdir %workdir -e %exe +Project Target=FCMasterMerge,src,Main,FreeCADMain +Use External Terminal=false +Working Directory= +isExecutable=true + +[Project] +VersionControlSupport=kdevgit diff --git a/FCMasterMerge.kdev4 b/FCMasterMerge.kdev4 new file mode 100644 index 000000000000..1aa8760a5815 --- /dev/null +++ b/FCMasterMerge.kdev4 @@ -0,0 +1,3 @@ +[Project] +Manager=KDevCMakeManager +Name=FCMasterMerge diff --git a/src/App/Application.cpp b/src/App/Application.cpp index e8adf113270e..333c680c1bd5 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1334,7 +1334,7 @@ void Application::processFiles(const std::list& files) Base::Interpreter().runFile(file.filePath().c_str(), true); } else if (file.hasExtension("py")) { - try { + try{ Base::Interpreter().loadModule(file.fileNamePure().c_str()); } catch(const PyException&) { diff --git a/src/App/Application.cpp.orig b/src/App/Application.cpp.orig new file mode 100644 index 000000000000..e123c760cf12 --- /dev/null +++ b/src/App/Application.cpp.orig @@ -0,0 +1,2169 @@ +/*************************************************************************** + * (c) Juergen Riegel (juergen.riegel@web.de) 2002 * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU Library General Public License (LGPL) * + * as published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * for detail see the LICENCE text file. * + * * + * 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with FreeCAD; if not, write to the Free Software * + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * + * USA * + * * + * Juergen Riegel 2002 * + ***************************************************************************/ + + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include +# include +# include +# if defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD) +# include +# include +# include +# elif defined(__MINGW32__) +# define WINVER 0x502 // needed for SetDllDirectory +# include +# endif +# include +# include +# include +#endif + +#ifdef FC_OS_WIN32 +# include +#endif + + + +#include "Application.h" +#include "Document.h" + +// FreeCAD Base header +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GeoFeature.h" +#include "FeatureTest.h" +#include "FeaturePython.h" +#include "ComplexGeoData.h" +#include "Property.h" +#include "PropertyContainer.h" +#include "PropertyUnits.h" +#include "PropertyFile.h" +#include "PropertyLinks.h" +#include "PropertyPythonObject.h" +#include "PropertyExpressionEngine.h" +#include "Document.h" +#include "DocumentObjectGroup.h" +#include "DocumentObjectFileIncluded.h" +#include "InventorObject.h" +#include "VRMLObject.h" +#include "Annotation.h" +#include "MeasureDistance.h" +#include "Placement.h" +#include "Plane.h" +#include "MaterialObject.h" +#include "Expression.h" + +// If you stumble here, run the target "BuildExtractRevision" on Windows systems +// or the Python script "SubWCRev.py" on Linux based systems which builds +// src/Build/Version.h. Or create your own from src/Build/Version.h.in! +#include +#include "Branding.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace App; +using namespace std; +using namespace boost; +using namespace boost::program_options; + + +// scriptings (scripts are build in but can be overridden by command line option) +#include "InitScript.h" +#include "TestScript.h" + +#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +# include +# include // VC exception handling +#else // Ansi C/C++ new handler +# include +#endif + + +//using Base::GetConsole; +using namespace Base; +using namespace App; +using namespace std; + + +//========================================================================== +// Application +//========================================================================== + +ParameterManager *App::Application::_pcSysParamMngr; +ParameterManager *App::Application::_pcUserParamMngr; +Base::ConsoleObserverStd *Application::_pConsoleObserverStd =0; +Base::ConsoleObserverFile *Application::_pConsoleObserverFile =0; + +AppExport std::map Application::mConfig; +BaseExport extern PyObject* Base::BaseExceptionFreeCADError; + + +//************************************************************************** +// Construction and destruction + +PyDoc_STRVAR(FreeCAD_doc, + "The functions in the FreeCAD module allow working with documents.\n" + "The FreeCAD instance provides a list of references of documents which\n" + "can be addressed by a string. Hence the document name must be unique.\n" + "\n" + "The document has the read-only attribute FileName which points to the\n" + "file the document should be stored to.\n" + ); + +PyDoc_STRVAR(Console_doc, + "FreeCAD Console\n" + ); + +Application::Application(ParameterManager * /*pcSysParamMngr*/, + ParameterManager * /*pcUserParamMngr*/, + std::map &mConfig) + ://_pcSysParamMngr(pcSysParamMngr), + //_pcUserParamMngr(pcUserParamMngr), + _mConfig(mConfig), + _pActiveDoc(0) +{ + //_hApp = new ApplicationOCC; + mpcPramManager["System parameter"] = _pcSysParamMngr; + mpcPramManager["User parameter"] = _pcUserParamMngr; + + + // setting up Python binding + Base::PyGILStateLocker lock; + PyObject* pAppModule = Py_InitModule3("FreeCAD", Application::Methods, FreeCAD_doc); + Py::Module(pAppModule).setAttr(std::string("ActiveDocument"),Py::None()); + + PyObject* pConsoleModule = Py_InitModule3("__FreeCADConsole__", ConsoleSingleton::Methods, Console_doc); + + // introducing additional classes + + // NOTE: To finish the initialization of our own type objects we must + // call PyType_Ready, otherwise we run into a segmentation fault, later on. + // This function is responsible for adding inherited slots from a type's base class. + if (PyType_Ready(&Base::VectorPy::Type) < 0) return; + union PyType_Object pyVecType = {&Base::VectorPy::Type}; + PyModule_AddObject(pAppModule, "Vector", pyVecType.o); + + if (PyType_Ready(&Base::MatrixPy::Type) < 0) return; + union PyType_Object pyMtxType = {&Base::MatrixPy::Type}; + PyModule_AddObject(pAppModule, "Matrix", pyMtxType.o); + + if (PyType_Ready(&Base::BoundBoxPy::Type) < 0) return; + union PyType_Object pyBoundBoxType = {&Base::BoundBoxPy::Type}; + PyModule_AddObject(pAppModule, "BoundBox", pyBoundBoxType.o); + + if (PyType_Ready(&Base::PlacementPy::Type) < 0) return; + union PyType_Object pyPlacementPyType = {&Base::PlacementPy::Type}; + PyModule_AddObject(pAppModule, "Placement", pyPlacementPyType.o); + + if (PyType_Ready(&Base::RotationPy::Type) < 0) return; + union PyType_Object pyRotationPyType = {&Base::RotationPy::Type}; + PyModule_AddObject(pAppModule, "Rotation", pyRotationPyType.o); + + if (PyType_Ready(&Base::AxisPy::Type) < 0) return; + union PyType_Object pyAxisPyType = {&Base::AxisPy::Type}; + PyModule_AddObject(pAppModule, "Axis", pyAxisPyType.o); + + // Note: Create an own module 'Base' which should provide the python + // binding classes from the base module. At a later stage we should + // remove these types from the FreeCAD module. + PyObject* pBaseModule = Py_InitModule3("__FreeCADBase__", NULL, + "The Base module contains the classes for the geometric basics\n" + "like vector, matrix, bounding box, placement, rotation, axis, ..."); + Base::BaseExceptionFreeCADError = PyErr_NewException( + "Base.FreeCADError", PyExc_RuntimeError, NULL); + Py_INCREF(Base::BaseExceptionFreeCADError); + PyModule_AddObject(pBaseModule, "FreeCADError", + Base::BaseExceptionFreeCADError); + Base::Interpreter().addType(&Base::VectorPy ::Type,pBaseModule,"Vector"); + Base::Interpreter().addType(&Base::MatrixPy ::Type,pBaseModule,"Matrix"); + Base::Interpreter().addType(&Base::BoundBoxPy ::Type,pBaseModule,"BoundBox"); + Base::Interpreter().addType(&Base::PlacementPy ::Type,pBaseModule,"Placement"); + Base::Interpreter().addType(&Base::RotationPy ::Type,pBaseModule,"Rotation"); + Base::Interpreter().addType(&Base::AxisPy ::Type,pBaseModule,"Axis"); + + //insert Base and Console + Py_INCREF(pBaseModule); + PyModule_AddObject(pAppModule, "Base", pBaseModule); + Py_INCREF(pConsoleModule); + PyModule_AddObject(pAppModule, "Console", pConsoleModule); + + //insert Units module + PyObject* pUnitsModule = Py_InitModule3("Units", Base::UnitsApi::Methods, + "The Unit API"); + Base::Interpreter().addType(&Base::QuantityPy ::Type,pUnitsModule,"Quantity"); + // make sure to set the 'nb_true_divide' slot + Base::QuantityPy::Type.tp_as_number->nb_true_divide = Base::QuantityPy::Type.tp_as_number->nb_divide; + Base::Interpreter().addType(&Base::UnitPy ::Type,pUnitsModule,"Unit"); + + Py_INCREF(pUnitsModule); + PyModule_AddObject(pAppModule, "Units", pUnitsModule); + + Base::ProgressIndicatorPy::init_type(); + Base::Interpreter().addType(Base::ProgressIndicatorPy::type_object(), + pBaseModule,"ProgressIndicator"); +} + +Application::~Application() +{ +} + +//************************************************************************** +// Interface + +/// get called by the document when the name is changing +void Application::renameDocument(const char *OldName, const char *NewName) +{ + std::map::iterator pos; + pos = DocMap.find(OldName); + + if (pos != DocMap.end()) { + Document* temp; + temp = pos->second; + DocMap.erase(pos); + DocMap[NewName] = temp; + signalRenameDocument(*temp); + } + else { + throw Base::Exception("Application::renameDocument(): no document with this name to rename!"); + } +} + +Document* Application::newDocument(const char * Name, const char * UserName) +{ + // get a valid name anyway! + if (!Name || Name[0] == '\0') + Name = "Unnamed"; + string name = getUniqueDocumentName(Name); + + std::string userName; + if (UserName && UserName[0] != '\0') { + userName = UserName; + } + else { + userName = Name; + std::vector names; + names.reserve(DocMap.size()); + std::map::const_iterator pos; + for (pos = DocMap.begin();pos != DocMap.end();++pos) { + names.push_back(pos->second->Label.getValue()); + } + + if (!names.empty()) + userName = Base::Tools::getUniqueName(userName, names); + } + + // create the FreeCAD document + auto_ptr newDoc(new Document() ); + + // add the document to the internal list + DocMap[name] = newDoc.release(); // now owned by the Application + _pActiveDoc = DocMap[name]; + + + // connect the signals to the application for the new document + _pActiveDoc->signalNewObject.connect(boost::bind(&App::Application::slotNewObject, this, _1)); + _pActiveDoc->signalDeletedObject.connect(boost::bind(&App::Application::slotDeletedObject, this, _1)); + _pActiveDoc->signalChangedObject.connect(boost::bind(&App::Application::slotChangedObject, this, _1, _2)); + _pActiveDoc->signalRelabelObject.connect(boost::bind(&App::Application::slotRelabelObject, this, _1)); + _pActiveDoc->signalActivatedObject.connect(boost::bind(&App::Application::slotActivatedObject, this, _1)); + _pActiveDoc->signalUndo.connect(boost::bind(&App::Application::slotUndoDocument, this, _1)); + _pActiveDoc->signalRedo.connect(boost::bind(&App::Application::slotRedoDocument, this, _1)); + + // make sure that the active document is set in case no GUI is up + { + Base::PyGILStateLocker lock; + Py::Object active(_pActiveDoc->getPyObject(), true); + Py::Module("FreeCAD").setAttr(std::string("ActiveDocument"),active); + } + + signalNewDocument(*_pActiveDoc); + + // set the UserName after notifying all observers + _pActiveDoc->Label.setValue(userName); + + return _pActiveDoc; +} + +bool Application::closeDocument(const char* name) +{ + map::iterator pos = DocMap.find( name ); + if (pos == DocMap.end()) // no such document + return false; + + // Trigger observers before removing the document from the internal map. + // Some observers might rely on this document still being there. + signalDeleteDocument(*pos->second); + + // For exception-safety use a smart pointer + if (_pActiveDoc == pos->second) + setActiveDocument((Document*)0); + auto_ptr delDoc (pos->second); + DocMap.erase( pos ); + + // Trigger observers after removing the document from the internal map. + signalDeletedDocument(); + + return true; +} + +void Application::closeAllDocuments(void) +{ + std::map::iterator pos; + while((pos = DocMap.begin()) != DocMap.end()) + closeDocument(pos->first.c_str()); +} + +App::Document* Application::getDocument(const char *Name) const +{ + std::map::const_iterator pos; + + pos = DocMap.find(Name); + + if (pos == DocMap.end()) + return 0; + + return pos->second; +} + +const char * Application::getDocumentName(const App::Document* doc) const +{ + for (std::map::const_iterator it = DocMap.begin(); it != DocMap.end(); ++it) + if (it->second == doc) + return it->first.c_str(); + + return 0; +} + +std::vector Application::getDocuments() const +{ + std::vector docs; + for (std::map::const_iterator it = DocMap.begin(); it != DocMap.end(); ++it) + docs.push_back(it->second); + return docs; +} + +std::string Application::getUniqueDocumentName(const char *Name) const +{ + if (!Name || *Name == '\0') + return std::string(); + std::string CleanName = Base::Tools::getIdentifier(Name); + + // name in use? + std::map::const_iterator pos; + pos = DocMap.find(CleanName); + + if (pos == DocMap.end()) { + // if not, name is OK + return CleanName; + } + else { + std::vector names; + names.reserve(DocMap.size()); + for (pos = DocMap.begin();pos != DocMap.end();++pos) { + names.push_back(pos->first); + } + return Base::Tools::getUniqueName(CleanName, names); + } +} + +Document* Application::openDocument(const char * FileName) +{ + FileInfo File(FileName); + + if (!File.exists()) { + std::stringstream str; + str << "File '" << FileName << "' does not exist!"; + throw Base::Exception(str.str().c_str()); + } + + // Before creating a new document we check whether the document is already open + std::string filepath = File.filePath(); + for (std::map::iterator it = DocMap.begin(); it != DocMap.end(); ++it) { + // get unique path separators + std::string fi = FileInfo(it->second->FileName.getValue()).filePath(); + if (filepath == fi) { + std::stringstream str; + str << "The project '" << FileName << "' is already open!"; + throw Base::Exception(str.str().c_str()); + } + } + + // Use the same name for the internal and user name. + // The file name is UTF-8 encoded which means that the internal name will be modified + // to only contain valid ASCII characters but the user name will be kept. + Document* newDoc = newDocument(File.fileNamePure().c_str(), File.fileNamePure().c_str()); + + newDoc->FileName.setValue(File.filePath()); + + // read the document + newDoc->restore(); + + return newDoc; +} + +Document* Application::getActiveDocument(void) const +{ + return _pActiveDoc; +} + +void Application::setActiveDocument(Document* pDoc) +{ + _pActiveDoc = pDoc; + + // make sure that the active document is set in case no GUI is up + if (pDoc) { + Base::PyGILStateLocker lock; + Py::Object active(pDoc->getPyObject(), true); + Py::Module("FreeCAD").setAttr(std::string("ActiveDocument"),active); + } + else { + Base::PyGILStateLocker lock; + Py::Module("FreeCAD").setAttr(std::string("ActiveDocument"),Py::None()); + } + + if (pDoc) + signalActiveDocument(*pDoc); +} + +void Application::setActiveDocument(const char *Name) +{ + // If no active document is set, resort to a default. + if (*Name == '\0') { + _pActiveDoc = 0; + return; + } + + std::map::iterator pos; + pos = DocMap.find(Name); + + if (pos != DocMap.end()) { + setActiveDocument(pos->second); + } + else { + std::stringstream s; + s << "Try to activate unknown document '" << Name << "'"; + throw Base::Exception(s.str()); + } +} + +const char* Application::getHomePath(void) const +{ + return _mConfig["AppHomePath"].c_str(); +} + +const char* Application::getExecutableName(void) const +{ + return _mConfig["ExeName"].c_str(); +} + +std::string Application::getTempPath() +{ + return mConfig["AppTempPath"]; +} + +std::string Application::getTempFileName(const char* FileName) +{ + return Base::FileInfo::getTempFileName(FileName, getTempPath().c_str()); +} + +std::string Application::getUserAppDataDir() +{ + return mConfig["UserAppData"]; +} + +std::string Application::getUserMacroDir() +{ + std::string path("Macro/"); + return mConfig["UserAppData"] + path; +} + +std::string Application::getResourceDir() +{ +#ifdef RESOURCEDIR + std::string path(RESOURCEDIR); + path.append("/"); + QDir dir(QString::fromUtf8(RESOURCEDIR)); + if (dir.isAbsolute()) + return path; + else + return mConfig["AppHomePath"] + path; +#else + return mConfig["AppHomePath"]; +#endif +} + +std::string Application::getHelpDir() +{ +#ifdef DOCDIR + std::string path(DOCDIR); + path.append("/"); + QDir dir(QString::fromUtf8(DOCDIR)); + if (dir.isAbsolute()) + return path; + else + return mConfig["AppHomePath"] + path; +#else + return mConfig["DocPath"]; +#endif +} + +ParameterManager & Application::GetSystemParameter(void) +{ + return *_pcSysParamMngr; +} + +ParameterManager & Application::GetUserParameter(void) +{ + return *_pcUserParamMngr; +} + +ParameterManager * Application::GetParameterSet(const char* sName) const +{ + std::map::const_iterator it = mpcPramManager.find(sName); + if ( it != mpcPramManager.end() ) + return it->second; + else + return 0; +} + +const std::map & Application::GetParameterSetList(void) const +{ + return mpcPramManager; +} + +void Application::AddParameterSet(const char* sName) +{ + std::map::const_iterator it = mpcPramManager.find(sName); + if ( it != mpcPramManager.end() ) + return; + mpcPramManager[sName] = new ParameterManager(); +} + +void Application::RemoveParameterSet(const char* sName) +{ + std::map::iterator it = mpcPramManager.find(sName); + // Must not delete user or system parameter + if ( it == mpcPramManager.end() || it->second == _pcUserParamMngr || it->second == _pcSysParamMngr ) + return; + delete it->second; + mpcPramManager.erase(it); +} + +Base::Reference Application::GetParameterGroupByPath(const char* sName) +{ + std::string cName = sName,cTemp; + + std::string::size_type pos = cName.find(':'); + + // is there a path seperator ? + if (pos == std::string::npos) { + throw Base::Exception("Application::GetParameterGroupByPath() no parameter set name specified"); + } + // assigning the parameter set name + cTemp.assign(cName,0,pos); + cName.erase(0,pos+1); + + // test if name is valid + std::map::iterator It = mpcPramManager.find(cTemp.c_str()); + if (It == mpcPramManager.end()) + throw Base::Exception("Application::GetParameterGroupByPath() unknown parameter set name specified"); + + return It->second->GetGroup(cName.c_str()); +} + +void Application::addImportType(const char* Type, const char* ModuleName) +{ + FileTypeItem item; + item.filter = Type; + item.module = ModuleName; + + // Extract each filetype from 'Type' literal + std::string::size_type pos = item.filter.find("*."); + while ( pos != std::string::npos ) { + std::string::size_type next = item.filter.find_first_of(" )", pos+1); + std::string::size_type len = next-pos-2; + std::string type = item.filter.substr(pos+2,len); + item.types.push_back(type); + pos = item.filter.find("*.", next); + } + + // Due to branding stuff replace "FreeCAD" with the branded application name + if (strncmp(Type, "FreeCAD", 7) == 0) { + std::string AppName = Config()["ExeName"]; + AppName += item.filter.substr(7); + item.filter = AppName; + // put to the front of the array + _mImportTypes.insert(_mImportTypes.begin(),item); + } + else { + _mImportTypes.push_back(item); + } +} + +std::vector Application::getImportModules(const char* Type) const +{ + std::vector modules; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + modules.push_back(it->module); + } + } + + return modules; +} + +std::vector Application::getImportModules() const +{ + std::vector modules; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) + modules.push_back(it->module); + std::sort(modules.begin(), modules.end()); + modules.erase(std::unique(modules.begin(), modules.end()), modules.end()); + return modules; +} + +std::vector Application::getImportTypes(const char* Module) const +{ + std::vector types; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { +#ifdef __GNUC__ + if (strcasecmp(Module,it->module.c_str()) == 0) +#else + if (_stricmp(Module,it->module.c_str()) == 0) +#endif + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + return types; +} + +std::vector Application::getImportTypes(void) const +{ + std::vector types; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + std::sort(types.begin(), types.end()); + types.erase(std::unique(types.begin(), types.end()), types.end()); + + return types; +} + +std::map Application::getImportFilters(const char* Type) const +{ + std::map moduleFilter; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + moduleFilter[it->filter] = it->module; + } + } + + return moduleFilter; +} + +std::map Application::getImportFilters(void) const +{ + std::map filter; + for (std::vector::const_iterator it = _mImportTypes.begin(); it != _mImportTypes.end(); ++it) { + filter[it->filter] = it->module; + } + + return filter; +} + +void Application::addExportType(const char* Type, const char* ModuleName) +{ + FileTypeItem item; + item.filter = Type; + item.module = ModuleName; + + // Extract each filetype from 'Type' literal + std::string::size_type pos = item.filter.find("*."); + while ( pos != std::string::npos ) { + std::string::size_type next = item.filter.find_first_of(" )", pos+1); + std::string::size_type len = next-pos-2; + std::string type = item.filter.substr(pos+2,len); + item.types.push_back(type); + pos = item.filter.find("*.", next); + } + + // Due to branding stuff replace "FreeCAD" with the branded application name + if (strncmp(Type, "FreeCAD", 7) == 0) { + std::string AppName = Config()["ExeName"]; + AppName += item.filter.substr(7); + item.filter = AppName; + // put to the front of the array + _mExportTypes.insert(_mExportTypes.begin(),item); + } + else { + _mExportTypes.push_back(item); + } +} + +std::vector Application::getExportModules(const char* Type) const +{ + std::vector modules; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + modules.push_back(it->module); + } + } + + return modules; +} + +std::vector Application::getExportModules() const +{ + std::vector modules; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) + modules.push_back(it->module); + std::sort(modules.begin(), modules.end()); + modules.erase(std::unique(modules.begin(), modules.end()), modules.end()); + return modules; +} + +std::vector Application::getExportTypes(const char* Module) const +{ + std::vector types; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { +#ifdef __GNUC__ + if (strcasecmp(Module,it->module.c_str()) == 0) +#else + if (_stricmp(Module,it->module.c_str()) == 0) +#endif + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + return types; +} + +std::vector Application::getExportTypes(void) const +{ + std::vector types; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + types.insert(types.end(), it->types.begin(), it->types.end()); + } + + std::sort(types.begin(), types.end()); + types.erase(std::unique(types.begin(), types.end()), types.end()); + + return types; +} + +std::map Application::getExportFilters(const char* Type) const +{ + std::map moduleFilter; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + const std::vector& types = it->types; + for (std::vector::const_iterator jt = types.begin(); jt != types.end(); ++jt) { +#ifdef __GNUC__ + if (strcasecmp(Type,jt->c_str()) == 0) +#else + if (_stricmp(Type,jt->c_str()) == 0) +#endif + moduleFilter[it->filter] = it->module; + } + } + + return moduleFilter; +} + +std::map Application::getExportFilters(void) const +{ + std::map filter; + for (std::vector::const_iterator it = _mExportTypes.begin(); it != _mExportTypes.end(); ++it) { + filter[it->filter] = it->module; + } + + return filter; +} + +//************************************************************************** +// signaling +void Application::slotNewObject(const App::DocumentObject&O) +{ + this->signalNewObject(O); +} + +void Application::slotDeletedObject(const App::DocumentObject&O) +{ + this->signalDeletedObject(O); +} + +void Application::slotChangedObject(const App::DocumentObject&O, const App::Property& P) +{ + this->signalChangedObject(O,P); +} + +void Application::slotRelabelObject(const App::DocumentObject&O) +{ + this->signalRelabelObject(O); +} + +void Application::slotActivatedObject(const App::DocumentObject&O) +{ + this->signalActivatedObject(O); +} + +void Application::slotUndoDocument(const App::Document& d) +{ + this->signalUndoDocument(d); +} + +void Application::slotRedoDocument(const App::Document& d) +{ + this->signalRedoDocument(d); +} + +//************************************************************************** +// Init, Destruct and singleton + +Application * Application::_pcSingleton = 0; + +int Application::_argc; +char ** Application::_argv; + + +void Application::destruct(void) +{ + // saving system parameter + Console().Log("Saving system parameter...\n"); + _pcSysParamMngr->SaveDocument(mConfig["SystemParameter"].c_str()); + // saving the User parameter + Console().Log("Saving system parameter...done\n"); + Console().Log("Saving user parameter...\n"); + _pcUserParamMngr->SaveDocument(mConfig["UserParameter"].c_str()); + Console().Log("Saving user parameter...done\n"); + // clean up + delete _pcSysParamMngr; + delete _pcUserParamMngr; + + // not initialized or doubel destruct! + assert(_pcSingleton); + delete _pcSingleton; + + // We must detach from console and delete the observer to save our file + destructObserver(); + + Base::Interpreter().finalize(); + + ScriptFactorySingleton::Destruct(); + InterpreterSingleton::Destruct(); + Base::Type::destruct(); +} + +void Application::destructObserver(void) +{ + if ( _pConsoleObserverFile ) { + Console().DetachObserver(_pConsoleObserverFile); + delete _pConsoleObserverFile; + _pConsoleObserverFile = 0; + } + if ( _pConsoleObserverStd ) { + Console().DetachObserver(_pConsoleObserverStd); + delete _pConsoleObserverStd; + _pConsoleObserverStd = 0; + } +} + +/** freecadNewHandler() + * prints an error message and throws an exception + */ +#ifdef _MSC_VER // New handler for Microsoft Visual C++ compiler +int __cdecl freecadNewHandler(size_t size ) +{ + // throw an exception + throw Base::MemoryException(); + return 0; +} +#else // Ansi C/C++ new handler +static void freecadNewHandler () +{ + // throw an exception + throw Base::MemoryException(); +} +#endif + +void segmentation_fault_handler(int sig) +{ + switch (sig) { + case SIGSEGV: + std::cerr << "Illegal storage access..." << std::endl; +#if !defined(_DEBUG) + throw Base::Exception("Illegal storage access! Please save your work under a new file name and restart the application!"); +#endif + break; + case SIGABRT: + std::cerr << "Abnormal program termination..." << std::endl; +#if !defined(_DEBUG) + throw Base::Exception("Break signal occoured"); +#endif + break; + default: + std::cerr << "Unknown error occurred..." << std::endl; + break; + } +} + +void my_terminate_handler() +{ + std::cerr << "Terminating..." << std::endl; +} + +void unexpection_error_handler() +{ + std::cerr << "Unexpected error occurred..." << std::endl; + // try to throw an exception and give the user chance to save their work +#if !defined(_DEBUG) + throw Base::Exception("Unexpected error occurred! Please save your work under a new file name and restart the application!"); +#endif + + terminate(); +} + +#ifdef _MSC_VER // Microsoft compiler + +void my_trans_func( unsigned int code, EXCEPTION_POINTERS* pExp ) +{ + + //switch (code) + //{ + // case FLT_DIVIDE_BY_ZERO : + // //throw CMyFunkyDivideByZeroException(code, pExp); + // throw Base::Exception("Devision by zero!"); + // break; + //} + + // general C++ SEH exception for things we don't need to handle separately.... + throw Base::Exception("my_trans_func()"); +} +#endif +void Application::init(int argc, char ** argv) +{ + try { + // install our own new handler +#ifdef _MSC_VER // Microsoft compiler + _set_new_handler ( freecadNewHandler ); // Setup new handler + _set_new_mode( 1 ); // Re-route malloc failures to new handler ! +#else // Ansi compiler + std::set_new_handler (freecadNewHandler); // ANSI new handler +#endif + // if an unexpected crash occurs we can install a handler function to + // write some additional information +#ifdef _MSC_VER // Microsoft compiler + std::signal(SIGSEGV,segmentation_fault_handler); + std::signal(SIGABRT,segmentation_fault_handler); + std::set_terminate(my_terminate_handler); + std::set_unexpected(unexpection_error_handler); +// _set_se_translator(my_trans_func); +#endif + + initTypes(); + +#if (BOOST_VERSION < 104600) || (BOOST_FILESYSTEM_VERSION == 2) + boost::filesystem::path::default_name_check(boost::filesystem::no_check); +#endif + + initConfig(argc,argv); + initApplication(); + } + catch (...) { + // force the log to flush + destructObserver(); + throw; + } +} + +void Application::initTypes(void) +{ + // Base types + Base::Type ::init(); + Base::BaseClass ::init(); + Base::Exception ::init(); + Base::Persistence ::init(); + + // Complex data classes + Data::ComplexGeoData ::init(); + Data::Segment ::init(); + + // Properties + App ::Property ::init(); + App ::PropertyContainer ::init(); + App ::PropertyLists ::init(); + App ::PropertyBool ::init(); + App ::PropertyBoolList ::init(); + App ::PropertyFloat ::init(); + App ::PropertyFloatList ::init(); + App ::PropertyFloatConstraint ::init(); + App ::PropertyQuantity ::init(); + App ::PropertyQuantityConstraint::init(); + App ::PropertyAngle ::init(); + App ::PropertyDistance ::init(); + App ::PropertyLength ::init(); + App ::PropertySpeed ::init(); + App ::PropertyAcceleration ::init(); + App ::PropertyForce ::init(); + App ::PropertyPressure ::init(); + App ::PropertyInteger ::init(); + App ::PropertyIntegerConstraint ::init(); + App ::PropertyPercent ::init(); + App ::PropertyEnumeration ::init(); + App ::PropertyIntegerList ::init(); + App ::PropertyIntegerSet ::init(); + App ::PropertyMap ::init(); + App ::PropertyString ::init(); + App ::PropertyUUID ::init(); + App ::PropertyFont ::init(); + App ::PropertyStringList ::init(); + App ::PropertyLink ::init(); + App ::PropertyLinkSub ::init(); + App ::PropertyLinkList ::init(); + App ::PropertyLinkSubList ::init(); + App ::PropertyMatrix ::init(); + App ::PropertyVector ::init(); + App ::PropertyVectorDistance ::init(); + App ::PropertyVectorList ::init(); + App ::PropertyPlacement ::init(); + App ::PropertyPlacementLink ::init(); + App ::PropertyGeometry ::init(); + App ::PropertyComplexGeoData ::init(); + App ::PropertyColor ::init(); + App ::PropertyColorList ::init(); + App ::PropertyMaterial ::init(); + App ::PropertyPath ::init(); + App ::PropertyFile ::init(); + App ::PropertyFileIncluded ::init(); + App ::PropertyPythonObject ::init(); + App ::PropertyExpressionEngine ::init(); + + // Document classes + App ::DocumentObject ::init(); + App ::GeoFeature ::init(); + App ::FeatureTest ::init(); + App ::FeatureTestException ::init(); + App ::FeaturePython ::init(); + App ::GeometryPython ::init(); + App ::Document ::init(); + App ::DocumentObjectGroup ::init(); + App ::DocumentObjectGroupPython ::init(); + App ::DocumentObjectFileIncluded::init(); + App ::InventorObject ::init(); + App ::VRMLObject ::init(); + App ::Annotation ::init(); + App ::AnnotationLabel ::init(); + App ::MeasureDistance ::init(); + App ::MaterialObject ::init(); + App ::MaterialObjectPython ::init(); + App ::Placement ::init(); + App ::Plane ::init(); + + // Expression classes + App ::Expression ::init(); + App ::UnitExpression ::init(); + App ::NumberExpression ::init(); + App ::ConstantExpression ::init(); + App ::OperatorExpression ::init(); + App ::VariableExpression ::init(); + App ::ConditionalExpression ::init(); + App ::StringExpression ::init(); + App ::FunctionExpression ::init(); + +} + +void Application::initConfig(int argc, char ** argv) +{ + // find the home path.... + mConfig["AppHomePath"] = FindHomePath(argv[0]); + + // Version of the application extracted from SubWCRef into src/Build/Version.h + // We only set these keys if not yet defined. Therefore it suffices to search + // only for 'BuildVersionMajor'. + if (App::Application::Config().find("BuildVersionMajor") == App::Application::Config().end()) { + std::stringstream str; str << FCVersionMajor << "." << FCVersionMinor; + App::Application::Config()["ExeVersion" ] = str.str(); + App::Application::Config()["BuildVersionMajor" ] = FCVersionMajor; + App::Application::Config()["BuildVersionMinor" ] = FCVersionMinor; + App::Application::Config()["BuildRevision" ] = FCRevision; + App::Application::Config()["BuildRepositoryURL" ] = FCRepositoryURL; + App::Application::Config()["BuildRevisionDate" ] = FCRevisionDate; +#if defined(FCRepositoryHash) + App::Application::Config()["BuildRevisionHash" ] = FCRepositoryHash; +#endif +#if defined(FCRepositoryBranch) + App::Application::Config()["BuildRevisionBranch"] = FCRepositoryBranch; +#endif + } + + _argc = argc; + _argv = argv; + + // Now it's time to read-in the file branding.xml if it exists + Branding brand; + QString binDir = QString::fromUtf8((mConfig["AppHomePath"] + "bin").c_str()); + QFileInfo fi(binDir, QString::fromLatin1("branding.xml")); + if (brand.readFile(fi.absoluteFilePath())) { + Branding::XmlConfig cfg = brand.getUserDefines(); + for (Branding::XmlConfig::iterator it = cfg.begin(); it != cfg.end(); ++it) { + App::Application::Config()[it.key()] = it.value(); + } + } + + // extract home paths + ExtractUserPath(); + +# ifdef FC_DEBUG + mConfig["Debug"] = "1"; +# else + mConfig["Debug"] = "0"; +# endif + + // init python + mConfig["PythonSearchPath"] = Interpreter().init(argc,argv); + + // Parse the options which have impact to the init process + ParseOptions(argc,argv); + + // Init console =========================================================== + Base::PyGILStateLocker lock; + _pConsoleObserverStd = new ConsoleObserverStd(); + Console().AttachObserver(_pConsoleObserverStd); + if (mConfig["Verbose"] == "Strict") + Console().SetMode(ConsoleSingleton::Verbose); + + // file logging Init =========================================================== + if (mConfig["LoggingFile"] == "1") { + _pConsoleObserverFile = new ConsoleObserverFile(mConfig["LoggingFileName"].c_str()); + Console().AttachObserver(_pConsoleObserverFile); + } + else + _pConsoleObserverFile = 0; + + // Banner =========================================================== + if (!(mConfig["Verbose"] == "Strict")) + Console().Message("%s %s, Libs: %s.%sR%s\n%s",mConfig["ExeName"].c_str(), + mConfig["ExeVersion"].c_str(), + mConfig["BuildVersionMajor"].c_str(), + mConfig["BuildVersionMinor"].c_str(), + mConfig["BuildRevision"].c_str(), + mConfig["CopyrightInfo"].c_str()); + else + Console().Message("%s %s, Libs: %s.%sB%s\n",mConfig["ExeName"].c_str(), + mConfig["ExeVersion"].c_str(), + mConfig["BuildVersionMajor"].c_str(), + mConfig["BuildVersionMinor"].c_str(), + mConfig["BuildRevision"].c_str()); + + LoadParameters(); + + // Set application tmp. directory + mConfig["AppTempPath"] = Base::FileInfo::getTempPath(); + std::string tmpPath = _pcUserParamMngr->GetGroup("BaseApp/Preferences/General")->GetASCII("TempPath"); + Base::FileInfo di(tmpPath); + if (di.exists() && di.isDir()) { + mConfig["AppTempPath"] = tmpPath + "/"; + } + + + // capture python variables + SaveEnv("PYTHONPATH"); + SaveEnv("PYTHONHOME"); + SaveEnv("TCL_LIBRARY"); + SaveEnv("TCLLIBPATH"); + + // capture CasCade variables + SaveEnv("CSF_MDTVFontDirectory"); + SaveEnv("CSF_MDTVTexturesDirectory"); + SaveEnv("CSF_UnitsDefinition"); + SaveEnv("CSF_UnitsLexicon"); + SaveEnv("CSF_StandardDefaults"); + SaveEnv("CSF_PluginDefaults"); + SaveEnv("CSF_LANGUAGE"); + SaveEnv("CSF_SHMessage"); + SaveEnv("CSF_XCAFDefaults"); + SaveEnv("CSF_GraphicShr"); + SaveEnv("CSF_IGESDefaults"); + SaveEnv("CSF_STEPDefaults"); + + // capture path + SaveEnv("PATH"); + logStatus(); +} + +void Application::SaveEnv(const char* s) +{ + char *c = getenv(s); + if (c) + mConfig[s] = c; +} + +void Application::initApplication(void) +{ + // interpreter and Init script ========================================================== + // register scripts + new ScriptProducer( "FreeCADInit", FreeCADInit ); + new ScriptProducer( "FreeCADTest", FreeCADTest ); + + // creating the application + if (!(mConfig["Verbose"] == "Strict")) Console().Log("Create Application\n"); + Application::_pcSingleton = new Application(0,0,mConfig); + + // set up Unit system default + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Units"); + UnitsApi::setSchema((UnitSystem)hGrp->GetInt("UserSchema",0)); + +#if defined (_DEBUG) + Console().Log("Application is built with debug information\n"); +#endif + + // starting the init script + Console().Log("Run App init script\n"); + Interpreter().runString(Base::ScriptFactory().ProduceScript("FreeCADInit")); +} + +std::list Application::getCmdLineFiles() +{ + std::list files; + + // cycling through all the open files + unsigned short count = 0; + count = atoi(mConfig["OpenFileCount"].c_str()); + std::string File; + + for (unsigned short i=0; i& files) +{ + Base::Console().Log("Init: Processing command line files\n"); + for (std::list::const_iterator it = files.begin(); it != files.end(); ++it) { + Base::FileInfo file(*it); + + Base::Console().Log("Init: Processing file: %s\n",file.filePath().c_str()); + + try { + if (file.hasExtension("fcstd") || file.hasExtension("std")) { + // try to open + Application::_pcSingleton->openDocument(file.filePath().c_str()); + } + else if (file.hasExtension("fcscript") || file.hasExtension("fcmacro")) { + Base::Interpreter().runFile(file.filePath().c_str(), true); + } +<<<<<<< d9efca578bac2e53f02f6d1807be05cf950b405f + else if (file.hasExtension("py")) { + try { + Base::Interpreter().loadModule(file.fileNamePure().c_str()); +======= + else if (File.hasExtension("py")) { + try{ + Base::Interpreter().loadModule(File.fileNamePure().c_str()); +>>>>>>> Run arbitrary scripts from Cmd command line + } + catch(const PyException&) { + // if loading the module does not work, try just running the script (run in __main__) + Base::Interpreter().runFile(file.filePath().c_str(),true); + } + } + else { + std::string ext = file.extension(); + std::vector mods = App::GetApplication().getImportModules(ext.c_str()); + if (!mods.empty()) { + std::string escapedstr = Base::Tools::escapedUnicodeFromUtf8(file.filePath().c_str()); + Base::Interpreter().loadModule(mods.front().c_str()); + Base::Interpreter().runStringArg("import %s",mods.front().c_str()); + Base::Interpreter().runStringArg("%s.open(u\"%s\")",mods.front().c_str(), + escapedstr.c_str()); + Base::Console().Log("Command line open: %s.open(u\"%s\")\n",mods.front().c_str(),escapedstr.c_str()); + } + else { + Console().Warning("File format not supported: %s \n", file.filePath().c_str()); + } + } + } + catch (const Base::SystemExitException&) { + throw; // re-throw to main() function + } + catch (const Base::Exception& e) { + Console().Error("Exception while processing file: %s [%s]\n", file.filePath().c_str(), e.what()); + } + catch (...) { + Console().Error("Unknown exception while processing file: %s \n", file.filePath().c_str()); + } + } +} + +void Application::processCmdLineFiles(void) +{ + // process files passed to command line + std::list files = getCmdLineFiles(); + processFiles(files); + + if (files.empty()) { + if (mConfig["RunMode"] == "Exit") + mConfig["RunMode"] = "Cmd"; + } + + const std::map& cfg = Application::Config(); + std::map::const_iterator it = cfg.find("SaveFile"); + if (it != cfg.end()) { + std::string output = it->second; + Base::FileInfo fi(output); + std::string ext = fi.extension(); + try { + std::vector mods = App::GetApplication().getExportModules(ext.c_str()); + if (!mods.empty()) { + Base::Interpreter().loadModule(mods.front().c_str()); + Base::Interpreter().runStringArg("import %s",mods.front().c_str()); + Base::Interpreter().runStringArg("%s.export(App.ActiveDocument.Objects, '%s')" + ,mods.front().c_str(),output.c_str()); + } + else { + Console().Warning("File format not supported: %s \n", output.c_str()); + } + } + catch (const Base::Exception& e) { + Console().Error("Exception while saving to file: %s [%s]\n", output.c_str(), e.what()); + } + catch (...) { + Console().Error("Unknown exception while saving to file: %s \n", output.c_str()); + } + } +} + +void Application::runApplication() +{ + // process all files given through command line interface + processCmdLineFiles(); + + if (mConfig["RunMode"] == "Cmd") { + // Run the comandline interface + Interpreter().runCommandLine("FreeCAD Console mode"); + } + else if (mConfig["RunMode"] == "Internal") { + // run internal script + Console().Log("Running internal script:\n"); + Interpreter().runString(Base::ScriptFactory().ProduceScript(mConfig["ScriptFileName"].c_str())); + } + else if (mConfig["RunMode"] == "Exit") { + // geting out + Console().Log("Exiting on purpose\n"); + } + else { + Console().Log("Unknown Run mode (%d) in main()?!?\n\n",mConfig["RunMode"].c_str()); + } +} + +void Application::logStatus() +{ + time_t now; + time(&now); + Console().Log("Time = %s", ctime(&now)); + + for (std::map::iterator It = mConfig.begin();It!= mConfig.end();++It) { + Console().Log("%s = %s\n",It->first.c_str(),It->second.c_str()); + } +} + +void Application::LoadParameters(void) +{ + // create standard parameter sets + _pcSysParamMngr = new ParameterManager(); + _pcUserParamMngr = new ParameterManager(); + + // Init parameter sets =========================================================== + // + if (mConfig.find("UserParameter") == mConfig.end()) + mConfig["UserParameter"] = mConfig["UserAppData"] + "user.cfg"; + if (mConfig.find("SystemParameter") == mConfig.end()) + mConfig["SystemParameter"] = mConfig["UserAppData"] + "system.cfg"; + + + try { + if (_pcSysParamMngr->LoadOrCreateDocument(mConfig["SystemParameter"].c_str()) && !(mConfig["Verbose"] == "Strict")) { + // Configuration file optional when using as Python module + if (!Py_IsInitialized()) { + Console().Warning(" Parameter does not exist, writing initial one\n"); + Console().Message(" This warning normally means that FreeCAD is running for the first time\n" + " or the configuration was deleted or moved. FreeCAD is generating the standard\n" + " configuration.\n"); + } + } + } + catch (const Base::Exception& e) { + // try to proceed with an empty XML document + Base::Console().Error("%s in file %s.\n" + "Continue with an empty configuration.\n", + e.what(), mConfig["SystemParameter"].c_str()); + _pcSysParamMngr->CreateDocument(); + } + + try { + if (_pcUserParamMngr->LoadOrCreateDocument(mConfig["UserParameter"].c_str()) && !(mConfig["Verbose"] == "Strict")) { + // The user parameter file doesn't exist. When an alternative parameter file is offered + // this will be used. + std::map::iterator it = mConfig.find("UserParameterTemplate"); + if (it != mConfig.end()) { + QString path = QString::fromUtf8(it->second.c_str()); + if (QDir(path).isRelative()) { + QString home = QString::fromUtf8(mConfig["AppHomePath"].c_str()); + path = QFileInfo(QDir(home), path).absoluteFilePath(); + } + QFileInfo fi(path); + if (fi.exists()) { + _pcUserParamMngr->LoadDocument(path.toUtf8().constData()); + } + } + + // Configuration file optional when using as Python module + if (!Py_IsInitialized()) { + Console().Warning(" User settings do not exist, writing initial one\n"); + Console().Message(" This warning normally means that FreeCAD is running for the first time\n" + " or your configuration was deleted or moved. The system defaults\n" + " will be automatically generated for you.\n"); + } + } + } + catch (const Base::Exception& e) { + // try to proceed with an empty XML document + Base::Console().Error("%s in file %s.\n" + "Continue with an empty configuration.\n", + e.what(), mConfig["UserParameter"].c_str()); + _pcUserParamMngr->CreateDocument(); + } +} + + +#if defined(_MSC_VER) +// fix weird error while linking boost (all versions of VC) +// VS2010: http://forum.freecadweb.org/viewtopic.php?f=4&t=1886&p=12553&hilit=boost%3A%3Afilesystem%3A%3Aget#p12553 +namespace boost { namespace program_options { std::string arg="arg"; } } +#if (defined (BOOST_VERSION) && (BOOST_VERSION >= 104100)) +namespace boost { namespace program_options { + const unsigned options_description::m_default_line_length = 80; +} } +#endif +#endif + +#if 0 // it seems that SUSE has fixed the broken boost package +// reported for SUSE in issue #0000208 +#if defined(__GNUC__) +#if BOOST_VERSION == 104400 +namespace boost { namespace filesystem { + bool no_check( const std::string & ) { return true; } +} } +#endif +#endif +#endif + +pair customSyntax(const string& s) +{ +#if defined(FC_OS_MACOSX) + if (s.find("-psn_") == 0) + return make_pair(string("psn"), s.substr(5)); +#endif + if (s.find("-display") == 0) + return make_pair(string("display"), string("null")); + else if (s.find("-style") == 0) + return make_pair(string("style"), string("null")); + else if (s.find("-geometry") == 0) + return make_pair(string("geometry"), string("null")); + else if (s.find("-font") == 0) + return make_pair(string("font"), string("null")); + else if (s.find("-fn") == 0) + return make_pair(string("fn"), string("null")); + else if (s.find("-background") == 0) + return make_pair(string("background"), string("null")); + else if (s.find("-bg") == 0) + return make_pair(string("bg"), string("null")); + else if (s.find("-foreground") == 0) + return make_pair(string("foreground"), string("null")); + else if (s.find("-fg") == 0) + return make_pair(string("fg"), string("null")); + else if (s.find("-button") == 0) + return make_pair(string("button"), string("null")); + else if (s.find("-btn") == 0) + return make_pair(string("btn"), string("null")); + else if (s.find("-name") == 0) + return make_pair(string("name"), string("null")); + else if (s.find("-title") == 0) + return make_pair(string("title"), string("null")); + else if (s.find("-visual") == 0) + return make_pair(string("visual"), string("null")); +// else if (s.find("-ncols") == 0) +// return make_pair(string("ncols"), boost::program_options::value(1)); +// else if (s.find("-cmap") == 0) +// return make_pair(string("cmap"), string("null")); + else if ('@' == s[0]) + return std::make_pair(string("response-file"), s.substr(1)); + else + return make_pair(string(), string()); + +} + +// A helper function to simplify the main part. +template +ostream& operator<<(ostream& os, const vector& v) +{ + copy(v.begin(), v.end(), ostream_iterator(cout, " ")); + return os; +} + +void Application::ParseOptions(int ac, char ** av) +{ + // Declare a group of options that will be + // allowed only on the command line + options_description generic("Generic options"); + generic.add_options() + ("version,v", "Prints version string") + ("help,h", "Prints help message") + ("console,c", "Starts in console mode") + ("response-file", value(),"Can be specified with '@name', too") + ("dump-config", "Dumps configuration") + ("get-config", value(), "Prints the value of the requested configuration key") + ; + + // Declare a group of options that will be + // allowed both on the command line and in + // the config file + std::string descr("Writes a log file to:\n"); + descr += mConfig["UserAppData"]; + descr += mConfig["ExeName"]; + descr += ".log"; + boost::program_options::options_description config("Configuration"); + config.add_options() + //("write-log,l", value(), "write a log file") + ("write-log,l", descr.c_str()) + ("log-file", value(), "Unlike to --write-log this allows to log to an arbitrary file") + ("user-cfg,u", value(),"User config file to load/save user settings") + ("system-cfg,s", value(),"Systen config file to load/save system settings") + ("run-test,t", value() ,"Test level") + ("module-path,M", value< vector >()->composing(),"Additional module paths") + ("python-path,P", value< vector >()->composing(),"Additional python paths") + ("single-instance", "Allow to run a single instance of the application") + ; + + + // Hidden options, will be allowed both on the command line and + // in the config file, but will not be shown to the user. + boost::program_options::options_description hidden("Hidden options"); + hidden.add_options() + ("input-file", boost::program_options::value< vector >(), "input file") + ("output", boost::program_options::value(),"output file") + ("hidden", "don't show the main window") + // this are to ignore for the window system (QApplication) + ("style", boost::program_options::value< string >(), "set the application GUI style") + ("stylesheet", boost::program_options::value< string >(), "set the application stylesheet") + ("session", boost::program_options::value< string >(), "restore the application from an earlier session") + ("reverse", "set the application's layout direction from right to left") + ("display", boost::program_options::value< string >(), "set the X-Server") + ("geometry ", boost::program_options::value< string >(), "set the X-Window geometry") + ("font", boost::program_options::value< string >(), "set the X-Window font") + ("fn", boost::program_options::value< string >(), "set the X-Window font") + ("background", boost::program_options::value< string >(), "set the X-Window background color") + ("bg", boost::program_options::value< string >(), "set the X-Window background color") + ("foreground", boost::program_options::value< string >(), "set the X-Window foreground color") + ("fg", boost::program_options::value< string >(), "set the X-Window foreground color") + ("button", boost::program_options::value< string >(), "set the X-Window button color") + ("btn", boost::program_options::value< string >(), "set the X-Window button color") + ("name", boost::program_options::value< string >(), "set the X-Window name") + ("title", boost::program_options::value< string >(), "set the X-Window title") + ("visual", boost::program_options::value< string >(), "set the X-Window to color scema") + ("ncols", boost::program_options::value< int >(), "set the X-Window to color scema") + ("cmap", "set the X-Window to color scema") +#if defined(FC_OS_MACOSX) + ("psn", boost::program_options::value< string >(), "process serial number") +#endif + ; + + // Ignored options, will be safely ignored. Mostly used by underlaying libs. + //boost::program_options::options_description x11("X11 options"); + //x11.add_options() + // ("display", boost::program_options::value< string >(), "set the X-Server") + // ; + //0000723: improper handling of qt specific comand line arguments + std::vector args; + bool merge=false; + for (int i=1; i().c_str()); + if (!ifs) { + Base::Console().Error("Could no open the response file\n"); + std::stringstream str; + str << "Could no open the response file: '" + << vm["response-file"].as() << "'" << endl; + throw Base::UnknownProgramOption(str.str()); + } + // Read the whole file into a string + stringstream ss; + ss << ifs.rdbuf(); + // Split the file content + char_separator sep(" \n\r"); + tokenizer > tok(ss.str(), sep); + vector args; + copy(tok.begin(), tok.end(), back_inserter(args)); + // Parse the file and store the options + store( boost::program_options::command_line_parser(args). + options(cmdline_options).positional(p).extra_parser(customSyntax).run(), vm); + } + + if (vm.count("version")) { + std::stringstream str; + str << mConfig["ExeName"] << " " << mConfig["ExeVersion"] + << " Revision: " << mConfig["BuildRevision"] << std::endl; + throw Base::ProgramInformation(str.str()); + } + + if (vm.count("console")) { + mConfig["RunMode"] = "Cmd"; + } + + if (vm.count("module-path")) { + vector Mods = vm["module-path"].as< vector >(); + string temp; + for (vector::const_iterator It= Mods.begin();It != Mods.end();++It) + temp += *It + ";"; + temp.erase(temp.end()-1); + mConfig["AdditionalModulePaths"] = temp; + } + + if (vm.count("python-path")) { + vector Paths = vm["python-path"].as< vector >(); + for (vector::const_iterator It= Paths.begin();It != Paths.end();++It) + Base::Interpreter().addPythonPath(It->c_str()); + } + + if (vm.count("input-file")) { + vector files(vm["input-file"].as< vector >()); + int OpenFileCount=0; + for (vector::const_iterator It = files.begin();It != files.end();++It) { + + //cout << "Input files are: " + // << vm["input-file"].as< vector >() << "\n"; + + std::ostringstream temp; + temp << "OpenFile" << OpenFileCount; + mConfig[temp.str()] = *It; + OpenFileCount++; + } + std::ostringstream buffer; + buffer << OpenFileCount; + mConfig["OpenFileCount"] = buffer.str(); + } + + if (vm.count("output")) { + string file = vm["output"].as(); + mConfig["SaveFile"] = file; + } + + if (vm.count("hidden")) { + mConfig["StartHidden"] = "1"; + } + + if (vm.count("write-log")) { + mConfig["LoggingFile"] = "1"; + //mConfig["LoggingFileName"] = vm["write-log"].as(); + mConfig["LoggingFileName"] = mConfig["UserAppData"] + mConfig["ExeName"] + ".log"; + } + + if (vm.count("log-file")) { + mConfig["LoggingFile"] = "1"; + mConfig["LoggingFileName"] = vm["log-file"].as(); + } + + if (vm.count("user-cfg")) { + mConfig["UserParameter"] = vm["user-cfg"].as(); + } + + if (vm.count("system-cfg")) { + mConfig["SystemParameter"] = vm["system-cfg"].as(); + } + + if (vm.count("run-test")) { + int level = vm["run-test"].as(); + switch (level) { + case '0': + // test script level 0 + mConfig["RunMode"] = "Internal"; + mConfig["ScriptFileName"] = "FreeCADTest"; + //sScriptName = FreeCADTest; + break; + default: + //default testing level 0 + mConfig["RunMode"] = "Internal"; + mConfig["ScriptFileName"] = "FreeCADTest"; + //sScriptName = FreeCADTest; + break; + }; + } + + if (vm.count("single-instance")) { + mConfig["SingleInstance"] = "1"; + } + + if (vm.count("dump-config")) { + std::stringstream str; + for (std::map::iterator it=mConfig.begin(); it != mConfig.end(); ++it) { + str << it->first << "=" << it->second << std::endl; + } + throw Base::ProgramInformation(str.str()); + } + + if (vm.count("get-config")) { + std::string configKey = vm["get-config"].as(); + std::stringstream str; + std::map::iterator pos; + pos = mConfig.find(configKey); + if (pos != mConfig.end()) { + str << pos->second; + } + str << std::endl; + throw Base::ProgramInformation(str.str()); + } +} + +void Application::ExtractUserPath() +{ + // std paths + mConfig["BinPath"] = mConfig["AppHomePath"] + "bin" + PATHSEP; + mConfig["DocPath"] = mConfig["AppHomePath"] + "doc" + PATHSEP; + +#if defined(FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_BSD) + // Default paths for the user specific stuff + struct passwd *pwd = getpwuid(getuid()); + if (pwd == NULL) + throw Base::Exception("Getting HOME path from system failed!"); + mConfig["UserHomePath"] = pwd->pw_dir; + std::string appData = pwd->pw_dir; + Base::FileInfo fi(appData.c_str()); + if (!fi.exists()) { + // This should never ever happen + std::stringstream str; + str << "Application data directory " << appData << " does not exist!"; + throw Base::Exception(str.str()); + } + + // In order to write into our data path, we must create some directories, first. + // If 'AppDataSkipVendor' is defined, the value of 'ExeVendor' must not be part of + // the path. + appData += PATHSEP; + appData += "."; + if (mConfig.find("AppDataSkipVendor") == mConfig.end()) { + appData += mConfig["ExeVendor"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + appData += PATHSEP; + } + + appData += mConfig["ExeName"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + + // Actually the name of the directory where the parameters are stored should be the name of + // the application due to branding reasons. + appData += PATHSEP; + mConfig["UserAppData"] = appData; + +#elif defined(FC_OS_MACOSX) + // Default paths for the user specific stuff on the platform + struct passwd *pwd = getpwuid(getuid()); + if (pwd == NULL) + throw Base::Exception("Getting HOME path from system failed!"); + mConfig["UserHomePath"] = pwd->pw_dir; + std::string appData = pwd->pw_dir; + appData += PATHSEP; + appData += "Library"; + appData += PATHSEP; + appData += "Preferences"; + Base::FileInfo fi(appData.c_str()); + if (!fi.exists()) { + // This should never ever happen + std::stringstream str; + str << "Application data directory " << appData << " does not exist!"; + throw Base::Exception(str.str()); + } + + // In order to write to our data path, we must create some directories, first. + // If 'AppDataSkipVendor' is defined the value of 'ExeVendor' must not be part of + // the path. + appData += PATHSEP; + if (mConfig.find("AppDataSkipVendor") == mConfig.end()) { + appData += mConfig["ExeVendor"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + appData += PATHSEP; + } + + appData += mConfig["ExeName"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + + // Actually the name of the directory where the parameters are stored should be the name of + // the application due to branding reasons. + appData += PATHSEP; + mConfig["UserAppData"] = appData; + +#elif defined(FC_OS_WIN32) + WCHAR szPath[MAX_PATH]; + TCHAR dest[MAX_PATH*3]; + // Get the default path where we can save our documents. It seems that + // 'CSIDL_MYDOCUMENTS' doesn't work on all machines, so we use 'CSIDL_PERSONAL' + // which does the same. + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, szPath))) { + WideCharToMultiByte(CP_UTF8, 0, szPath, -1,dest, 256, NULL, NULL); + mConfig["UserHomePath"] = dest; + } + else + mConfig["UserHomePath"] = mConfig["AppHomePath"]; + + // In the second step we want the directory where user settings of the application can be + // kept. There we create a directory with name of the vendor and a sub-directory with name + // of the application. + if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, szPath))) { + // convert to UTF8 + WideCharToMultiByte(CP_UTF8, 0, szPath, -1,dest, 256, NULL, NULL); + + std::string appData = dest; + Base::FileInfo fi(appData.c_str()); + if (!fi.exists()) { + // This should never ever happen + std::stringstream str; + str << "Application data directory " << appData << " does not exist!"; + throw Base::Exception(str.str()); + } + + // In order to write to our data path we must create some directories first. + // If 'AppDataSkipVendor' is defined the value of 'ExeVendor' must not be part of + // the path. + if (mConfig.find("AppDataSkipVendor") == mConfig.end()) { + appData += PATHSEP; + appData += mConfig["ExeVendor"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + } + + appData += PATHSEP; + appData += mConfig["ExeName"]; + fi.setFile(appData.c_str()); + if (!fi.exists() && !Py_IsInitialized()) { + if (!fi.createDirectory()) { + std::string error = "Cannot create directory "; + error += appData; + // Want more details on console + std::cerr << error << std::endl; + throw Base::Exception(error); + } + } + + // Actually the name of the directory where the parameters are stored should be the name of + // the application due to branding reasons. + appData += PATHSEP; + mConfig["UserAppData"] = appData; + } +#else +# error "Implement ExtractUserPath() for your platform." +#endif +} + +#if defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_BSD) +#include +#include +#include + +std::string Application::FindHomePath(const char* sCall) +{ + // We have three ways to start this application either use one of the two executables or + // import the FreeCAD.so module from a running Python session. In the latter case the + // Python interpreter is already initialized. + std::string absPath; + std::string homePath; + if (Py_IsInitialized()) { + // Note: realpath is known to cause a buffer overflow because it + // expands the given path to an absolute path of unknown length. + // Even setting PATH_MAX does not necessarily solve the problem + // for sure but the risk of overflow is rather small. + char resolved[PATH_MAX]; + char* path = realpath(sCall, resolved); + if (path) + absPath = path; + } + else { + // Find the path of the executable. Theoretically, there could occur a + // race condition when using readlink, but we only use this method to + // get the absolute path of the executable to compute the actual home + // path. In the worst case we simply get q wrong path and FreeCAD is not + // able to load its modules. + char resolved[PATH_MAX]; + int nchars = readlink("/proc/self/exe", resolved, PATH_MAX); + if (nchars < 0 || nchars >= PATH_MAX) + throw Base::Exception("Cannot determine the absolute path of the executable"); + resolved[nchars] = '\0'; // enfore null termination + absPath = resolved; + } + + // should be an absolute path now + std::string::size_type pos = absPath.find_last_of("/"); + homePath.assign(absPath,0,pos); + pos = homePath.find_last_of("/"); + homePath.assign(homePath,0,pos+1); + + return homePath; +} + +#elif defined(FC_OS_MACOSX) +#include +#include +#include +#include + +std::string Application::FindHomePath(const char* call) +{ + uint32_t sz = 0; + char *buf; + + _NSGetExecutablePath(NULL, &sz); //function only returns "sz" if first arg is to small to hold value + buf = (char*) malloc(++sz); + + if (_NSGetExecutablePath(buf, &sz) == 0) { + char resolved[PATH_MAX]; + char* path = realpath(buf, resolved); + free(buf); + + if (path) { + std::string Call(resolved), TempHomePath; + std::string::size_type pos = Call.find_last_of(PATHSEP); + TempHomePath.assign(Call,0,pos); + pos = TempHomePath.find_last_of(PATHSEP); + TempHomePath.assign(TempHomePath,0,pos+1); + return TempHomePath; + } + } + + return call; // error +} + +#elif defined (FC_OS_WIN32) +std::string Application::FindHomePath(const char* sCall) +{ + // We have three ways to start this application either use one of the two executables or + // import the FreeCAD.pyd module from a running Python session. In the latter case the + // Python interpreter is already initialized. + wchar_t szFileName [MAX_PATH]; + if (Py_IsInitialized()) { + GetModuleFileNameW(GetModuleHandle(sCall),szFileName, MAX_PATH-1); + } + else { + GetModuleFileNameW(0, szFileName, MAX_PATH-1); + } + + std::wstring Call(szFileName), homePath; + std::wstring::size_type pos = Call.find_last_of(PATHSEP); + homePath.assign(Call,0,pos); + pos = homePath.find_last_of(PATHSEP); + homePath.assign(homePath,0,pos+1); + + // switch to posix style + for (std::wstring::iterator it = homePath.begin(); it != homePath.end(); ++it) { + if (*it == '\\') + *it = '/'; + } + + // fixes #0001638 to avoid to load DLLs from Windows' system directories before FreeCAD's bin folder + std::wstring binPath = homePath; + binPath += L"bin"; + SetDllDirectoryW(binPath.c_str()); + + // http://stackoverflow.com/questions/5625884/conversion-of-stdwstring-to-qstring-throws-linker-error +#ifdef _MSC_VER + QString str = QString::fromUtf16(reinterpret_cast(homePath.c_str())); +#else + QString str = QString::fromStdWString(homePath); +#endif + return str.toStdString(); +} + +#else +# error "std::string Application::FindHomePath(const char*) not implemented" +#endif diff --git a/src/Mod/Assembly/DevAssembly.py b/src/Mod/Assembly/DevAssembly.py new file mode 100644 index 000000000000..43e12aafcc8b --- /dev/null +++ b/src/Mod/Assembly/DevAssembly.py @@ -0,0 +1,3 @@ +import FreeCAD,Assembly + +print "Script to test the assembly development" From a224d93d8cae0210f95b28c79aeb3fdc2ca093ad Mon Sep 17 00:00:00 2001 From: jriegel Date: Tue, 3 Jan 2012 01:21:45 +0100 Subject: [PATCH 003/664] Add Assembly App objects and some python bindings Make Part working --- src/Mod/Assembly/App/AppAssembly.cpp | 6 +- src/Mod/Assembly/App/CMakeLists.txt | 59 +++++++++++++++++- src/Mod/Assembly/App/Constraint.cpp | 60 +++++++++++++++++++ src/Mod/Assembly/App/Constraint.h | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintAngle.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintAngle.h | 58 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintAxis.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintAxis.h | 57 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintContact.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintContact.h | 57 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintFix.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintFix.h | 56 +++++++++++++++++ src/Mod/Assembly/App/ConstraintGroup.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintGroup.h | 58 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintGroupPy.xml | 17 ++++++ src/Mod/Assembly/App/ConstraintGroupPyImp.cpp | 34 +++++++++++ src/Mod/Assembly/App/ConstraintOffset.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ConstraintOffset.h | 58 ++++++++++++++++++ src/Mod/Assembly/App/Item.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/Item.h | 59 ++++++++++++++++++ src/Mod/Assembly/App/ItemAssembly.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ItemAssembly.h | 58 ++++++++++++++++++ src/Mod/Assembly/App/ItemAssemblyPy.xml | 17 ++++++ src/Mod/Assembly/App/ItemAssemblyPyImp.cpp | 34 +++++++++++ src/Mod/Assembly/App/ItemPart.cpp | 59 ++++++++++++++++++ src/Mod/Assembly/App/ItemPart.h | 58 ++++++++++++++++++ src/Mod/Assembly/App/ItemPartPy.xml | 17 ++++++ src/Mod/Assembly/App/ItemPartPyImp.cpp | 34 +++++++++++ src/Mod/Assembly/App/ItemPy.xml | 17 ++++++ src/Mod/Assembly/App/ItemPyImp.cpp | 34 +++++++++++ src/Mod/Assembly/App/PreCompiled.h | 4 +- src/Mod/Assembly/DevAssembly.py | 4 +- 32 files changed, 1437 insertions(+), 9 deletions(-) create mode 100644 src/Mod/Assembly/App/Constraint.cpp create mode 100644 src/Mod/Assembly/App/Constraint.h create mode 100644 src/Mod/Assembly/App/ConstraintAngle.cpp create mode 100644 src/Mod/Assembly/App/ConstraintAngle.h create mode 100644 src/Mod/Assembly/App/ConstraintAxis.cpp create mode 100644 src/Mod/Assembly/App/ConstraintAxis.h create mode 100644 src/Mod/Assembly/App/ConstraintContact.cpp create mode 100644 src/Mod/Assembly/App/ConstraintContact.h create mode 100644 src/Mod/Assembly/App/ConstraintFix.cpp create mode 100644 src/Mod/Assembly/App/ConstraintFix.h create mode 100644 src/Mod/Assembly/App/ConstraintGroup.cpp create mode 100644 src/Mod/Assembly/App/ConstraintGroup.h create mode 100644 src/Mod/Assembly/App/ConstraintGroupPy.xml create mode 100644 src/Mod/Assembly/App/ConstraintGroupPyImp.cpp create mode 100644 src/Mod/Assembly/App/ConstraintOffset.cpp create mode 100644 src/Mod/Assembly/App/ConstraintOffset.h create mode 100644 src/Mod/Assembly/App/Item.cpp create mode 100644 src/Mod/Assembly/App/Item.h create mode 100644 src/Mod/Assembly/App/ItemAssembly.cpp create mode 100644 src/Mod/Assembly/App/ItemAssembly.h create mode 100644 src/Mod/Assembly/App/ItemAssemblyPy.xml create mode 100644 src/Mod/Assembly/App/ItemAssemblyPyImp.cpp create mode 100644 src/Mod/Assembly/App/ItemPart.cpp create mode 100644 src/Mod/Assembly/App/ItemPart.h create mode 100644 src/Mod/Assembly/App/ItemPartPy.xml create mode 100644 src/Mod/Assembly/App/ItemPartPyImp.cpp create mode 100644 src/Mod/Assembly/App/ItemPy.xml create mode 100644 src/Mod/Assembly/App/ItemPyImp.cpp diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index 5291e56727e8..3a2434acd103 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -39,12 +39,12 @@ PyDoc_STRVAR(module_Assembly_doc, /* Python entry */ extern "C" { -void AppAssemblyExport initAssembly() +void AssemblyExport initAssembly() { // load dependend module try { - Base::Interpreter().loadModule("Part"); - Base::Interpreter().loadModule("PartDesign"); + Base::Interpreter().runString("import Part"); + //Base::Interpreter().runString("import PartDesign"); } catch(const Base::Exception& e) { PyErr_SetString(PyExc_ImportError, e.what()); diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 50537fd1641a..11eb37cc0442 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -1,25 +1,78 @@ include_directories( ${CMAKE_SOURCE_DIR}/src + ${CMAKE_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${OCC_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} ${XercesC_INCLUDE_DIRS} - # ${ODE_INCLUDE_DIRS} + ${ODE_INCLUDE_DIRS} ) set(Assembly_LIBS -# ${ODE_LIBRARIES} + ${ODE_LIBRARIES} + ${OCC_LIBRARIES} + Part FreeCADApp ) -SET(Assembly_SRCS +generate_from_xml(ItemPy) +generate_from_xml(ItemAssemblyPy) +generate_from_xml(ItemPartPy) +generate_from_xml(ConstraintGroupPy) + +SET(Features_SRCS + Item.cpp + Item.h + ItemPart.cpp + ItemPart.h + ItemAssembly.cpp + ItemAssembly.h + Constraint.cpp + Constraint.h + ConstraintGroup.cpp + ConstraintGroup.h + ConstraintAngle.cpp + ConstraintAngle.h + ConstraintAxis.cpp + ConstraintAxis.h + ConstraintContact.cpp + ConstraintContact.h + ConstraintFix.cpp + ConstraintFix.h + ConstraintOffset.cpp + ConstraintOffset.h +) +SOURCE_GROUP("Features" FILES ${Features_SRCS}) + +SET(Module_SRCS AppAssembly.cpp AppAssemblyPy.cpp PreCompiled.cpp PreCompiled.h ) +SOURCE_GROUP("Module" FILES ${Module_SRCS}) + +SET(Python_SRCS + ItemPy.xml + ItemPyImp.cpp + ItemAssemblyPy.xml + ItemAssemblyPyImp.cpp + ItemPartPy.xml + ItemPartPyImp.cpp + ConstraintGroupPy.xml + ConstraintGroupPyImp.cpp +) +SOURCE_GROUP("Python" FILES ${Python_SRCS}) + +SET(Assembly_SRCS + ${Features_SRCS} + ${Python_SRCS} + ${Module_SRCS} +) + add_library(Assembly SHARED ${Assembly_SRCS}) target_link_libraries(Assembly ${Assembly_LIBS}) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp new file mode 100644 index 000000000000..01aa71c5a0a7 --- /dev/null +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 + +#include "Constraint.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::Constraint, App::DocumentObject) + +Constraint::Constraint() +{ + ADD_PROPERTY(First, (0)); + ADD_PROPERTY(Second,(0)); +} + +short Constraint::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *Constraint::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h new file mode 100644 index 000000000000..28b8fa086d91 --- /dev/null +++ b/src/Mod/Assembly/App/Constraint.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_Constraint_H +#define Assembly_Constraint_H + +#include +#include + + +namespace Assembly +{ + +class AssemblyExport Constraint : public App::DocumentObject +{ + PROPERTY_HEADER(Assembly::Constraint); + +public: + Constraint(); + + App::PropertyLinkSub First; + App::PropertyLinkSub Second; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraint"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_Constraint_H diff --git a/src/Mod/Assembly/App/ConstraintAngle.cpp b/src/Mod/Assembly/App/ConstraintAngle.cpp new file mode 100644 index 000000000000..52d38337500f --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAngle.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "ConstraintAngle.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintAngle, Assembly::Constraint) + +ConstraintAngle::ConstraintAngle() +{ + ADD_PROPERTY(Angle,(0)); +} + +short ConstraintAngle::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintAngle::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAngle.h b/src/Mod/Assembly/App/ConstraintAngle.h new file mode 100644 index 000000000000..13b2ae68a188 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAngle.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 Assembly_ConstraintAngle_H +#define Assembly_ConstraintAngle_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintAngle : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintAngle); + +public: + ConstraintAngle(); + + App::PropertyFloat Angle; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraintAngle"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintAngle_H diff --git a/src/Mod/Assembly/App/ConstraintAxis.cpp b/src/Mod/Assembly/App/ConstraintAxis.cpp new file mode 100644 index 000000000000..b2ed9ab40553 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAxis.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 + +#include "ConstraintAxis.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintAxis, Assembly::Constraint) + +ConstraintAxis::ConstraintAxis() +{ + +} + +short ConstraintAxis::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintAxis::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAxis.h b/src/Mod/Assembly/App/ConstraintAxis.h new file mode 100644 index 000000000000..c776ce8925a8 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAxis.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_ConstraintAxis_H +#define Assembly_ConstraintAxis_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintAxis : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintAxis); + +public: + ConstraintAxis(); + + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraintAxis"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintAxis_H diff --git a/src/Mod/Assembly/App/ConstraintContact.cpp b/src/Mod/Assembly/App/ConstraintContact.cpp new file mode 100644 index 000000000000..94c28bc71002 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintContact.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 + +#include "ConstraintContact.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintContact, Assembly::Constraint) + +ConstraintContact::ConstraintContact() +{ + +} + +short ConstraintContact::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintContact::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintContact.h b/src/Mod/Assembly/App/ConstraintContact.h new file mode 100644 index 000000000000..659bf4000ea2 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintContact.h @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_ConstraintContact_H +#define Assembly_ConstraintContact_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintContact : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintContact); + +public: + ConstraintContact(); + + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraintContact"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintContact_H diff --git a/src/Mod/Assembly/App/ConstraintFix.cpp b/src/Mod/Assembly/App/ConstraintFix.cpp new file mode 100644 index 000000000000..033222172c32 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintFix.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "ConstraintFix.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintFix, Assembly::Constraint) + +ConstraintFix::ConstraintFix() +{ + +} + +short ConstraintFix::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintFix::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintFix.h b/src/Mod/Assembly/App/ConstraintFix.h new file mode 100644 index 000000000000..c2b28035b133 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintFix.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 Assembly_ConstraintFix_H +#define Assembly_ConstraintFix_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintFix : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintFix); + +public: + ConstraintFix(); + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraintFix"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintFix_H diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp new file mode 100644 index 000000000000..b27746f7e1bd --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "ConstraintGroup.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintGroup, App::DocumentObject) + +ConstraintGroup::ConstraintGroup() +{ + ADD_PROPERTY(Constraints,(0)); +} + +short ConstraintGroup::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintGroup::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintGroup.h b/src/Mod/Assembly/App/ConstraintGroup.h new file mode 100644 index 000000000000..15406dacd2f1 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintGroup.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 Assembly_ConstraintGroup_H +#define Assembly_ConstraintGroup_H + +#include +#include + + +namespace Assembly +{ + +class AssemblyExport ConstraintGroup : public App::DocumentObject +{ + PROPERTY_HEADER(Assembly::ConstraintGroup); + +public: + ConstraintGroup(); + + App::PropertyLinkList Constraints; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraintGroup"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintGroup_H diff --git a/src/Mod/Assembly/App/ConstraintGroupPy.xml b/src/Mod/Assembly/App/ConstraintGroupPy.xml new file mode 100644 index 000000000000..6ff8732e5423 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintGroupPy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all objects in Assembly + + + diff --git a/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp b/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp new file mode 100644 index 000000000000..0fbcfaff1575 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp @@ -0,0 +1,34 @@ + +#include "PreCompiled.h" + +#include "Mod/Assembly/App/ConstraintGroup.h" + +// inclusion of the generated files (generated out of ConstraintGroupPy.xml) +#include "ConstraintGroupPy.h" +#include "ConstraintGroupPy.cpp" + +using namespace Assembly; + +// returns a string which represents the object e.g. when printed in python +std::string ConstraintGroupPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *ConstraintGroupPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ConstraintGroupPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Assembly/App/ConstraintOffset.cpp b/src/Mod/Assembly/App/ConstraintOffset.cpp new file mode 100644 index 000000000000..e9b62e957614 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintOffset.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "ConstraintOffset.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintOffset, Assembly::Constraint) + +ConstraintOffset::ConstraintOffset() +{ + ADD_PROPERTY(Offset,(0)); +} + +short ConstraintOffset::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintOffset::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintOffset.h b/src/Mod/Assembly/App/ConstraintOffset.h new file mode 100644 index 000000000000..26cdd20a32de --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintOffset.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 Assembly_ConstraintOffset_H +#define Assembly_ConstraintOffset_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintOffset : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintOffset); + +public: + ConstraintOffset(); + + App::PropertyFloat Offset; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderConstraintOffset"; + //} + //@} +}; + +} //namespace PartDesign + + +#endif // PART_ConstraintOffset_H diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp new file mode 100644 index 000000000000..b77bb871efcb --- /dev/null +++ b/src/Mod/Assembly/App/Item.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "Item.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::Item, Part::Feature) + +Item::Item() +{ + ADD_PROPERTY(Model,(0)); +} + +short Item::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *Item::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h new file mode 100644 index 000000000000..15f4f8af0bde --- /dev/null +++ b/src/Mod/Assembly/App/Item.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 Assembly_Item_H +#define Assembly_Item_H + +#include +#include + + +namespace Assembly +{ + +class AssemblyExport Item : public Part::Feature +{ + PROPERTY_HEADER(Assembly::Item); + +public: + Item(); + + App::PropertyLinkList Model; + App::PropertyLink Tip; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderItem"; + //} + //@} +}; + +} //namespace PartDesign + + +#endif // PART_Item_H diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp new file mode 100644 index 000000000000..ce43002eca4e --- /dev/null +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 + +#include "ItemAssembly.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ItemAssembly, Assembly::Item) + +ItemAssembly::ItemAssembly() +{ + ADD_PROPERTY(Items,(0)); +} + +short ItemAssembly::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ItemAssembly::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h new file mode 100644 index 000000000000..86b3ef2429f8 --- /dev/null +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 ItemAssembly_ItemAssembly_H +#define ItemAssembly_ItemAssembly_H + +#include +#include "Item.h" + + +namespace Assembly +{ + +class AssemblyExport ItemAssembly : public Assembly::Item +{ + PROPERTY_HEADER(Assembly::ItemAssembly); + +public: + ItemAssembly(); + + App::PropertyLinkList Items; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderItemAssembly"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ItemAssembly_H diff --git a/src/Mod/Assembly/App/ItemAssemblyPy.xml b/src/Mod/Assembly/App/ItemAssemblyPy.xml new file mode 100644 index 000000000000..e2f560946eae --- /dev/null +++ b/src/Mod/Assembly/App/ItemAssemblyPy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all objects in Assembly + + + diff --git a/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp b/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp new file mode 100644 index 000000000000..7542d312f75a --- /dev/null +++ b/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp @@ -0,0 +1,34 @@ + +#include "PreCompiled.h" + +#include "Mod/Assembly/App/ItemAssembly.h" + +// inclusion of the generated files (generated out of ItemAssemblyPy.xml) +#include "ItemAssemblyPy.h" +#include "ItemAssemblyPy.cpp" + +using namespace Assembly; + +// returns a string which represents the object e.g. when printed in python +std::string ItemAssemblyPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *ItemAssemblyPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ItemAssemblyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp new file mode 100644 index 000000000000..85e1db9e139a --- /dev/null +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 + +#include "ItemPart.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ItemPart, Assembly::Item) + +ItemPart::ItemPart() +{ + ADD_PROPERTY(Model,(0)); +} + +short ItemPart::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ItemPart::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h new file mode 100644 index 000000000000..80acb8303724 --- /dev/null +++ b/src/Mod/Assembly/App/ItemPart.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_ItemPart_H +#define Assembly_ItemPart_H + +#include +#include "Item.h" + + +namespace Assembly +{ + +class AssemblyExport ItemPart : public Assembly::Item +{ + PROPERTY_HEADER(Assembly::ItemPart); + +public: + ItemPart(); + + App::PropertyLink Model; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "ItemPartDesignGui::ViewProviderItemPart"; + //} + //@} +}; + +} //namespace Assembly + + +#endif // Assembly_ItemPart_H diff --git a/src/Mod/Assembly/App/ItemPartPy.xml b/src/Mod/Assembly/App/ItemPartPy.xml new file mode 100644 index 000000000000..02d47416f974 --- /dev/null +++ b/src/Mod/Assembly/App/ItemPartPy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all objects in Assembly + + + diff --git a/src/Mod/Assembly/App/ItemPartPyImp.cpp b/src/Mod/Assembly/App/ItemPartPyImp.cpp new file mode 100644 index 000000000000..8d07922487eb --- /dev/null +++ b/src/Mod/Assembly/App/ItemPartPyImp.cpp @@ -0,0 +1,34 @@ + +#include "PreCompiled.h" + +#include "Mod/Assembly/App/ItemPart.h" + +// inclusion of the generated files (generated out of ItemPartPy.xml) +#include "ItemPartPy.h" +#include "ItemPartPy.cpp" + +using namespace Assembly; + +// returns a string which represents the object e.g. when printed in python +std::string ItemPartPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *ItemPartPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ItemPartPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Assembly/App/ItemPy.xml b/src/Mod/Assembly/App/ItemPy.xml new file mode 100644 index 000000000000..d9bca2eea46c --- /dev/null +++ b/src/Mod/Assembly/App/ItemPy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all objects in Assembly + + + diff --git a/src/Mod/Assembly/App/ItemPyImp.cpp b/src/Mod/Assembly/App/ItemPyImp.cpp new file mode 100644 index 000000000000..b2f5918562f6 --- /dev/null +++ b/src/Mod/Assembly/App/ItemPyImp.cpp @@ -0,0 +1,34 @@ + +#include "PreCompiled.h" + +#include "Mod/Assembly/App/Item.h" + +// inclusion of the generated files (generated out of ItemPy.xml) +#include "ItemPy.h" +#include "ItemPy.cpp" + +using namespace Assembly; + +// returns a string which represents the object e.g. when printed in python +std::string ItemPy::representation(void) const +{ + return std::string(""); +} + + + + + + + +PyObject *ItemPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ItemPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Assembly/App/PreCompiled.h b/src/Mod/Assembly/App/PreCompiled.h index ef82449af498..8dfc4eb52a0d 100644 --- a/src/Mod/Assembly/App/PreCompiled.h +++ b/src/Mod/Assembly/App/PreCompiled.h @@ -28,11 +28,11 @@ // Exporting of App classes #ifdef FC_OS_WIN32 -# define AppAssemblyExport __declspec(dllexport) +# define AssemblyExport __declspec(dllexport) # define PartExport __declspec(dllimport) # define MeshExport __declspec(dllimport) #else // for Linux -# define AppAssemblyExport +# define AssemblyExport # define PartExport # define MeshExport #endif diff --git a/src/Mod/Assembly/DevAssembly.py b/src/Mod/Assembly/DevAssembly.py index 43e12aafcc8b..e6365961d533 100644 --- a/src/Mod/Assembly/DevAssembly.py +++ b/src/Mod/Assembly/DevAssembly.py @@ -1,3 +1,5 @@ -import FreeCAD,Assembly +import FreeCAD,Assembly,time print "Script to test the assembly development" + +time.sleep(3) From 9396e5e02d863f6fa8c72b503895379b9ebd6a85 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 7 Jan 2012 15:29:57 +0100 Subject: [PATCH 004/664] First work for LibPack8 and PropertyUUID --- src/Base/Uuid.h | 7 +++++++ src/Mod/Assembly/App/AppAssembly.cpp | 7 ++++++- src/Mod/Assembly/App/CMakeLists.txt | 5 +++++ src/Mod/Assembly/App/Item.cpp | 4 +++- src/Mod/Assembly/App/Item.h | 5 +++-- src/Mod/Assembly/Gui/CMakeLists.txt | 6 ++++++ 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Base/Uuid.h b/src/Base/Uuid.h index 3ec4e9af97d4..362d6b7b2618 100644 --- a/src/Base/Uuid.h +++ b/src/Base/Uuid.h @@ -47,8 +47,15 @@ class BaseExport Uuid const std::string& getValue(void) const; static std::string createUuid(void); + /// raw data + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[ 8 ]; + private: std::string _uuid; + }; } //namespace Base diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index 3a2434acd103..d46f1d4d946c 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -30,6 +30,9 @@ #include #include +#include "Item.h" +#include "ItemAssembly.h" +#include "ItemPart.h" extern struct PyMethodDef Assembly_methods[]; @@ -61,7 +64,9 @@ void AssemblyExport initAssembly() // call PyType_Ready, otherwise we run into a segmentation fault, later on. // This function is responsible for adding inherited slots from a type's base class. - //Assembly::FeatureViewPart ::init(); + Assembly::Item ::init(); + Assembly::ItemAssembly ::init(); + Assembly::ItemPart ::init(); } } // extern "C" diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 11eb37cc0442..a9e499a91248 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -1,3 +1,8 @@ +if(MSVC) + add_definitions(-DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH) +else(MSVC) + add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) +endif(MSVC) include_directories( ${CMAKE_SOURCE_DIR}/src diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index b77bb871efcb..0ca9126d86ca 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -39,7 +39,9 @@ PROPERTY_SOURCE(Assembly::Item, Part::Feature) Item::Item() { - ADD_PROPERTY(Model,(0)); + ADD_PROPERTY(Id,(0)); + ADD_PROPERTY(Name,(0)); + ADD_PROPERTY(Description,(0)); } short Item::mustExecute() const diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index 15f4f8af0bde..0dd7f9fe1a26 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -38,8 +38,9 @@ class AssemblyExport Item : public Part::Feature public: Item(); - App::PropertyLinkList Model; - App::PropertyLink Tip; + App::PropertyString Id; + App::PropertyString Name ; + App::PropertyString Description ; /** @name methods override feature */ //@{ diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 432839c5d2a4..04734001b4eb 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -1,3 +1,9 @@ +if(MSVC) + add_definitions(-DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH) +else(MSVC) + add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) +endif(MSVC) + include_directories( ${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} From 04feea80b10d12c5f355a2ce347b9f8fafc77a01 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 15 Jan 2012 12:57:06 +0100 Subject: [PATCH 005/664] Starting DocTool for FreeCAD documents --- src/Mod/Assembly/FCDocTool.py | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/Mod/Assembly/FCDocTool.py diff --git a/src/Mod/Assembly/FCDocTool.py b/src/Mod/Assembly/FCDocTool.py new file mode 100644 index 000000000000..02951285ca6d --- /dev/null +++ b/src/Mod/Assembly/FCDocTool.py @@ -0,0 +1,37 @@ +#! python +# -*- coding: utf-8 -*- +# (c) 2007 Juergen Riegel LGPL + +import zipfile + +class Document: + """ Document representation """ + def __init__(self,DocFile): + self.FileName = DocFile + print "Parsing: ",DocFile + self.ZFile = zipfile.ZipFile(DocFile,'r') + DStr = self.ZFile.read('Document.xml') + print DStr + + def fileInfo(self): + ret = '' + for i in self.ZFile.infolist(): + i += i.filename + i += '\n' + return ret + + +if __name__ == "__main__": + from optparse import OptionParser + + parser = OptionParser() + parser.add_option("-f", "--file", dest="filename", + help="write report to FILE", metavar="FILE") + parser.add_option("-l", "--list", + action="store_false", dest="verbose", default=True, + help="don't print status messages to stdout") + + (options, args) = parser.parse_args() + print (options,args) + d = Document(args[0]) + From 1feafdd2c5d9364bc309311af6291d5ae1729be5 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 15 Jan 2012 21:44:52 +0100 Subject: [PATCH 006/664] Adding ViewProvider --- src/Mod/Assembly/App/Item.cpp | 1 + src/Mod/Assembly/App/Item.h | 14 ++++++-- src/Mod/Assembly/App/ItemAssembly.cpp | 32 +++++++++++++++-- src/Mod/Assembly/App/ItemAssembly.h | 6 ++-- src/Mod/Assembly/App/ItemPart.cpp | 7 +++- src/Mod/Assembly/Gui/CMakeLists.txt | 22 ++++++++++-- src/Mod/Assembly/Gui/PreCompiled.h | 2 ++ src/Mod/Assembly/Gui/ViewProvider.cpp | 50 ++++++++++++++++++++++++++ src/Mod/Assembly/Gui/ViewProvider.h | 51 +++++++++++++++++++++++++++ 9 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 src/Mod/Assembly/Gui/ViewProvider.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProvider.h diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index 0ca9126d86ca..b43225ac999d 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -40,6 +40,7 @@ PROPERTY_SOURCE(Assembly::Item, Part::Feature) Item::Item() { ADD_PROPERTY(Id,(0)); + ADD_PROPERTY(Uid,(0)); ADD_PROPERTY(Name,(0)); ADD_PROPERTY(Description,(0)); } diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index 0dd7f9fe1a26..a572526304c3 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -38,9 +38,17 @@ class AssemblyExport Item : public Part::Feature public: Item(); + /** @name base properties of all Assembly Items */ + //@{ + /// Id e.g. Part number App::PropertyString Id; + /// unique identifier of the Item + App::PropertyUUID Uid; + /// Name of the Item (human readable) App::PropertyString Name ; + /// long description of the Item App::PropertyString Description ; + //@} /** @name methods override feature */ //@{ @@ -48,9 +56,9 @@ class AssemblyExport Item : public Part::Feature App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderItem"; - //} + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderItem"; + } //@} }; diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index ce43002eca4e..e6210ca3b8cd 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -23,9 +23,11 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include +#include #include "ItemAssembly.h" @@ -52,8 +54,34 @@ short ItemAssembly::mustExecute() const App::DocumentObjectExecReturn *ItemAssembly::execute(void) { - + std::vector s; + std::vector obj = Items.getValues(); + + std::vector::iterator it; + for (it = obj.begin(); it != obj.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(Assembly::Item::getClassTypeId())) { + s.push_back(static_cast(*it)->Shape.getValue()); + } + } + + if (s.size() > 0) { + TopoDS_Compound aRes = TopoDS_Compound(); + BRep_Builder aBuilder = BRep_Builder(); + aBuilder.MakeCompound(aRes); + + for (std::vector::iterator it = s.begin(); it != s.end(); ++it) { + + aBuilder.Add(aRes, *it); + } + if (aRes.IsNull()) + throw Base::Exception("Resulting shape is invalid"); + this->Shape.setValue(aRes); + } + else { + // set empty shape + this->Shape.setValue(TopoDS_Shape()); + } return App::DocumentObject::StdReturn; } -} \ No newline at end of file +} diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 86b3ef2429f8..35e822390482 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -46,9 +46,9 @@ class AssemblyExport ItemAssembly : public Assembly::Item App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderItemAssembly"; - //} + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderItemAssembly"; + } //@} }; diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index 85e1db9e139a..3e909a2955eb 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -52,7 +52,12 @@ short ItemPart::mustExecute() const App::DocumentObjectExecReturn *ItemPart::execute(void) { - + App::DocumentObject* obj = Model.getValue(); + + if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + this->Shape.setValue(static_cast(obj)->Shape.getValue()); + } + return App::DocumentObject::StdReturn; } diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 04734001b4eb..6487b35f04c7 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -10,8 +10,10 @@ include_directories( ${Boost_INCLUDE_DIRS} ${COIN_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} + ${OCC_INCLUDE_DIR} ${QT_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS} + ${COIN3D_INCLUDE_DIRS} ${XercesC_INCLUDE_DIRS} #${ODE_INCLUDE_DIRS} ) @@ -19,22 +21,38 @@ include_directories( set(AssemblyGui_LIBS #${ODE_LIBRARIES} Assembly + PartGui FreeCADGui ) qt4_add_resources(AssemblyGui_SRCS Resources/Assembly.qrc) -SET(AssemblyGui_SRCS - ${AssemblyGui_SRCS} + +SET(AssemblyGuiViewProvider_SRCS + ViewProvider.cpp + ViewProvider.h +) +SOURCE_GROUP("ViewProvider" FILES ${AssemblyGuiViewProvider_SRCS}) + +SET(AssemblyGuiModule_SRCS AppAssemblyGui.cpp AppAssemblyGuiPy.cpp Command.cpp Resources/Assembly.qrc + qrc_Assembly.cxx PreCompiled.cpp PreCompiled.h Workbench.cpp Workbench.h ) +SOURCE_GROUP("Module" FILES ${AssemblyGuiModule_SRCS}) + + +SET(AssemblyGui_SRCS + ${AssemblyGui_SRCS} + ${AssemblyGuiViewProvider_SRCS} + ${AssemblyGuiModule_SRCS} +) add_library(AssemblyGui SHARED ${AssemblyGui_SRCS}) target_link_libraries(AssemblyGui ${AssemblyGui_LIBS}) diff --git a/src/Mod/Assembly/Gui/PreCompiled.h b/src/Mod/Assembly/Gui/PreCompiled.h index 402f58d47b86..3fe37f681084 100644 --- a/src/Mod/Assembly/Gui/PreCompiled.h +++ b/src/Mod/Assembly/Gui/PreCompiled.h @@ -29,9 +29,11 @@ // Importing of App classes #ifdef FC_OS_WIN32 # define AssemblyAppExport __declspec(dllimport) +# define PartGuiExport __declspec(dllimport) # define AssemblyGuiExport __declspec(dllexport) #else // for Linux # define AssemblyAppExport +# define PartGuiExport # define AssemblyGuiExport #endif diff --git a/src/Mod/Assembly/Gui/ViewProvider.cpp b/src/Mod/Assembly/Gui/ViewProvider.cpp new file mode 100644 index 000000000000..8193335ab4ba --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProvider.cpp @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 "ViewProvider.h" +#include +//#include + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProvider,PartGui::ViewProviderPart) + +ViewProvider::ViewProvider() +{ +} + +ViewProvider::~ViewProvider() +{ +} + +bool ViewProvider::doubleClicked(void) +{ + return true; +} + + diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h new file mode 100644 index 000000000000..8f75eb8a430d --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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_ViewProvider_H +#define PARTGUI_ViewProvider_H + +#include + + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProvider : public PartGui::ViewProviderPart +{ + PROPERTY_HEADER(PartGui::ViewProvider); + +public: + /// constructor + ViewProvider(); + /// destructor + virtual ~ViewProvider(); + + virtual bool doubleClicked(void); + +}; + + + +} // namespace AssemblyGui + + +#endif // PARTGUI_ViewProviderHole_H From 1bb3fbc11996f00fe8fae47327c6db7afefa9975 Mon Sep 17 00:00:00 2001 From: "U-EMEA\\jriegel" Date: Wed, 18 Jan 2012 19:00:01 +0100 Subject: [PATCH 007/664] Add ViewProvider for Assembly and Part and add FreeGCE3D --- src/Mod/Assembly/App/gcs3d/CMakeLists.txt | 24 + src/Mod/Assembly/App/gcs3d/Constraints.cpp | 416 ++++++ src/Mod/Assembly/App/gcs3d/Constraints.h | 133 ++ src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx | 28 + src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx | 61 + src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx | 55 + src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx | 64 + src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx | 61 + src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx | 64 + src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx | 64 + src/Mod/Assembly/App/gcs3d/GCS.cpp | 1139 +++++++++++++++++ src/Mod/Assembly/App/gcs3d/GCS.h | 122 ++ src/Mod/Assembly/App/gcs3d/Geo.h | 67 + src/Mod/Assembly/App/gcs3d/InputParser.cpp | 359 ++++++ src/Mod/Assembly/App/gcs3d/InputParser.h | 60 + src/Mod/Assembly/App/gcs3d/SubSystem.cpp | 351 +++++ src/Mod/Assembly/App/gcs3d/SubSystem.h | 89 ++ src/Mod/Assembly/App/gcs3d/Util.h | 47 + src/Mod/Assembly/App/gcs3d/main.cpp | 122 ++ src/Mod/Assembly/App/gcs3d/qp_eq.cpp | 65 + src/Mod/Assembly/App/gcs3d/qp_eq.h | 25 + src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 50 + src/Mod/Assembly/Gui/ViewProviderAssembly.h | 51 + src/Mod/Assembly/Gui/ViewProviderPart.cpp | 50 + src/Mod/Assembly/Gui/ViewProviderPart.h | 51 + 25 files changed, 3618 insertions(+) create mode 100644 src/Mod/Assembly/App/gcs3d/CMakeLists.txt create mode 100644 src/Mod/Assembly/App/gcs3d/Constraints.cpp create mode 100644 src/Mod/Assembly/App/gcs3d/Constraints.h create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx create mode 100644 src/Mod/Assembly/App/gcs3d/GCS.cpp create mode 100644 src/Mod/Assembly/App/gcs3d/GCS.h create mode 100644 src/Mod/Assembly/App/gcs3d/Geo.h create mode 100644 src/Mod/Assembly/App/gcs3d/InputParser.cpp create mode 100644 src/Mod/Assembly/App/gcs3d/InputParser.h create mode 100644 src/Mod/Assembly/App/gcs3d/SubSystem.cpp create mode 100644 src/Mod/Assembly/App/gcs3d/SubSystem.h create mode 100644 src/Mod/Assembly/App/gcs3d/Util.h create mode 100644 src/Mod/Assembly/App/gcs3d/main.cpp create mode 100644 src/Mod/Assembly/App/gcs3d/qp_eq.cpp create mode 100644 src/Mod/Assembly/App/gcs3d/qp_eq.h create mode 100644 src/Mod/Assembly/Gui/ViewProviderAssembly.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderAssembly.h create mode 100644 src/Mod/Assembly/Gui/ViewProviderPart.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderPart.h diff --git a/src/Mod/Assembly/App/gcs3d/CMakeLists.txt b/src/Mod/Assembly/App/gcs3d/CMakeLists.txt new file mode 100644 index 000000000000..518b8553efc6 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/CMakeLists.txt @@ -0,0 +1,24 @@ +project(solver) + +cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +find_package(XercesC REQUIRED) +find_package(Eigen3) + +include_directories(${EIGEN3_INCLUDE_DIR}) + +#add_subdirectory(NewSolver) + +set(solver_SRC main.cpp + Constraints.cpp + GCS.cpp + InputParser.cpp + qp_eq.cpp + SubSystem.cpp) + +add_executable(solver ${solver_SRC}) + +target_link_libraries(solver ${XERCESC_LIBRARIES}) + + diff --git a/src/Mod/Assembly/App/gcs3d/Constraints.cpp b/src/Mod/Assembly/App/gcs3d/Constraints.cpp new file mode 100644 index 000000000000..8dbe679358af --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Constraints.cpp @@ -0,0 +1,416 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 +#include "Constraints.h" + +using namespace Eigen; + +namespace GCS +{ + +/////////////////////////////////////// +// Constraints +/////////////////////////////////////// + +Constraint::Constraint() +: origpvec(0), pvec(0), scale(1.), tag(0) +{ +} + +void Constraint::redirectParams(MAP_pD_pD redirectionmap) +{ + int i=0; + for (VEC_pD::iterator param=origpvec.begin(); + param != origpvec.end(); ++param, i++) { + MAP_pD_pD::const_iterator it = redirectionmap.find(*param); + if (it != redirectionmap.end()) + pvec[i] = it->second; + } +} + +void Constraint::revertParams() +{ + pvec = origpvec; +} + +ConstraintType Constraint::getTypeId() +{ + return None; +} + +void Constraint::rescale(double coef) +{ + scale = coef * 1.; +} + +double Constraint::error() +{ + return 0.; +} + +double Constraint::grad(double *param) +{ + return 0.; +} + +double Constraint::maxStep(MAP_pD_D &dir, double lim) +{ + return lim; +} + + +//quattorot and derivatives + +Matrix3d rotation(double a, double b, double c, double d) { + + double norm = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); + double x=a/norm, y=b/norm, z=c/norm, w=d/norm; + + Matrix3d rot; + rot(0,0) = 1-2*(pow(y,2)+pow(z,2)); + rot(0,1) = -2.0*w*z + 2.0*x*y; + rot(0,2) = 2.0*w*y + 2.0*x*z; + rot(1,0) = 2.0*w*z + 2.0*x*y; + rot(1,1) = 1-2*(pow(x,2)+pow(z,2)); + rot(1,2) = -2.0*w*x + 2.0*y*z; + rot(2,0) = -2.0*w*y + 2.0*x*z; + rot(2,1) = 2.0*w*x + 2.0*y*z; + rot(2,2) = 1-2*(pow(x,2)+pow(y,2)); + + return rot; +} + +Matrix3d rotation_da(double a, double b, double c, double d) { + + double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); + double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); + double x=a/no, y=b/no, z=c/no, w=d/no; + + double dxa = 1.0/no - pow(a,2)/pow(no,3); + double dya = (-1.0*b*a)/div; + double dza = (-1.0*c*a)/div; + double dwa = (-1.0*d*a)/div; + + Matrix3d rot; + rot << -4.0*(y*dya+z*dza), -2.0*(w*dza+dwa*z)+2.0*(x*dya+dxa*y), 2.0*(dwa*y+w*dya)+2.0*(dxa*z+x*dza), + 2.0*(w*dza+dwa*z)+2.0*(x*dya+dxa*y), -4.0*(x*dxa+z*dza), -2.0*(dwa*x+w*dxa)+2.0*(dya*z+y*dza), + -2.0*(dwa*y+w*dya)+2.0*(dxa*z+x*dza), 2.0*(dwa*x+w*dxa)+2.0*(dya*z+y*dza), -4.0*(x*dxa+y*dya); + + return rot; +} + +Matrix3d rotation_db(double a, double b, double c, double d) { + + double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); + double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); + double x=a/no, y=b/no, z=c/no, w=d/no; + + double dxb = (-1.0*a*b)/div; + double dyb = 1.0/no - pow(b,2)/pow(no,3); + double dzb = (-1.0*c*b)/div; + double dwb = (-1.0*d*b)/div; + + Matrix3d rot; + rot << -4.0*(y*dyb+z*dzb), -2.0*(w*dzb+dwb*z)+2.0*(x*dyb+dxb*y), 2.0*(dwb*y+w*dyb)+2.0*(dxb*z+x*dzb), + 2.0*(w*dzb+dwb*z)+2.0*(x*dyb+dxb*y), -4.0*(x*dxb+z*dzb), -2.0*(dwb*x+w*dxb)+2.0*(dyb*z+y*dzb), + -2.0*(dwb*y+w*dyb)+2.0*(dxb*z+x*dzb), 2.0*(dwb*x+w*dxb)+2.0*(dyb*z+y*dzb), -4.0*(x*dxb+y*dyb); + + return rot; +} + +Matrix3d rotation_dc(double a, double b, double c, double d) { + + double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); + double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); + double x=a/no, y=b/no, z=c/no, w=d/no; + + double dxc = (-1.0*a*c)/div; + double dyc = (-1.0*b*c)/div; + double dzc = 1.0/no - pow(c,2)/pow(no,3); + double dwc = (-1.0*d*c)/div; + + Matrix3d rot; + rot << -4.0*(y*dyc+z*dzc), -2.0*(w*dzc+dwc*z)+2.0*(x*dyc+dxc*y), 2.0*(dwc*y+w*dyc)+2.0*(dxc*z+x*dzc), + 2.0*(w*dzc+dwc*z)+2.0*(x*dyc+dxc*y), -4.0*(x*dxc+z*dzc), -2.0*(dwc*x+w*dxc)+2.0*(dyc*z+y*dzc), + -2.0*(dwc*y+w*dyc)+2.0*(dxc*z+x*dzc), 2.0*(dwc*x+w*dxc)+2.0*(dyc*z+y*dzc), -4.0*(x*dxc+y*dyc); + + return rot; +} + +Matrix3d rotation_dd(double a, double b, double c, double d) { + + double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); + double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); + double x=a/no, y=b/no, z=c/no, w=d/no; + + double dxd = (-1.0*a*d)/div; + double dyd = (-1.0*b*d)/div; + double dzd = (-1.0*c*d)/div; + double dwd = 1.0/no - pow(d,2)/pow(no,3); + + Matrix3d rot; + rot << -4.0*(y*dyd+z*dzd), -2.0*(w*dzd+dwd*z)+2.0*(x*dyd+dxd*y), 2.0*(dwd*y+w*dyd)+2.0*(dxd*z+x*dzd), + 2.0*(w*dzd+dwd*z)+2.0*(x*dyd+dxd*y), -4.0*(x*dxd+z*dzd), -2.0*(dwd*x+w*dxd)+2.0*(dyd*z+y*dzd), + -2.0*(dwd*y+w*dyd)+2.0*(dxd*z+x*dzd), 2.0*(dwd*x+w*dxd)+2.0*(dyd*z+y*dzd), -4.0*(x*dxd+y*dyd); + + return rot; +} + + +//Plane parallel (need to be treated special as angle=0° or angle=180° dos not work with angle constraint +ConstraintParralelFaceAS::ConstraintParralelFaceAS( GCS::Solid& s0, GCS::Solid& s1, ParallelType *t) +{ + type = t; + + //get the face placements in the objects coordinate system and calculate the normals + Vector3d a,b; + a << s0.n.x, s0.n.y, s0.n.z; + b << s1.n.x, s1.n.y, s1.n.z; + + //get the normal vector + n0 = (a).normalized(); + n1 = (b).normalized(); + + + pvec.push_back(s0.q.a); + pvec.push_back(s0.q.b); + pvec.push_back(s0.q.c); + pvec.push_back(s0.q.d); + pvec.push_back(s1.q.a); + pvec.push_back(s1.q.b); + pvec.push_back(s1.q.c); + pvec.push_back(s1.q.d); + origpvec = pvec; + rescale(); + +} + +ConstraintType ConstraintParralelFaceAS::getTypeId() +{ + return ASParallel; +} + +void ConstraintParralelFaceAS::rescale(double coef) +{ + scale = coef; +} + +double ConstraintParralelFaceAS::error() +{ + + Matrix3d rot0, rot1; + + rot0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); + rot1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); + + Vector3d n0_g = (rot0*n0); + Vector3d n1_g = (rot1*n1); + + double error = 0; + if (*type == GCS::NormalSame) + error = pow((n0_g-n1_g).norm(),2); + else + error = pow((n0_g+n1_g).norm(),2); + + return error; +} + +double ConstraintParralelFaceAS::grad(double* param) +{ + + Vector3d dn; + Matrix3d r0, r1; + r0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); + r1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); + + if (param == q0a()) { + Matrix3d rot = rotation_da(*q0a(), *q0b(), *q0c(), *q0d()); + dn = rot*n0; + } + else if (param == q0b()) { + Matrix3d rot = rotation_db(*q0a(), *q0b(), *q0c(), *q0d()); + dn = rot*n0; + } + else if (param == q0c()) { + Matrix3d rot = rotation_dc(*q0a(), *q0b(), *q0c(), *q0d()); + dn = rot*n0; + } + else if (param == q0d()) { + Matrix3d rot = rotation_dd(*q0a(), *q0b(), *q0c(), *q0d()); + dn = rot*n0; + } + else if (param == q1a()) { + Matrix3d rot = rotation_da(*q1a(), *q1b(), *q1c(), *q1d()); + dn = rot*n1*-1; + } + else if (param == q1b()) { + Matrix3d rot = rotation_db(*q1a(), *q1b(), *q1c(), *q1d()); + dn = rot*n1*-1; + } + else if (param == q1c()) { + Matrix3d rot = rotation_dc(*q1a(), *q1b(), *q1c(), *q1d()); + dn = rot*n1*-1; + } + else if (param == q1d()) { + Matrix3d rot = rotation_dd(*q1a(), *q1b(), *q1c(), *q1d()); + dn = rot*n1*-1; + } + else return 0; + + + Vector3d n0n = r0*n0; + Vector3d n1n = r1*n1; + + double div = 0; + if (*type == NormalSame) + div = (n0n-n1n).dot(dn)*2; + else + div = (n0n+n1n).dot(dn)*2; + + return div; +} + + +//dDistance constraint + +ConstraintFaceDistanceAS::ConstraintFaceDistanceAS(GCS::Solid& s0, GCS::Solid& s1, double *d) +{ + + n0 << s0.n.x, s0.n.y, s0.n.z; + n0.normalize(); + p0 << s0.p.x, s0.p.y, s0.p.z; + p1 << s1.p.x, s1.p.y, s1.p.z; + + //and positions + pvec.push_back(s0.d.x); + pvec.push_back(s0.d.y); + pvec.push_back(s0.d.z); + pvec.push_back(s1.d.x); + pvec.push_back(s1.d.y); + pvec.push_back(s1.d.z); + + //quaternions + pvec.push_back(s0.q.a); + pvec.push_back(s0.q.b); + pvec.push_back(s0.q.c); + pvec.push_back(s0.q.d); + pvec.push_back(s1.q.a); + pvec.push_back(s1.q.b); + pvec.push_back(s1.q.c); + pvec.push_back(s1.q.d); + + //distance + dist = d; + + origpvec = pvec; + rescale(); + +} + +ConstraintType ConstraintFaceDistanceAS::getTypeId() +{ + return ASDistance; +} + +void ConstraintFaceDistanceAS::rescale(double coef) +{ + scale = coef; +} + +double ConstraintFaceDistanceAS::error() +{ + + Matrix3d rot0, rot1; + Vector3d v0, v1; + + rot0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); + rot1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); + v0 << *p0x(), *p0y(), *p0z(); + v1 << *p1x(), *p1y(), *p1z(); + + double error = std::pow(((rot0*n0).dot(rot1*p1+v1) - (rot0*n0).dot(rot0*p0+v0))/(rot0*n0).norm() - *dist,2); + + return error; +} + +double ConstraintFaceDistanceAS::grad(double* param) +{ + + Matrix3d r0, r1; + Vector3d v0, v1; + + v0 << *p0x(), *p0y(), *p0z(); + v1 << *p1x(), *p1y(), *p1z(); + r0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); + r1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); + + Matrix3d dr0, dr1; + double div = 0; + double error=((r0*n0).dot(r1*p1+v1) - (r0*n0).dot(r0*p0+v0))/(r0*n0).norm() - *dist; + if (param == q0a() || param == q0b() || param == q0c() || param == q0d()) { + + if (param == q0a()) dr0 = rotation_da(*q0a(), *q0b(), *q0c(), *q0d()); + else if (param == q0b()) dr0 = rotation_db(*q0a(), *q0b(), *q0c(), *q0d()); + else if (param == q0c()) dr0 = rotation_dc(*q0a(), *q0b(), *q0c(), *q0d()); + else if (param == q0d()) dr0 = rotation_dd(*q0a(), *q0b(), *q0c(), *q0d()); + + VectorXd r0n = r0*n0; + div = ( (dr0*n0).dot(r1*p1+v1)*r0n.norm() - r0n.dot(r1*p1+v1)*r0n.dot(dr0*n0)/r0n.norm() ); + div -= ( ((dr0*n0).dot(r0*p0+v0)+r0n.dot(dr0*p0))*r0n.norm() ); + div -= ( r0n.dot(r0*p0+v0)*r0n.dot(dr0*n0)/r0n.norm() ); + div /= pow(r0n.norm(),2); + } + else if (param == q1a() || param == q1b() || param == q1c() || param == q1d()) { + + if (param == q1a()) dr1 = rotation_da(*q1a(), *q1b(), *q1c(), *q1d()); + else if (param == q1b()) dr1 = rotation_db(*q1a(), *q1b(), *q1c(), *q1d()); + else if (param == q1c()) dr1 = rotation_dc(*q1a(), *q1b(), *q1c(), *q1d()); + else if (param == q1d()) dr1 = rotation_dd(*q1a(), *q1b(), *q1c(), *q1d()); + + div = (r0*n0).dot(dr1*p1)/(r0*n0).norm(); + } + else if (param == p0x() || param == p0y() || param == p0z()) { + + Vector3d dp_g; + if (param == p0x()) dp_g << 1,0,0; + else if (param == p0y()) dp_g << 0,1,0; + else if (param == p0z()) dp_g << 0,0,1; + + div = -1*(r0*n0).dot(dp_g)/(r0*n0).norm(); + } + else if (param == p1x() || param == p1y() || param == p1z()) { + + Vector3d dp_g; + if (param == p1x()) dp_g << 1,0,0; + else if (param == p1y()) dp_g << 0,1,0; + else if (param == p1z()) dp_g << 0,0,1; + + div = (r0*n0).dot(dp_g)/(r0*n0).norm(); + } + else return 0; + + div *= 2*error; + return div; +} + +} //namespace GCS diff --git a/src/Mod/Assembly/App/gcs3d/Constraints.h b/src/Mod/Assembly/App/gcs3d/Constraints.h new file mode 100644 index 000000000000..f8b2b38c95d6 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Constraints.h @@ -0,0 +1,133 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 FREEGCS_CONSTRAINTS_H +#define FREEGCS_CONSTRAINTS_H + +#include "Geo.h" +#include "Util.h" +#include + +namespace GCS +{ + + /////////////////////////////////////// + // Constraints + /////////////////////////////////////// + + enum ConstraintType { + None = 0, + ASParallel, + ASDistance + }; + + enum ParallelType { + + NormalWhatever = 0, + NormalSame, + NormalOpposite + }; + + class Constraint + { + protected: + VEC_pD origpvec; // is used only as a reference for redirecting and reverting pvec + VEC_pD pvec; + double scale; + int tag; + public: + Constraint(); + + inline VEC_pD params() { return pvec; } + + void redirectParams(MAP_pD_pD redirectionmap); + void revertParams(); + void setTag(int tagId) { tag = tagId; } + int getTag() { return tag; } + + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + // virtual void grad(MAP_pD_D &deriv); --> TODO: vectorized grad version + virtual double maxStep(MAP_pD_D &dir, double lim=1.); + }; + + // AS_plane_parallel + class ConstraintParralelFaceAS : public Constraint + { + private: + inline double* q0a() { return pvec[0]; } + inline double* q0b() { return pvec[1]; } + inline double* q0c() { return pvec[2]; } + inline double* q0d() { return pvec[3]; } + inline double* q1a() { return pvec[4]; } + inline double* q1b() { return pvec[5]; } + inline double* q1c() { return pvec[6]; } + inline double* q1d() { return pvec[7]; } + + Eigen::Vector3d n0, n1; + ParallelType *type; + + public: + ConstraintParralelFaceAS(GCS::Solid& s0, GCS::Solid& s1, ParallelType *t); + + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + + class ConstraintFaceDistanceAS : public Constraint + { + private: + inline double* p0x() { return pvec[0]; } + inline double* p0y() { return pvec[1]; } + inline double* p0z() { return pvec[2]; } + inline double* p1x() { return pvec[3]; } + inline double* p1y() { return pvec[4]; } + inline double* p1z() { return pvec[5]; } + inline double* q0a() { return pvec[6]; } + inline double* q0b() { return pvec[7]; } + inline double* q0c() { return pvec[8]; } + inline double* q0d() { return pvec[9]; } + inline double* q1a() { return pvec[10]; } + inline double* q1b() { return pvec[11]; } + inline double* q1c() { return pvec[12]; } + inline double* q1d() { return pvec[13]; } + + Eigen::Vector3d p0, p1; + Eigen::Vector3d n0; + + double *dist; + public: + ConstraintFaceDistanceAS(GCS::Solid& s0, GCS::Solid& s1, double *d); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + + +} //namespace GCS + +#endif // FREEGCS_CONSTRAINTS_H diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx new file mode 100644 index 000000000000..8216a86e5ef7 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx new file mode 100644 index 000000000000..68e3d8c5dbde --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx new file mode 100644 index 000000000000..207e000674d2 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx new file mode 100644 index 000000000000..5164d326eb9f --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx new file mode 100644 index 000000000000..d505e772ce6f --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx new file mode 100644 index 000000000000..c4ccdfa2c781 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx new file mode 100644 index 000000000000..ab4cd68738dd --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/GCS.cpp b/src/Mod/Assembly/App/gcs3d/GCS.cpp new file mode 100644 index 000000000000..1a5fc76a0370 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/GCS.cpp @@ -0,0 +1,1139 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 +#include +#include + +#include "GCS.h" +#include "qp_eq.h" +#include + +#include +#include +#include + +namespace GCS +{ + + +/////////////////////////////////////// +// Solver +/////////////////////////////////////// + +// System +System::System() + : clist(0), + c2p(), p2c(), + subsys0(0), + subsys1(0), + subsys2(0), + reference(), + init(false) +{ +} + +System::System(std::vector clist_) + : c2p(), p2c(), + subsys0(0), + subsys1(0), + subsys2(0), + reference(), + init(false) +{ + // create own (shallow) copy of constraints + for (std::vector::iterator constr=clist_.begin(); + constr != clist_.end(); ++constr) { + Constraint *newconstr; + switch ((*constr)->getTypeId()) { + + case GCS::ASParallel: { + ConstraintParralelFaceAS *oldconstr = static_cast(*constr); + newconstr = new ConstraintParralelFaceAS(*oldconstr); + break; + } + case GCS::ASDistance: { + ConstraintFaceDistanceAS *oldconstr = static_cast(*constr); + newconstr = new ConstraintFaceDistanceAS(*oldconstr); + break; + } + case None: + break; + } + if (newconstr) + addConstraint(newconstr); + } +} + +System::~System() +{ + clear(); +} + +void System::clear() +{ + clearReference(); + clearSubSystems(); + free(clist); + c2p.clear(); + p2c.clear(); +} + +void System::clearByTag(int tagId) +{ + std::vector constrvec; + for (std::vector::const_iterator + constr=clist.begin(); constr != clist.end(); ++constr) { + if ((*constr)->getTag() == tagId) + constrvec.push_back(*constr); + } + for (std::vector::const_iterator + constr=constrvec.begin(); constr != constrvec.end(); ++constr) { + removeConstraint(*constr); + } +} + +int System::addConstraint(Constraint *constr) +{ + clearReference(); + + clist.push_back(constr); + VEC_pD constr_params = constr->params(); + for (VEC_pD::const_iterator param=constr_params.begin(); + param != constr_params.end(); ++param) { +// jacobi.set(constr, *param, 0.); + c2p[constr].push_back(*param); + p2c[*param].push_back(constr); + } + return clist.size()-1; +} + +void System::removeConstraint(Constraint *constr) +{ + clearReference(); + clearSubSystems(); + + std::vector::iterator it; + it = std::find(clist.begin(), clist.end(), constr); + clist.erase(it); + + VEC_pD constr_params = c2p[constr]; + for (VEC_pD::const_iterator param=constr_params.begin(); + param != constr_params.end(); ++param) { + std::vector &constraints = p2c[*param]; + it = std::find(constraints.begin(), constraints.end(), constr); + constraints.erase(it); + } + c2p.erase(constr); + + std::vector constrvec; + constrvec.push_back(constr); + free(constrvec); +} + + + +void System::initSolution(VEC_pD ¶ms) +{ + // - Stores the current parameters in the vector "reference" + // - Identifies the equality constraints tagged with ids >= 0 + // and prepares a corresponding system reduction + // - Organizes the rest of constraints into two subsystems for + // tag ids >=0 and < 0 respectively and applies the + // system reduction specified in the previous step + + clearReference(); + for (VEC_pD::const_iterator param=params.begin(); + param != params.end(); ++param) + reference[*param] = **param; + + // identification of equality constraints and parameter reduction + std::set eliminated; // constraints that will be eliminated through reduction + reductionmap.clear(); + { + VEC_pD reduced_params=params; + MAP_pD_I params_index; + for (int i=0; i < int(params.size()); ++i) + params_index[params[i]] = i; + + /* for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr) { + if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) { + MAP_pD_I::const_iterator it1,it2; + it1 = params_index.find((*constr)->params()[0]); + it2 = params_index.find((*constr)->params()[1]); + if (it1 != params_index.end() && it2 != params_index.end()) { + eliminated.insert(*constr); + double *p_kept = reduced_params[it1->second]; + double *p_replaced = reduced_params[it2->second]; + for (int i=0; i < int(params.size()); ++i) + if (reduced_params[i] == p_replaced) + reduced_params[i] = p_kept; + } + } + }*/ + for (int i=0; i < int(params.size()); ++i) + if (params[i] != reduced_params[i]) + reductionmap[params[i]] = reduced_params[i]; + } + + int i=0; + std::vector clist0, clist1, clist2; + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr, i++) { + if (eliminated.count(*constr) == 0) { + if ((*constr)->getTag() >= 0) + clist0.push_back(*constr); + else if ((*constr)->getTag() == -1) // move constraints + clist1.push_back(*constr); + else // distance from reference constraints + clist2.push_back(*constr); + } + } + + clearSubSystems(); + if (clist0.size() > 0) + subsys0 = new SubSystem(clist0, params, reductionmap); + if (clist1.size() > 0) + subsys1 = new SubSystem(clist1, params, reductionmap); + if (clist2.size() > 0) + subsys2 = new SubSystem(clist2, params, reductionmap); + init = true; +} + +void System::clearReference() +{ + init = false; + reference.clear(); +} + +void System::resetToReference() +{ + for (MAP_pD_D::const_iterator it=reference.begin(); + it != reference.end(); ++it) + *(it->first) = it->second; +} + +int System::solve(VEC_pD ¶ms, bool isFine, Algorithm alg) +{ + initSolution(params); + return solve(isFine, alg); +} + +int System::solve(bool isFine, Algorithm alg) +{ + if (subsys0) { + resetToReference(); + if (subsys2) { + int ret = solve(subsys0, subsys2, isFine); + if (subsys1) // give subsys1 higher priority than subsys2 + // in this case subsys2 acts like a preconditioner + return solve(subsys0, subsys1, isFine); + else + return ret; + } + else if (subsys1) + return solve(subsys0, subsys1, isFine); + else + return solve(subsys0, isFine, alg); + } + else if (subsys1) { + resetToReference(); + if (subsys2) + return solve(subsys1, subsys2, isFine); + else + return solve(subsys1, isFine, alg); + } + else + // return success in order to permit coincidence constraints to be applied + return Success; +} + +int System::solve(SubSystem *subsys, bool isFine, Algorithm alg) +{ + + std::cout << std::endl << "Initial Error: " << subsys->error() << std::endl; + clock_t begin = clock(); + int ret; + if (alg == BFGS) + ret= solve_BFGS(subsys, isFine); + else if (alg == LevenbergMarquardt) + ret= solve_LM(subsys); + else if (alg == DogLeg) + ret= solve_DL(subsys); + else if (alg == HOPS) + ret= solve_EX(subsys); + + clock_t end = clock(); + std::cout << "Time elapsed: " << double( ((end-begin)*1000)/CLOCKS_PER_SEC ) << " ms"<< std::endl; + + return ret; +} + +int System::solve_EX(SubSystem* subsys) { + + + +} + + +int System::solve_BFGS(SubSystem *subsys, bool isFine) +{ + int xsize = subsys->pSize(); + if (xsize == 0) + return Success; + + subsys->redirectParams(); + + Eigen::MatrixXd D = Eigen::MatrixXd::Identity(xsize, xsize); + Eigen::VectorXd x(xsize); + Eigen::VectorXd xdir(xsize); + Eigen::VectorXd grad(xsize); + Eigen::VectorXd h(xsize); + Eigen::VectorXd y(xsize); + Eigen::VectorXd Dy(xsize); + + // Initial unknowns vector and initial gradient vector + subsys->getParams(x); + subsys->calcGrad(grad); + + // Initial search direction oposed to gradient (steepest-descent) + xdir = grad; + lineSearch(subsys, xdir); + double err = subsys->error(); + + h = x; + subsys->getParams(x); + h = x - h; // = x xold + + double convergence = isFine ? XconvergenceFine : XconvergenceRough; + int maxIterNumber = MaxIterations * xsize; + double diverging_lim = 1e6*err + 1e12; + + for (int iter=1; iter < maxIterNumber; iter++) { + + if (h.norm() <= convergence || err <= smallF) + break; + if (err > diverging_lim || err != err) // check for diverging and NaN + break; + + y = grad; + subsys->calcGrad(grad); + y = grad - y; // = grad gradold + + double hty = h.dot(y); + //make sure that hty is never 0 + if (hty == 0) + hty = .0000000001; + + Dy = D * y; + + double ytDy = y.dot(Dy); + + //Now calculate the BFGS update on D + D += (1.+ytDy/hty)/hty * h * h.transpose(); + D -= 1./hty * (h * Dy.transpose() + Dy * h.transpose()); + + xdir = D * grad; + lineSearch(subsys, xdir); + err = subsys->error(); + + h = x; + subsys->getParams(x); + h = x - h; // = x xold + } + + subsys->revertParams(); + + std::cout << "Error after BFGS solving: " << err << std::endl; + + if (err <= smallF) + return Success; + if (h.norm() <= convergence) + return Converged; + return Failed; +} + +int System::solve_LM(SubSystem* subsys) +{ + int xsize = subsys->pSize(); + int csize = subsys->cSize(); + + if (xsize == 0) + return Success; + + Eigen::VectorXd e(csize), e_new(csize); // vector of all function errors (every constraint is one function) + Eigen::MatrixXd J(csize, xsize); // Jacobi of the subsystem + Eigen::MatrixXd A(xsize, xsize); + Eigen::VectorXd x(xsize), h(xsize), x_new(xsize), g(xsize), diag_A(xsize); + + subsys->redirectParams(); + + subsys->getParams(x); + subsys->calcResidual(e); + e*=-1; + + int maxIterNumber = MaxIterations * xsize; + double diverging_lim = 1e6*e.squaredNorm() + 1e12; + + double eps=1e-10, eps1=1e-80; + double tau=1e-3; + double nu=2, mu=0; + int iter=0, stop=0; + for (iter=0; iter < maxIterNumber && !stop; ++iter) { + + // check error + double err=e.squaredNorm(); + if (err <= eps) { // error is small, Success + stop = 1; + break; + } + else if (err > diverging_lim || err != err) { // check for diverging and NaN + stop = 6; + break; + } + + // J^T J, J^T e + subsys->calcJacobi(J);; + + A = J.transpose()*J; + g = J.transpose()*e; + + // Compute ||J^T e||_inf + double g_inf = g.lpNorm(); + diag_A = A.diagonal(); // save diagonal entries so that augmentation can be later canceled + + // check for convergence + if (g_inf <= eps1) { + stop = 2; + break; + } + + // compute initial damping factor + if (iter == 0) + mu = tau * A.diagonal().lpNorm(); + + // determine increment using adaptive damping + while (1) { + // augment normal equations A = A+uI + for (int i=0; i < xsize; ++i) + A(i,i) += mu; + + //solve augmented functions A*h=-g + h = A.fullPivLu().solve(g); + double rel_error = (A*h - g).norm() / g.norm(); + + // check if solving works + if (rel_error < 1e-5) { +/* + double scale = subsys->maxStep() / h.lpNorm(); + if ( scale < 1.) + h *= scale; +*/ + // compute par's new estimate and ||d_par||^2 + x_new = x + h; + double h_norm = h.squaredNorm(); + + if (h_norm <= eps1*eps1*x.norm()) { // relative change in p is small, stop + stop = 3; + break; + } + else if (h_norm >= (x.norm()+eps1)/(DBL_EPSILON*DBL_EPSILON)) { // almost singular + stop = 4; + break; + } + + subsys->setParams(x_new); + subsys->calcResidual(e_new); + e_new *= -1; + + double dF = e.squaredNorm() - e_new.squaredNorm(); + double dL = h.dot(mu*h+g); + + if (dF>0. && dL>0.) { // reduction in error, increment is accepted + double tmp=2*dF/dL-1.; + mu *= std::max(1./3., 1.-tmp*tmp*tmp); + nu=2; + + // update par's estimate + x = x_new; + e = e_new; + break; + } + } + + // if this point is reached, either the linear system could not be solved or + // the error did not reduce; in any case, the increment must be rejected + + mu*=nu; + nu*=2.0; + for (int i=0; i < xsize; ++i) // restore diagonal J^T J entries + A(i,i) = diag_A(i); + } + } + + if (iter >= maxIterNumber) + stop = 5; + + std::cout << "Error after LM solving: " << subsys->error() << std::endl; + + subsys->revertParams(); + + return (stop == 1) ? Success : Failed; +} + + +int System::solve_DL(SubSystem* subsys) +{ + double tolg=1e-80, tolx=1e-80, tolf=1e-10; + + int xsize = subsys->pSize(); + int csize = subsys->cSize(); + + Eigen::VectorXd x(xsize), x_new(xsize); + Eigen::VectorXd fx(csize), fx_new(csize); + Eigen::MatrixXd Jx(csize, xsize), Jx_new(csize, xsize); + Eigen::VectorXd g(xsize), h_sd(xsize), h_gn(xsize), h_dl(xsize); + + subsys->redirectParams(); + + double err; + subsys->getParams(x); + subsys->calcResidual(fx, err); + subsys->calcJacobi(Jx); + + g = Jx.transpose()*(-fx); + + // get the infinity norm fx_inf and g_inf + double g_inf = g.lpNorm(); + double fx_inf = fx.lpNorm(); + + int maxIterNumber = MaxIterations * xsize; + double diverging_lim = 1e6*err + 1e12; + + double delta=0.1; + double alpha=0.; + double nu=2.; + int iter=0, stop=0, reduce=0; + while (!stop) { + + // check if finished + if (fx_inf <= tolf) // Success + stop = 1; + else if (g_inf <= tolg) + stop = 2; + else if (delta <= tolx*(tolx + x.norm())) + stop = 3; + else if (iter >= maxIterNumber) + stop = 4; + else if (err > diverging_lim || err != err) { // check for diverging and NaN + stop = 6; + } + else { + // get the steepest descent direction + alpha = g.squaredNorm()/(Jx*g).squaredNorm(); + h_sd = alpha*g; + + // get the gauss-newton step + h_gn = Jx.fullPivLu().solve(-fx); + double rel_error = (Jx*h_gn + fx).norm() / fx.norm(); + if (rel_error > 1e15) + break; + + // compute the dogleg step + if (h_gn.norm() < delta) { + h_dl = h_gn; + if (h_dl.norm() <= tolx*(tolx + x.norm())) { + stop = 5; + break; + } + } + else if (alpha*g.norm() >= delta) { + h_dl = (delta/(alpha*g.norm()))*h_sd; + } + else { + //compute beta + double beta = 0; + Eigen::VectorXd b = h_gn - h_sd; + double bb = (b.transpose()*b).norm(); + double gb = (h_sd.transpose()*b).norm(); + double c = (delta + h_sd.norm())*(delta - h_sd.norm()); + + if (gb > 0) + beta = c / (gb + sqrt(gb * gb + c * bb)); + else + beta = (sqrt(gb * gb + c * bb) - gb)/bb; + + // and update h_dl and dL with beta + h_dl = h_sd + beta*b; + } + } + + // see if we are already finished + if (stop) + break; +/* + double scale = subsys->maxStep() / h_dl.lpNorm(); + if ( scale < 1.) + h_dl *= scale; +*/ + // get the new values + double err_new; + x_new = x + h_dl; + subsys->setParams(x_new); + subsys->calcResidual(fx_new, err_new); + subsys->calcJacobi(Jx_new); + + // calculate the linear model and the update ratio + double dL = err - 0.5*(fx + Jx*h_dl).squaredNorm(); + double dF = err - err_new; + double rho = dL/dF; + + if (dF > 0 && dL > 0) { + x = x_new; + Jx = Jx_new; + fx = fx_new; + err = err_new; + + g = Jx.transpose()*(-fx); + + // get infinity norms + g_inf = g.lpNorm(); + fx_inf = fx.lpNorm(); + } + else + rho = -1; + + // update delta + if (fabs(rho-1.) < 0.2 && h_dl.norm() > delta/3. && reduce <= 0) { + delta = 3*delta; + nu = 2; + reduce = 0; + } + else if (rho < 0.25) { + delta = delta/nu; + nu = 2*nu; + reduce = 2; + } + else + reduce--; + + // count this iteration and start again + iter++; + } + + std::cout << "Error after DogLeg solving: " << subsys->error() << std::endl; + + + subsys->revertParams(); + + return (stop == 1) ? Success : Failed; +} + +// The following solver variant solves a system compound of two subsystems +// treating the first of them as of higher priority than the second +int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) +{ + int xsizeA = subsysA->pSize(); + int xsizeB = subsysB->pSize(); + int csizeA = subsysA->cSize(); + + VEC_pD plist(xsizeA+xsizeB); + { + VEC_pD plistA, plistB; + subsysA->getParamList(plistA); + subsysB->getParamList(plistB); + + std::sort(plistA.begin(),plistA.end()); + std::sort(plistB.begin(),plistB.end()); + + VEC_pD::const_iterator it; + it = std::set_union(plistA.begin(),plistA.end(), + plistB.begin(),plistB.end(),plist.begin()); + plist.resize(it-plist.begin()); + } + int xsize = plist.size(); + + Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize); + Eigen::MatrixXd JA(csizeA, xsize); + Eigen::MatrixXd Y,Z; + + Eigen::VectorXd resA(csizeA); + Eigen::VectorXd lambda(csizeA), lambda0(csizeA), lambdadir(csizeA); + Eigen::VectorXd x(xsize), x0(xsize), xdir(xsize), xdir1(xsize); + Eigen::VectorXd grad(xsize); + Eigen::VectorXd h(xsize); + Eigen::VectorXd y(xsize); + Eigen::VectorXd Bh(xsize); + + // We assume that there are no common constraints in subsysA and subsysB + subsysA->redirectParams(); + subsysB->redirectParams(); + + subsysB->getParams(plist,x); + subsysA->getParams(plist,x); + subsysB->setParams(plist,x); // just to ensure that A and B are synchronized + + subsysB->calcGrad(plist,grad); + subsysA->calcJacobi(plist,JA); + subsysA->calcResidual(resA); + + double convergence = isFine ? XconvergenceFine : XconvergenceRough; + int maxIterNumber = MaxIterations * xsize; + double diverging_lim = 1e6*subsysA->error() + 1e12; + + double mu = 0; + lambda.setZero(); + for (int iter=1; iter < maxIterNumber; iter++) { + int status = qp_eq(B, grad, JA, resA, xdir, Y, Z); + if (status) + break; + + x0 = x; + lambda0 = lambda; + lambda = Y.transpose() * (B * xdir + grad); + lambdadir = lambda - lambda0; + + // line search + { + double eta=0.25; + double tau=0.5; + double rho=0.5; + double alpha=1; + alpha = std::min(alpha, subsysA->maxStep(plist,xdir)); + + // Eq. 18.32 + // double mu = lambda.lpNorm() + 0.01; + // Eq. 18.33 + // double mu = grad.dot(xdir) / ( (1.-rho) * resA.lpNorm<1>()); + // Eq. 18.36 + mu = std::max(mu, + (grad.dot(xdir) + std::max(0., 0.5*xdir.dot(B*xdir))) / + ( (1. - rho) * resA.lpNorm<1>() ) ); + + // Eq. 18.27 + double f0 = subsysB->error() + mu * resA.lpNorm<1>(); + + // Eq. 18.29 + double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>(); + + x = x0 + alpha * xdir; + subsysA->setParams(plist,x); + subsysB->setParams(plist,x); + subsysA->calcResidual(resA); + double f = subsysB->error() + mu * resA.lpNorm<1>(); + + // line search, Eq. 18.28 + bool first = true; + while (f > f0 + eta * alpha * deriv) { + if (first) { // try a second order step + // xdir1 = JA.jacobiSvd(Eigen::ComputeThinU | + // Eigen::ComputeThinV).solve(-resA); + xdir1 = -Y*resA; + x += xdir1; // = x0 + alpha * xdir + xdir1 + subsysA->setParams(plist,x); + subsysB->setParams(plist,x); + subsysA->calcResidual(resA); + f = subsysB->error() + mu * resA.lpNorm<1>(); + if (f < f0 + eta * alpha * deriv) + break; + } + alpha = tau * alpha; + x = x0 + alpha * xdir; + subsysA->setParams(plist,x); + subsysB->setParams(plist,x); + subsysA->calcResidual(resA); + f = subsysB->error() + mu * resA.lpNorm<1>(); + } + lambda = lambda0 + alpha * lambdadir; + + } + h = x - x0; + + y = grad - JA.transpose() * lambda; + { + subsysB->calcGrad(plist,grad); + subsysA->calcJacobi(plist,JA); + subsysA->calcResidual(resA); + } + y = grad - JA.transpose() * lambda - y; // Eq. 18.13 + + if (iter > 1) { + double yTh = y.dot(h); + if (yTh != 0) { + Bh = B * h; + //Now calculate the BFGS update on B + B += 1./yTh * y * y.transpose(); + B -= 1./h.dot(Bh) * (Bh * Bh.transpose()); + } + } + + double err = subsysA->error(); + if (h.norm() <= convergence && err <= smallF) + break; + if (err > diverging_lim || err != err) // check for diverging and NaN + break; + } + + int ret; + if (subsysA->error() <= smallF) + ret = Success; + else if (h.norm() <= convergence) + ret = Converged; + else + ret = Failed; + + subsysA->revertParams(); + subsysB->revertParams(); + return ret; + +} + +void System::getSubSystems(std::vector &subsysvec) +{ + subsysvec.clear(); + if (subsys0) + subsysvec.push_back(subsys0); + if (subsys1) + subsysvec.push_back(subsys1); + if (subsys2) + subsysvec.push_back(subsys2); +} + +void System::applySolution() +{ + if (subsys2) + subsys2->applySolution(); + if (subsys1) + subsys1->applySolution(); + if (subsys0) + subsys0->applySolution(); + + for (MAP_pD_pD::const_iterator it=reductionmap.begin(); + it != reductionmap.end(); ++it) + *(it->first) = *(it->second); +} + +int System::diagnose(VEC_pD ¶ms, VEC_I &conflicting) +{ + // Analyses the constrainess grad of the system and provides feedback + // The vector "conflicting" will hold a group of conflicting constraints + conflicting.clear(); + std::vector conflictingIndex; + VEC_I tags; + Eigen::MatrixXd J(clist.size(), params.size()); + int count=0; + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) { + (*constr)->revertParams(); + if ((*constr)->getTag() >= 0) { + count++; + tags.push_back((*constr)->getTag()); + for (int j=0; j < int(params.size()); j++) + J(count-1,j) = (*constr)->grad(params[j]); + } + } + + if (J.rows() > 0) { + Eigen::FullPivHouseholderQR qrJT(J.topRows(count).transpose()); + Eigen::MatrixXd Q = qrJT.matrixQ (); + int params_num = qrJT.rows(); + int constr_num = qrJT.cols(); + int rank = qrJT.rank(); + + Eigen::MatrixXd R; + if (constr_num >= params_num) + R = qrJT.matrixQR().triangularView(); + else + R = qrJT.matrixQR().topRows(constr_num) + .triangularView(); + + if (constr_num > rank) { // conflicting constraints + for (int i=1; i < rank; i++) { + // eliminate non zeros above pivot + assert(R(i,i) != 0); + for (int row=0; row < i; row++) { + if (R(row,i) != 0) { + double coef=R(row,i)/R(i,i); + R.block(row,i+1,1,constr_num-i-1) -= coef * R.block(i,i+1,1,constr_num-i-1); + R(row,i) = 0; + } + } + } + conflictingIndex.resize(constr_num-rank); + for (int j=rank; j < constr_num; j++) { + for (int row=0; row < rank; row++) { + if (R(row,j) != 0) { + int orig_col = qrJT.colsPermutation().indices()[row]; + conflictingIndex[j-rank].push_back(orig_col); + } + } + int orig_col = qrJT.colsPermutation().indices()[j]; + conflictingIndex[j-rank].push_back(orig_col); + } + + SET_I tags_set; + for (int i=0; i < conflictingIndex.size(); i++) { + for (int j=0; j < conflictingIndex[i].size(); j++) { + tags_set.insert(tags[conflictingIndex[i][j]]); + } + } + tags_set.erase(0); // exclude constraints tagged with zero + conflicting.resize(tags_set.size()); + std::copy(tags_set.begin(), tags_set.end(), conflicting.begin()); + + if (params_num == rank) // over-constrained + return params_num - constr_num; + } + + return params_num - rank; + } + return params.size(); +} + +void System::clearSubSystems() +{ + init = false; + std::vector subsystems; + getSubSystems(subsystems); + free(subsystems); + subsys0 = NULL; + subsys1 = NULL; + subsys2 = NULL; +} + + +//calculates the wolfe condition test functions p and g +Eigen::Vector2d PG(SubSystem* sys, Eigen::VectorXd xdir, double sigma) { + + int xsize = sys->pSize(); + Eigen::Vector2d PG; + Eigen::VectorXd x(xsize), x_new(xsize); + Eigen::VectorXd gr(xsize), grn(xsize); + double fx, fxn; + + sys->getParams(x); + fx = sys->error(); + sys->calcGrad(gr); + x_new = x-sigma*xdir; + sys->setParams(x_new); + fxn = sys->error(); + sys->calcGrad(grn); + sys->setParams(x); + + if (sigma == 0) + PG(1) = 1; + else + PG(1) = (fx-fxn) / (sigma * gr.transpose()*xdir).norm(); + + PG(0) = (grn.transpose()*xdir).norm() / (gr.transpose()*xdir).norm(); + + return PG; +} + + +double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir) +{ + double alpha, beta; + int xsize = subsys->pSize(); + + + + //get inital alpha and beta interval + //********************************** + double c3 = 0.1, c4 = 5; + double delta = 0.01, kappa = 0.9, mu = 0.8, sigma, gamma; + double fx, fxmd; + bool run = true; + + Eigen::VectorXd x(xsize), x_new(xsize); + Eigen::VectorXd grad(xsize); + + + subsys->getParams(x); + subsys->calcGrad(grad); + fx = subsys->error(); + x_new = x-xdir; + subsys->setParams(x_new); + fxmd= subsys->error(); + subsys->setParams(x); + + //calculate an guess for sigma + double comp1 = (grad.transpose()*xdir).norm() / std::pow(xdir.norm(),2); + double comp2 = (grad.transpose()*xdir).norm() /(2*(fxmd-fx+(grad.transpose()*xdir).norm())); + sigma = std::min(c4*comp1 , std::max(c3*comp1, comp2)); + + //calculate test functions with guess + Eigen::Vector2d pg = PG(subsys, xdir, sigma); + + //see if we are alread fisished + if ( pg(1)>=delta && pg(0) <= kappa) + run = false; + else if ( pg(1)>=delta && pg(0)>kappa) { + alpha = sigma; + //beta is sigma/mu^j with j minimal so that g(beta)=delta and p(alpha)>=kappa (j element natural numbers) + for (int i=1; i<=1000; i++) { + alpha = sigma*(std::pow(mu, i)); + pg = PG(subsys, xdir, alpha); + if (pg(0)>=kappa && pg(1) >= delta) break; + } + } + + //start sigma search in interval alpha beta + //***************************************** + while (run) { + + gamma = (alpha + beta)/2.; + pg = PG(subsys, xdir, gamma); + + if (pg(0) > kappa && pg(1) >= delta) alpha = gamma; + else if (pg(0) <= kappa && pg(1) >= delta) { + sigma = gamma; + run = false; + } + else beta = gamma; + + if (alpha == beta) break; + } + + x_new = x - sigma* xdir; + subsys->setParams(x_new); + + std::cout << "sigma: "<maxStep(xdir); + + Eigen::VectorXd x0, x; + + //Save initial values + subsys->getParams(x0); + + //Start at the initial position alpha1 = 0 + alpha1 = 0.; + f1 = subsys->error(); + + //Take a step of alpha2 = 1 + alpha2 = 1.; + x = x0 + alpha2 * xdir; + subsys->setParams(x); + f2 = subsys->error(); + + //Take a step of alpha3 = 2*alpha2 + alpha3 = alpha2*2; + x = x0 + alpha3 * xdir; + subsys->setParams(x); + f3 = subsys->error(); + + //Now reduce or lengthen alpha2 and alpha3 until the minimum is + //Bracketed by the triplet f1>f2 f1 || f2 > f3) { + if (f2 > f1) { + //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1 + //Effectively both are shortened by a factor of two. + alpha3 = alpha2; + f3 = f2; + alpha2 = alpha2 / 2; + x = x0 + alpha2 * xdir; + subsys->setParams(x); + f2 = subsys->error(); + } + else if (f2 > f3) { + if (alpha3 >= alphaMax) + break; + //If f2 is greater than f3 then we increase alpha2 and alpha3 away from f1 + //Effectively both are lengthened by a factor of two. + alpha2 = alpha3; + f2 = f3; + alpha3 = alpha3 * 2; + x = x0 + alpha3 * xdir; + subsys->setParams(x); + f3 = subsys->error(); + } + } + //Get the alpha for the minimum f of the quadratic approximation + alphaStar = alpha2 + ((alpha2-alpha1)*(f1-f3))/(3*(f1-2*f2+f3)); + + //Guarantee that the new alphaStar is within the bracket + if (alphaStar >= alpha3 || alphaStar <= alpha1) + alphaStar = alpha2; + + if (alphaStar > alphaMax) + alphaStar = alphaMax; + + if (alphaStar != alphaStar) + alphaStar = 0.; + + //Take a final step to alphaStar + x = x0 + alphaStar * xdir; + subsys->setParams(x); + + return alphaStar; +}*/ + + +void free(VEC_pD &doublevec) +{ + for (VEC_pD::iterator it = doublevec.begin(); + it != doublevec.end(); ++it) + if (*it) delete *it; + doublevec.clear(); +} + +void free(std::vector &constrvec) +{ + for (std::vector::iterator constr=constrvec.begin(); + constr != constrvec.end(); ++constr) { + if (*constr) { + switch ((*constr)->getTypeId()) { + + case None: + default: + delete *constr; + } + } + } + constrvec.clear(); +} + +void free(std::vector &subsysvec) +{ + for (std::vector::iterator it=subsysvec.begin(); + it != subsysvec.end(); ++it) + if (*it) delete *it; +} + +} //namespace GCS diff --git a/src/Mod/Assembly/App/gcs3d/GCS.h b/src/Mod/Assembly/App/gcs3d/GCS.h new file mode 100644 index 000000000000..c4a2ac671d13 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/GCS.h @@ -0,0 +1,122 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 FREEGCS_GCS_H +#define FREEGCS_GCS_H + +#include "SubSystem.h" + + +namespace GCS { + + + +/////////////////////////////////////// +// Solver +/////////////////////////////////////// + +enum SolveStatus { + Success = 0, // Found a solution zeroing the error function + Converged = 1, // Found a solution minimizing the error function + Failed = 2 // Failed to find any solution +}; + +enum Algorithm { + BFGS = 0, + LevenbergMarquardt = 1, + DogLeg = 2, + HOPS, +}; + +class System { + // This is the main class. It holds all constraints and information + // about partitioning into subsystems and solution strategies +private: + std::vector clist; + + std::map c2p; // constraint to parameter adjacency list + std::map > p2c; // parameter to constraint adjacency list + + SubSystem *subsys0; // has the highest priority, always used as the primary subsystem + SubSystem *subsys1; // normally used as secondary subsystem, it is considered primary only if subsys0 is missing + SubSystem *subsys2; // has the lowest priority, always used as secondary system + void clearSubSystems(); + + MAP_pD_D reference; + void clearReference(); + void resetToReference(); + + MAP_pD_pD reductionmap; // for simplification of equality constraints + + bool init; + + int solve_BFGS ( SubSystem *subsys, bool isFine ); + int solve_LM ( SubSystem *subsys ); + int solve_DL ( SubSystem *subsys ); + int solve_EX ( SubSystem *subsys ); +public: + System(); + System ( std::vector clist_ ); + ~System(); + + void clear(); + void clearByTag ( int tagId ); + + int addConstraint ( Constraint *constr ); + void removeConstraint ( Constraint *constr ); + + void initSolution ( VEC_pD ¶ms ); + + int solve ( bool isFine=true, Algorithm alg=DogLeg ); + int solve ( VEC_pD ¶ms, bool isFine=true, Algorithm alg=DogLeg ); + int solve ( SubSystem *subsys, bool isFine=true, Algorithm alg=DogLeg ); + int solve ( SubSystem *subsysA, SubSystem *subsysB, bool isFine=true ); + + void getSubSystems ( std::vector &subsysvec ); + void applySolution(); + + bool isInit() const { + return init; + } + + int diagnose ( VEC_pD ¶ms, VEC_I &conflicting ); +}; + +/////////////////////////////////////// +// BFGS Solver parameters +/////////////////////////////////////// +#define XconvergenceRough 1e-8 +#define XconvergenceFine 1e-10 +#define smallF 1e-20 +#define MaxIterations 100 //Note that the total number of iterations allowed is MaxIterations *xLength + +/////////////////////////////////////// +// Helper elements +/////////////////////////////////////// + +void free ( VEC_pD &doublevec ); +void free ( std::vector &constrvec ); +void free ( std::vector &subsysvec ); + +} //namespace GCS + +#endif // FREEGCS_GCS_H diff --git a/src/Mod/Assembly/App/gcs3d/Geo.h b/src/Mod/Assembly/App/gcs3d/Geo.h new file mode 100644 index 000000000000..c7629b51f001 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Geo.h @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 FREEGCS_GEO_H +#define FREEGCS_GEO_H + +namespace GCS +{ + + class Displacement { + + public: + Displacement(){x = 0; y = 0; z = 0;} + double *x, *y, *z; + }; + + class Point { + + public: + Point() { x=y=z=0;} + double x,y,z; + }; + + class Normal : public Point { + + public: + Normal() {}; + }; + + class Quaternion { + + public: + Quaternion() {a = b = c = d = 0;}; + double *a, *b, *c, *d; + }; + + class Solid { + + public: + Solid() {}; + Quaternion q; + Displacement d; + Normal n; + Point p; + }; +} //namespace GCS + +#endif // FREEGCS_GEO_H diff --git a/src/Mod/Assembly/App/gcs3d/InputParser.cpp b/src/Mod/Assembly/App/gcs3d/InputParser.cpp new file mode 100644 index 000000000000..43f47f59ec00 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/InputParser.cpp @@ -0,0 +1,359 @@ +#include +#include + +#include "InputParser.h" + +#include + + + +InputParser::InputParser() +{ + try { + xercesc::XMLPlatformUtils::Initialize(); // Initialize Xerces infrastructure + } + catch (xercesc::XMLException& e) { + char* message = xercesc::XMLString::transcode(e.getMessage()); + std::cout << "XML toolkit initialization error: " << message << std::endl; + xercesc::XMLString::release(&message); + } + + // Tags and attributes used in XML file. + // Can't call transcode till after Xerces Initialize() + TAG_points = xercesc::XMLString::transcode("points"); + TAG_point = xercesc::XMLString::transcode("point"); + TAG_constraints= xercesc::XMLString::transcode("constraints"); + TAG_constraint = xercesc::XMLString::transcode("constraint"); + ATTR_id = xercesc::XMLString::transcode("id"); + ATTR_x = xercesc::XMLString::transcode("x"); + ATTR_y = xercesc::XMLString::transcode("y"); + ATTR_z = xercesc::XMLString::transcode("z"); + ATTR_point = xercesc::XMLString::transcode("point"); + ATTR_kind = xercesc::XMLString::transcode("kind"); + ATTR_distance = xercesc::XMLString::transcode("distance"); + + TAG_GCS_AS = xercesc::XMLString::transcode("GCS_AS"); + TAG_quaternion = xercesc::XMLString::transcode("quaternion"); + TAG_quaternions = xercesc::XMLString::transcode("quaternions"); + TAG_normal = xercesc::XMLString::transcode("normal"); + TAG_normals = xercesc::XMLString::transcode("normals"); + TAG_displacement = xercesc::XMLString::transcode("displacement"); + TAG_displacements = xercesc::XMLString::transcode("displacements"); + TAG_solid = xercesc::XMLString::transcode("solid"); + TAG_solids = xercesc::XMLString::transcode("solids"); + KIND_Parallel_AS = xercesc::XMLString::transcode("Parallel_AS"); + KIND_Distance_AS = xercesc::XMLString::transcode("Distance_AS"); + ATTR_a = xercesc::XMLString::transcode("a"); + ATTR_b= xercesc::XMLString::transcode("b"); + ATTR_c = xercesc::XMLString::transcode("c"); + ATTR_d = xercesc::XMLString::transcode("d"); + ATTR_type = xercesc::XMLString::transcode("type"); + ATTR_quaternion = xercesc::XMLString::transcode("quaternion"); + ATTR_normal = xercesc::XMLString::transcode("normal"); + ATTR_displacement = xercesc::XMLString::transcode("displacement"); + ATTR_solid1 = xercesc::XMLString::transcode("solid1"); + ATTR_solid2 = xercesc::XMLString::transcode("solid2"); + + + m_InputFileParser = new xercesc::XercesDOMParser; +} + +InputParser::~InputParser() +{ + // Free memory + delete m_InputFileParser; +} + +bool InputParser::readInputFileAS(std::string &fileName, + std::vector &variables, + std::vector ¶meters, + std::vector &points, + std::vector &norms, + std::vector &disps, + std::vector &quats, + std::vector &solids, + std::vector &constraints) +{ + int pointsOffset = points.size(); + int normsOffset = norms.size(); + int dispsOffset = disps.size(); + int quatsOffset = quats.size(); + int solidsOffset = solids.size(); + + // Test to see if the file is ok. + struct stat fileStatus; + if (stat(fileName.c_str(), &fileStatus) != 0) { + std::cout << "Error reading the file " << fileName << std::endl; + return false; + } + + // Configure DOM parser. + m_InputFileParser->setValidationScheme(xercesc::XercesDOMParser::Val_Never); + m_InputFileParser->setDoNamespaces(false); + m_InputFileParser->setDoSchema(false); + m_InputFileParser->setLoadExternalDTD(false); + + try { + m_InputFileParser->parse(fileName.c_str()); + + // no need to free this pointer - owned by the parent parser object + xercesc::DOMDocument* xmlDoc = m_InputFileParser->getDocument(); + + // Get the top-level element: Name is "GCS_3D". No attributes for "GCS_3D" + xercesc::DOMElement* elementRoot = xmlDoc->getDocumentElement(); + if (!elementRoot) { + std::cout << "empty XML document" << std::endl; + return false; + } + else if (!xercesc::XMLString::equals(elementRoot->getTagName(), TAG_GCS_AS)) { + std::cout << "wrong root element in the XML file" << std::endl; + return false; + } + + // Parse XML file for tags of interest: "ApplicationSettings" + // Look one level nested within "root". (child of root) + xercesc::DOMNodeList* children = elementRoot->getChildNodes(); + const XMLSize_t nodeCount = children->getLength(); + + // Points + xercesc::DOMNodeList* pointsNodes = elementRoot->getElementsByTagName(TAG_points); + const XMLSize_t pointsCount = pointsNodes->getLength(); + + for (XMLSize_t i = 0; i < pointsCount; ++i) { + xercesc::DOMNode* pointsNode = pointsNodes->item(i); + xercesc::DOMElement* pointsElement = dynamic_cast(pointsNode); + + xercesc::DOMNodeList* pointNodes = pointsElement->getElementsByTagName(TAG_point); + const XMLSize_t pointCount = pointNodes->getLength(); + + for (XMLSize_t j = 0; j < pointCount; ++j) { + xercesc::DOMNode* pointNode = pointNodes->item(j); + xercesc::DOMElement* pointElement = dynamic_cast(pointNode); + + int id = getIntAttr(pointElement, ATTR_id); + double x = getDoubleAttr(pointElement, ATTR_x); + double y = getDoubleAttr(pointElement, ATTR_y); + double z = getDoubleAttr(pointElement, ATTR_z); + + if (id + pointsOffset > points.size()) + points.resize(id + pointsOffset); + + GCS::Point p; + p.x = x; + p.y = y; + p.z = z; + points[id + pointsOffset -1] = p; + } + } + + // normals + xercesc::DOMNodeList* normsNodes = elementRoot->getElementsByTagName(TAG_normals); + const XMLSize_t normsCount = normsNodes->getLength(); + + for (XMLSize_t i = 0; i < normsCount; ++i) { + xercesc::DOMNode* normsNode = normsNodes->item(i); + xercesc::DOMElement* normsElement = dynamic_cast(normsNode); + + xercesc::DOMNodeList* lineNodes = normsElement->getElementsByTagName(TAG_normal); + const XMLSize_t lineCount = lineNodes->getLength(); + + for (XMLSize_t j = 0; j < lineCount; ++j) { + xercesc::DOMNode* normNode = lineNodes->item(j); + xercesc::DOMElement* normElement = dynamic_cast(normNode); + + int id = getIntAttr(normElement, ATTR_id); + double x = getDoubleAttr(normElement, ATTR_x); + double y = getDoubleAttr(normElement, ATTR_y); + double z = getDoubleAttr(normElement, ATTR_z); + + if (id + normsOffset > norms.size()) + norms.resize(id + normsOffset); + + GCS::Normal p; + p.x = x; + p.y = y; + p.z = z; + norms[id + normsOffset -1] = p; + } + } + + // Displacements + xercesc::DOMNodeList* dispsNodes = elementRoot->getElementsByTagName(TAG_displacements); + const XMLSize_t dispsCount = dispsNodes->getLength(); + + for (XMLSize_t i = 0; i < dispsCount; ++i) { + xercesc::DOMNode* dispsNode = dispsNodes->item(i); + xercesc::DOMElement* dispsElement = dynamic_cast(dispsNode); + + xercesc::DOMNodeList* lineNodes = dispsElement->getElementsByTagName(TAG_displacement); + const XMLSize_t lineCount = lineNodes->getLength(); + + for (XMLSize_t j = 0; j < lineCount; ++j) { + xercesc::DOMNode* dispNode = lineNodes->item(j); + xercesc::DOMElement* dispElement = dynamic_cast(dispNode); + + int id = getIntAttr(dispElement, ATTR_id); + double x = getDoubleAttr(dispElement, ATTR_x); + double y = getDoubleAttr(dispElement, ATTR_y); + double z = getDoubleAttr(dispElement, ATTR_z); + + if (id + dispsOffset > disps.size()) + disps.resize(id + dispsOffset); + + // Memory allocation!! + int varStartIndex = variables.size(); + variables.push_back(new double(x)); + variables.push_back(new double(y)); + variables.push_back(new double(z)); + + GCS::Displacement p; + p.x = variables[varStartIndex+0]; + p.y = variables[varStartIndex+1]; + p.z = variables[varStartIndex+2]; + disps[id + dispsOffset -1] = p; + } + } + + // Quaternions + xercesc::DOMNodeList* quatsNodes = elementRoot->getElementsByTagName(TAG_quaternions); + const XMLSize_t quatCount = quatsNodes->getLength(); + + for (XMLSize_t i = 0; i < quatCount; ++i) { + xercesc::DOMNode* quatsNode = quatsNodes->item(i); + xercesc::DOMElement* quatsElement = dynamic_cast(quatsNode); + + xercesc::DOMNodeList* quatNodes = quatsElement->getElementsByTagName(TAG_quaternion); + const XMLSize_t quatCount = quatNodes->getLength(); + + for (XMLSize_t j = 0; j < quatCount; ++j) { + xercesc::DOMNode* quatNode = quatNodes->item(j); + xercesc::DOMElement* quatElement = dynamic_cast(quatNode); + + int id = getIntAttr(quatElement, ATTR_id); + double a = getDoubleAttr(quatElement, ATTR_a); + double b = getDoubleAttr(quatElement, ATTR_b); + double c = getDoubleAttr(quatElement, ATTR_c); + double d = getDoubleAttr(quatElement, ATTR_d); + + if (id + quatsOffset > quats.size()) + quats.resize(id + quatsOffset); + + GCS::Quaternion q; + // Memory allocation!! + int varStartIndex = variables.size(); + variables.push_back(new double(a)); + variables.push_back(new double(b)); + variables.push_back(new double(c)); + variables.push_back(new double(d)); + + q.a = variables[varStartIndex+0]; + q.b = variables[varStartIndex+1]; + q.c = variables[varStartIndex+2]; + q.d = variables[varStartIndex+3]; + quats[id + quatsOffset -1] = q; + } + } + + // Solids + xercesc::DOMNodeList* solidsNodes = elementRoot->getElementsByTagName(TAG_solids); + const XMLSize_t solidCount = solidsNodes->getLength(); + + for (XMLSize_t i = 0; i < solidCount; ++i) { + xercesc::DOMNode* solidsNode = solidsNodes->item(i); + xercesc::DOMElement* solidsElement = dynamic_cast(solidsNode); + + xercesc::DOMNodeList* solidNodes = solidsElement->getElementsByTagName(TAG_solid); + const XMLSize_t solidCount = solidNodes->getLength(); + + for (XMLSize_t j = 0; j < solidCount; ++j) { + xercesc::DOMNode* solidNode = solidNodes->item(j); + xercesc::DOMElement* solidElement = dynamic_cast(solidNode); + + int id = getIntAttr(solidElement, ATTR_id); + int p = getIntAttr(solidElement, ATTR_point); + int n = getIntAttr(solidElement, ATTR_normal); + int d = getIntAttr(solidElement, ATTR_displacement); + int q = getIntAttr(solidElement, ATTR_quaternion); + + GCS::Solid s; + s.p = points[p-1]; + s.n = norms[n-1]; + s.d = disps[d-1]; + s.q = quats[q-1]; + + solids.push_back(s); + } + } + + + + // Constraints + xercesc::DOMNodeList* constraintsNodes = elementRoot->getElementsByTagName(TAG_constraints); + const XMLSize_t constraintsCount = constraintsNodes->getLength(); + + for (XMLSize_t i = 0; i < constraintsCount; ++i) { + xercesc::DOMNode* constraintsNode = constraintsNodes->item(i); + xercesc::DOMElement* constraintsElement = dynamic_cast(constraintsNode); + + xercesc::DOMNodeList* constraintNodes = constraintsElement->getElementsByTagName(TAG_constraint); + const XMLSize_t constraintCount = constraintNodes->getLength(); + + for (XMLSize_t j = 0; j < constraintCount; ++j) { + xercesc::DOMNode* constraintNode = constraintNodes->item(j); + xercesc::DOMElement* constraintElement = dynamic_cast(constraintNode); + + int id = getIntAttr(constraintElement, ATTR_id); + + const XMLCh* xmlch_kind = constraintElement->getAttribute(ATTR_kind); + + //PlaneParallel Assembly + if (xercesc::XMLString::equals(xmlch_kind, KIND_Parallel_AS)) { + int s1 = getIntAttr(constraintElement, ATTR_solid1); + int s2 = getIntAttr(constraintElement, ATTR_solid2); + int t = getIntAttr(constraintElement, ATTR_type); + + int paramStartIndex = parameters.size(); + parameters.push_back(new double(t)); + + GCS::Constraint *constr + = new GCS::ConstraintParralelFaceAS( solids[s1-1], solids[s2-1], + (GCS::ParallelType*) parameters[paramStartIndex] ); + constraints.push_back(constr); + } + //Distance Assembly + if (xercesc::XMLString::equals(xmlch_kind, KIND_Distance_AS)) { + int s1 = getIntAttr(constraintElement, ATTR_solid1); + int s2 = getIntAttr(constraintElement, ATTR_solid2); + double t = getDoubleAttr(constraintElement, ATTR_distance); + + int paramStartIndex = parameters.size(); + parameters.push_back(new double(t)); + + GCS::Constraint *constr + = new GCS::ConstraintFaceDistanceAS( solids[s1-1], solids[s2-1], parameters[paramStartIndex] ); + constraints.push_back(constr); + } + } + } + return true; + } + catch (xercesc::XMLException& e) { + char* message = xercesc::XMLString::transcode(e.getMessage()); + std::cout << "Error parsing file: " << message << std::endl; + xercesc::XMLString::release(&message); + } +} + +int InputParser::getIntAttr(xercesc::DOMElement* element, XMLCh* attr) +{ + const XMLCh* xmlch_val = element->getAttribute(attr); + return xercesc::XMLString::parseInt(xmlch_val); +} + +double InputParser::getDoubleAttr(xercesc::DOMElement* element, XMLCh* attr) +{ + const XMLCh* xmlch_val = element->getAttribute(attr); + xercesc::XMLDouble xmldouble_val(xmlch_val); + return xmldouble_val.getValue(); +} + diff --git a/src/Mod/Assembly/App/gcs3d/InputParser.h b/src/Mod/Assembly/App/gcs3d/InputParser.h new file mode 100644 index 000000000000..e6f71b1d57d9 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/InputParser.h @@ -0,0 +1,60 @@ + +#include +#include + +#include "GCS.h" + +class InputParser +{ +public: + InputParser(); + ~InputParser(); + + bool readInputFileAS(std::string &fileName, + std::vector &variables, + std::vector ¶meters, + std::vector &points, + std::vector &normals, + std::vector &displacements, + std::vector &quaternions, + std::vector &solids, + std::vector &constraints); + + int getIntAttr(xercesc::DOMElement* element, XMLCh* attr); + double getDoubleAttr(xercesc::DOMElement* element, XMLCh* attr); +private: + xercesc::XercesDOMParser *m_InputFileParser; + + XMLCh* TAG_points; + XMLCh* TAG_constraints; + XMLCh* TAG_point; + XMLCh* TAG_constraint; + XMLCh* ATTR_id; + XMLCh* ATTR_x; + XMLCh* ATTR_y; + XMLCh* ATTR_z; + XMLCh* ATTR_point; + XMLCh* ATTR_kind; + XMLCh* ATTR_distance; + XMLCh* TAG_GCS_AS; + XMLCh* TAG_quaternions; + XMLCh* TAG_quaternion; + XMLCh* TAG_normals; + XMLCh* TAG_normal; + XMLCh* TAG_displacements; + XMLCh* TAG_displacement; + XMLCh* TAG_solids; + XMLCh* TAG_solid; + XMLCh* KIND_Parallel_AS; + XMLCh* KIND_Distance_AS; + XMLCh* ATTR_a; + XMLCh* ATTR_b; + XMLCh* ATTR_c; + XMLCh* ATTR_d; + XMLCh* ATTR_quaternion; + XMLCh* ATTR_type; + XMLCh* ATTR_normal; + XMLCh* ATTR_displacement; + XMLCh* ATTR_solid1; + XMLCh* ATTR_solid2; +}; diff --git a/src/Mod/Assembly/App/gcs3d/SubSystem.cpp b/src/Mod/Assembly/App/gcs3d/SubSystem.cpp new file mode 100644 index 000000000000..e6bb8321231a --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/SubSystem.cpp @@ -0,0 +1,351 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 +#include +#include "SubSystem.h" + +namespace GCS +{ + +// SubSystem +SubSystem::SubSystem(std::vector &clist_, VEC_pD ¶ms) +: clist(clist_) +{ + MAP_pD_pD dummymap; + initialize(params, dummymap); +} + +SubSystem::SubSystem(std::vector &clist_, VEC_pD ¶ms, + MAP_pD_pD &reductionmap) +: clist(clist_) +{ + initialize(params, reductionmap); +} + +SubSystem::~SubSystem() +{ +} + +void SubSystem::initialize(VEC_pD ¶ms, MAP_pD_pD &reductionmap) +{ + csize = clist.size(); + + // tmpplist will contain the subset of parameters from params that are + // relevant for the constraints listed in clist + VEC_pD tmpplist; + { + SET_pD s1(params.begin(), params.end()); + SET_pD s2; + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) { + (*constr)->revertParams(); // ensure that the constraint points to the original parameters + VEC_pD constr_params = (*constr)->params(); + s2.insert(constr_params.begin(), constr_params.end()); + } + std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), + std::back_inserter(tmpplist) ); + } + + plist.clear(); + MAP_pD_I rindex; + if (reductionmap.size() > 0) { + int i=0; + MAP_pD_I pindex; + for (VEC_pD::const_iterator itt=tmpplist.begin(); + itt != tmpplist.end(); itt++) { + MAP_pD_pD::const_iterator itr = reductionmap.find(*itt); + if (itr != reductionmap.end()) { + MAP_pD_I::const_iterator itp = pindex.find(itr->second); + if (itp == pindex.end()) { // the reduction target is not in plist yet, so add it now + plist.push_back(itr->second); + rindex[itr->first] = i; + pindex[itr->second] = i; + i++; + } + else // the reduction target is already in plist, just inform rindex + rindex[itr->first] = itp->second; + } + else if (pindex.find(*itt) == pindex.end()) { // not in plist yet, so add it now + plist.push_back(*itt); + pindex[*itt] = i; + i++; + } + } + } + else + plist = tmpplist; + + psize = plist.size(); + pvals.resize(psize); + pmap.clear(); + for (int j=0; j < psize; j++) { + pmap[plist[j]] = &pvals[j]; + pvals[j] = *plist[j]; + } + for (MAP_pD_I::const_iterator itr=rindex.begin(); itr != rindex.end(); ++itr) + pmap[itr->first] = &pvals[itr->second]; + + c2p.clear(); + p2c.clear(); + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) { + (*constr)->revertParams(); // ensure that the constraint points to the original parameters + VEC_pD constr_params_orig = (*constr)->params(); + SET_pD constr_params; + for (VEC_pD::const_iterator p=constr_params_orig.begin(); + p != constr_params_orig.end(); ++p) { + MAP_pD_pD::const_iterator pmapfind = pmap.find(*p); + if (pmapfind != pmap.end()) + constr_params.insert(pmapfind->second); + } + for (SET_pD::const_iterator p=constr_params.begin(); + p != constr_params.end(); ++p) { +// jacobi.set(*constr, *p, 0.); + c2p[*constr].push_back(*p); + p2c[*p].push_back(*constr); + } +// (*constr)->redirectParams(pmap); // redirect parameters to pvec + } +} + +void SubSystem::redirectParams() +{ + // copying values to pvals + for (MAP_pD_pD::const_iterator p=pmap.begin(); + p != pmap.end(); ++p) + *(p->second) = *(p->first); + + // redirect constraints to point to pvals + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) { + (*constr)->revertParams(); // this line will normally not be necessary + (*constr)->redirectParams(pmap); + } +} + +void SubSystem::revertParams() +{ + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) + (*constr)->revertParams(); +} + +void SubSystem::getParamMap(MAP_pD_pD &pmapOut) +{ + pmapOut = pmap; +} + +void SubSystem::getParamList(VEC_pD &plistOut) +{ + plistOut = plist; +} + +void SubSystem::getParams(VEC_pD ¶ms, Eigen::VectorXd &xOut) +{ + if (xOut.size() != int(params.size())) + xOut.setZero(params.size()); + + for (int j=0; j < int(params.size()); j++) { + MAP_pD_pD::const_iterator + pmapfind = pmap.find(params[j]); + if (pmapfind != pmap.end()) + xOut[j] = *(pmapfind->second); + } +} + +void SubSystem::getParams(Eigen::VectorXd &xOut) +{ + if (xOut.size() != psize) + xOut.setZero(psize); + + for (int i=0; i < psize; i++) + xOut[i] = pvals[i]; +} + +void SubSystem::setParams(VEC_pD ¶ms, Eigen::VectorXd &xIn) +{ + assert(xIn.size() == int(params.size())); + for (int j=0; j < int(params.size()); j++) { + MAP_pD_pD::const_iterator + pmapfind = pmap.find(params[j]); + if (pmapfind != pmap.end()) + *(pmapfind->second) = xIn[j]; + } +} + +void SubSystem::setParams(Eigen::VectorXd &xIn) +{ + assert(xIn.size() == psize); + for (int i=0; i < psize; i++) + pvals[i] = xIn[i]; +} + +double SubSystem::error() +{ + double err = 0.; + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr) { + double tmp = (*constr)->error(); + err += tmp*tmp; + } + err *= 0.5; + return err; +} + +void SubSystem::calcResidual(Eigen::VectorXd &r) +{ + assert(r.size() == csize); + + int i=0; + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr, i++) { + r[i] = (*constr)->error(); + } +} + +void SubSystem::calcResidual(Eigen::VectorXd &r, double &err) +{ + assert(r.size() == csize); + + int i=0; + err = 0.; + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr, i++) { + r[i] = (*constr)->error(); + err += r[i]*r[i]; + } + err *= 0.5; +} + +/* +void SubSystem::calcJacobi() +{ + assert(grad.size() != xsize); + + for (MAP_pD_pD::const_iterator param=pmap.begin(); + param != pmap.end(); ++param) { + // assert(p2c.find(param->second) != p2c.end()); + std::vector constrs=p2c[param->second]; + for (std::vector::const_iterator constr = constrs.begin(); + constr != constrs.end(); ++constr) + jacobi.set(*constr,param->second,(*constr)->grad(param->second)); + } +} +*/ + +void SubSystem::calcJacobi(VEC_pD ¶ms, Eigen::MatrixXd &jacobi) +{ + jacobi.setZero(csize, params.size()); + for (int j=0; j < int(params.size()); j++) { + MAP_pD_pD::const_iterator + pmapfind = pmap.find(params[j]); + if (pmapfind != pmap.end()) + for (int i=0; i < csize; i++) + jacobi(i,j) = clist[i]->grad(pmapfind->second); + } +} + +void SubSystem::calcJacobi(Eigen::MatrixXd &jacobi) +{ + calcJacobi(plist, jacobi); +} + +void SubSystem::calcGrad(VEC_pD ¶ms, Eigen::VectorXd &grad) +{ + assert(grad.size() == int(params.size())); + + grad.setZero(); + for (int j=0; j < int(params.size()); j++) { + MAP_pD_pD::const_iterator + pmapfind = pmap.find(params[j]); + if (pmapfind != pmap.end()) { + // assert(p2c.find(pmapfind->second) != p2c.end()); + std::vector constrs=p2c[pmapfind->second]; + for (std::vector::const_iterator constr = constrs.begin(); + constr != constrs.end(); ++constr) + grad[j] += (*constr)->error() * (*constr)->grad(pmapfind->second); + } + } +} + +void SubSystem::calcGrad(Eigen::VectorXd &grad) +{ + calcGrad(plist, grad); +} + +double SubSystem::maxStep(VEC_pD ¶ms, Eigen::VectorXd &xdir) +{ + assert(xdir.size() == int(params.size())); + + MAP_pD_D dir; + for (int j=0; j < int(params.size()); j++) { + MAP_pD_pD::const_iterator pmapfind = pmap.find(params[j]); + if (pmapfind != pmap.end()) + dir[pmapfind->second] = xdir[j]; + } + + double alpha=1e10; + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) + alpha = (*constr)->maxStep(dir, alpha); + + return alpha; +} + +double SubSystem::maxStep(Eigen::VectorXd &xdir) +{ + return maxStep(plist, xdir); +} + +void SubSystem::applySolution() +{ + for (MAP_pD_pD::const_iterator it=pmap.begin(); + it != pmap.end(); ++it) + *(it->first) = *(it->second); +} + +void SubSystem::analyse(Eigen::MatrixXd &J, Eigen::MatrixXd &ker, Eigen::MatrixXd &img) +{ +} + +void SubSystem::report() +{ +} + +void SubSystem::printResidual() +{ + Eigen::VectorXd r(csize); + int i=0; + double err = 0.; + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr, i++) { + r[i] = (*constr)->error(); + err += r[i]*r[i]; + } + err *= 0.5; + std::cout << "Residual r = " << r.transpose() << std::endl; + std::cout << "Residual err = " << err << std::endl; +} + + +} //namespace GCS diff --git a/src/Mod/Assembly/App/gcs3d/SubSystem.h b/src/Mod/Assembly/App/gcs3d/SubSystem.h new file mode 100644 index 000000000000..1e313e35ea56 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/SubSystem.h @@ -0,0 +1,89 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 FREEGCS_SUBSYSTEM_H +#define FREEGCS_SUBSYSTEM_H + +#undef min +#undef max + +#include +#include "Constraints.h" + +namespace GCS +{ + + class SubSystem + { + private: + int psize, csize; + std::vector clist; + VEC_pD plist; // pointers to the original parameters + MAP_pD_pD pmap; // redirection map from the original parameters to pvals + VEC_D pvals; // current variables vector (psize) +// JacobianMatrix jacobi; // jacobi matrix of the residuals + std::map c2p; // constraint to parameter adjacency list + std::map > p2c; // parameter to constraint adjacency list + void initialize(VEC_pD ¶ms, MAP_pD_pD &reductionmap); // called by the constructors + public: + SubSystem(std::vector &clist_, VEC_pD ¶ms); + SubSystem(std::vector &clist_, VEC_pD ¶ms, + MAP_pD_pD &reductionmap); + ~SubSystem(); + + int pSize() { return psize; }; + int cSize() { return csize; }; + + void redirectParams(); + void revertParams(); + + void getParamMap(MAP_pD_pD &pmapOut); + void getParamList(VEC_pD &plistOut); + + void getParams(VEC_pD ¶ms, Eigen::VectorXd &xOut); + void getParams(Eigen::VectorXd &xOut); + void setParams(VEC_pD ¶ms, Eigen::VectorXd &xIn); + void setParams(Eigen::VectorXd &xIn); + + double error(); + void calcResidual(Eigen::VectorXd &r); + void calcResidual(Eigen::VectorXd &r, double &err); + void calcJacobi(VEC_pD ¶ms, Eigen::MatrixXd &jacobi); + void calcJacobi(Eigen::MatrixXd &jacobi); + void calcGrad(VEC_pD ¶ms, Eigen::VectorXd &grad); + void calcGrad(Eigen::VectorXd &grad); + + double maxStep(VEC_pD ¶ms, Eigen::VectorXd &xdir); + double maxStep(Eigen::VectorXd &xdir); + + void applySolution(); + void analyse(Eigen::MatrixXd &J, Eigen::MatrixXd &ker, Eigen::MatrixXd &img); + void report(); + +void printResidual(); + }; + + double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir); + +} //namespace GCS + +#endif // FREEGCS_SUBSYSTEM_H diff --git a/src/Mod/Assembly/App/gcs3d/Util.h b/src/Mod/Assembly/App/gcs3d/Util.h new file mode 100644 index 000000000000..18eacf9ad6c6 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/Util.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 FREEGCS_UTIL_H +#define FREEGCS_UTIL_H + +#include +#include +#include + +namespace GCS +{ + typedef std::vector VEC_pD; + typedef std::vector VEC_D; + typedef std::vector VEC_I; + typedef std::map MAP_pD_pD; + typedef std::map MAP_pD_D; + typedef std::map MAP_pD_I; + typedef std::set SET_pD; + typedef std::set SET_I; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +} //namespace GCS + +#endif // FREEGCS_UTIL_H diff --git a/src/Mod/Assembly/App/gcs3d/main.cpp b/src/Mod/Assembly/App/gcs3d/main.cpp new file mode 100644 index 000000000000..a68ac1f22450 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/main.cpp @@ -0,0 +1,122 @@ +#include +#include + +#include "Geo.h" +#include "Constraints.h" +#include "InputParser.h" +#include "OutputWriter.h" + +#include + +using namespace std; +using namespace Eigen; + +Vector3d Place(GCS::Point p, GCS::Quaternion q, GCS::Displacement di) { + + double a=*q.a, b=*q.b, c=*q.c, d=*q.d; + double norm = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); + double x=a/norm, y=b/norm, z=c/norm, w=d/norm; + + Matrix3d rot; + rot(0,0) = 1-2*(pow(y,2)+pow(z,2)); + rot(0,1) = -2.0*w*z + 2.0*x*y; + rot(0,2) = 2.0*w*y + 2.0*x*z; + rot(1,0) = 2.0*w*z + 2.0*x*y; + rot(1,1) = 1-2*(pow(x,2)+pow(z,2)); + rot(1,2) = -2.0*w*x + 2.0*y*z; + rot(2,0) = -2.0*w*y + 2.0*x*z; + rot(2,1) = 2.0*w*x + 2.0*y*z; + rot(2,2) = 1-2*(pow(x,2)+pow(y,2)); + + Vector3d v(p.x, p.y, p.z); + Vector3d n = rot*v; + + if (di.x != NULL) { + n(0) += *di.x; + n(1) += *di.y; + n(2) += *di.z; + } + + return n; +} + +std::string Vec(Vector3d vec) { + + std::stringstream s; + s<<"Base.Vector(" << vec(0) << ", " << vec(1) << ", " << vec(2) <<")"; + return s.str(); +} + + +int main(int argc, char **argv) { + + if (argc<3) return 1; + + cout << endl << "loading file: " << argv[1]; + cout << endl << "generating output: " << argv[2] << endl << endl; + + vector variables; + vector parameters; + vector points; + vector norms; + vector disps; + vector quats; + vector solids; + vector constraints; + + string inputfile(argv[1]); + string outputfile(argv[2]); + + bool d2,d3; + + InputParser parser; + d3 = parser.readInputFileAS(inputfile, variables, parameters, points, norms, disps, quats, solids, constraints); + + cout << "Variables: " << variables.size() << endl << "parameters: " << parameters.size() << endl; + cout << "Points: " << points.size() << endl << "Normals: " << norms.size() << endl; + cout << "Displacements: " << disps.size() << endl; + cout << "Quaternions: " << quats.size() << endl; + cout << "Solids: " << solids.size() << endl; + cout << "Constraints: " << constraints.size() << endl; + + //init output writing + remove(outputfile.c_str()); + ofstream file; + file.open (outputfile.c_str()); + if (!file.is_open()) return 0; + //import all needed modules + file << "import Part" << endl << "from FreeCAD import Base" << endl << endl; + //open new document + file << "App.newDocument(\"solver\")" << endl << endl; + GCS::Displacement emd; + for (int i=0; i +#include + +using namespace Eigen; + +// minimizes ( 0.5 * x^T * H * x + g^T * x ) under the condition ( A*x + c = 0 ) +// it returns the solution in x, the row-space of A in Y, and the null space of A in Z +int qp_eq(MatrixXd &H, VectorXd &g, MatrixXd &A, VectorXd &c, + VectorXd &x, MatrixXd &Y, MatrixXd &Z) +{ + FullPivHouseholderQR qrAT(A.transpose()); + MatrixXd Q = qrAT.matrixQ (); + + size_t params_num = qrAT.rows(); + size_t constr_num = qrAT.cols(); + size_t rank = qrAT.rank(); + + if (rank != constr_num || constr_num > params_num) + return -1; + + // A^T = Q*R*P^T = Q1*R1*P^T + // Q = [Q1,Q2], R=[R1;0] + // Y = Q1 * inv(R^T) * P^T + // Z = Q2 + Y = qrAT.matrixQR().topRows(constr_num) + .triangularView() + .transpose() + .solve(Q.leftCols(rank)) + * qrAT.colsPermutation().transpose(); + if (params_num == rank) + x = - Y * c; + else { + Z = Q.rightCols(params_num-rank); + + MatrixXd ZTHZ = Z.transpose() * H * Z; + VectorXd rhs = Z.transpose() * (H * Y * c - g); + + VectorXd y = ZTHZ.colPivHouseholderQr().solve(rhs); + + x = - Y * c + Z * y; + } + + return 0; +} diff --git a/src/Mod/Assembly/App/gcs3d/qp_eq.h b/src/Mod/Assembly/App/gcs3d/qp_eq.h new file mode 100644 index 000000000000..f05ca6d52247 --- /dev/null +++ b/src/Mod/Assembly/App/gcs3d/qp_eq.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * + * * + * 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 + +int qp_eq(Eigen::MatrixXd &H, Eigen::VectorXd &g, Eigen::MatrixXd &A, Eigen::VectorXd &c, + Eigen::VectorXd &x, Eigen::MatrixXd &Y, Eigen::MatrixXd &Z); diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp new file mode 100644 index 000000000000..95e4992f8d03 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 "ViewProvider.h" +#include +//#include + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) + +ViewProviderItem::ViewProvider() +{ +} + +ViewProviderItem::~ViewProvider() +{ +} + +bool ViewProviderItem::doubleClicked(void) +{ + return true; +} + + diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h new file mode 100644 index 000000000000..0ebf8ad1173c --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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_ViewProvider_H +#define PARTGUI_ViewProvider_H + +#include + + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart +{ + PROPERTY_HEADER(PartGui::ViewProviderItem); + +public: + /// constructor + ViewProviderItem(); + /// destructor + virtual ~ViewProviderItem(); + + virtual bool doubleClicked(void); + +}; + + + +} // namespace AssemblyGui + + +#endif // PARTGUI_ViewProviderHole_H diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.cpp b/src/Mod/Assembly/Gui/ViewProviderPart.cpp new file mode 100644 index 000000000000..95e4992f8d03 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderPart.cpp @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 "ViewProvider.h" +#include +//#include + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) + +ViewProviderItem::ViewProvider() +{ +} + +ViewProviderItem::~ViewProvider() +{ +} + +bool ViewProviderItem::doubleClicked(void) +{ + return true; +} + + diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.h b/src/Mod/Assembly/Gui/ViewProviderPart.h new file mode 100644 index 000000000000..0ebf8ad1173c --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderPart.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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_ViewProvider_H +#define PARTGUI_ViewProvider_H + +#include + + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart +{ + PROPERTY_HEADER(PartGui::ViewProviderItem); + +public: + /// constructor + ViewProviderItem(); + /// destructor + virtual ~ViewProviderItem(); + + virtual bool doubleClicked(void); + +}; + + + +} // namespace AssemblyGui + + +#endif // PARTGUI_ViewProviderHole_H From f98a811bd163a0d007b1c23ef884bc481ce7f2a0 Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 19 Jan 2012 10:08:12 +0100 Subject: [PATCH 008/664] Add more objects for Assembly --- src/Mod/Assembly/App/CMakeLists.txt | 17 +++++++++++++++++ src/Mod/Assembly/App/Item.cpp | 3 +++ src/Mod/Assembly/App/Item.h | 11 +++++++++++ src/Mod/Assembly/App/ItemPart.h | 8 ++++---- src/Mod/Assembly/App/gcs3d/GCS.cpp | 1 + src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 9 +++++++++ src/Mod/Assembly/Gui/CMakeLists.txt | 4 ++++ src/Mod/Assembly/Gui/ViewProvider.cpp | 8 ++++---- src/Mod/Assembly/Gui/ViewProvider.h | 14 +++++++------- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 12 ++++++------ src/Mod/Assembly/Gui/ViewProviderAssembly.h | 16 ++++++++-------- src/Mod/Assembly/Gui/ViewProviderPart.cpp | 12 ++++++------ src/Mod/Assembly/Gui/ViewProviderPart.h | 16 ++++++++-------- 13 files changed, 88 insertions(+), 43 deletions(-) diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index a9e499a91248..6eaebbfdcc97 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -14,6 +14,8 @@ include_directories( ${ZLIB_INCLUDE_DIR} ${XercesC_INCLUDE_DIRS} ${ODE_INCLUDE_DIRS} + ${EIGEN3_INCLUDE_DIR} + ) set(Assembly_LIBS @@ -28,6 +30,20 @@ generate_from_xml(ItemAssemblyPy) generate_from_xml(ItemPartPy) generate_from_xml(ConstraintGroupPy) +SET(FreeGCS3D_SRCS + gcs3d/GCS.cpp + gcs3d/GCS.h + gcs3d/Util.h + gcs3d/Geo.h + gcs3d/Constraints.cpp + gcs3d/Constraints.h + gcs3d/SubSystem.cpp + gcs3d/SubSystem.h + gcs3d/qp_eq.cpp + gcs3d/qp_eq.h +) +SOURCE_GROUP("FreeGCS3D" FILES ${FreeGCS3D_SRCS}) + SET(Features_SRCS Item.cpp Item.h @@ -76,6 +92,7 @@ SET(Assembly_SRCS ${Features_SRCS} ${Python_SRCS} ${Module_SRCS} + ${FreeGCS3D_SRCS} ) diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index b43225ac999d..0a52687e88d8 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -43,6 +43,9 @@ Item::Item() ADD_PROPERTY(Uid,(0)); ADD_PROPERTY(Name,(0)); ADD_PROPERTY(Description,(0)); + + ADD_PROPERTY(Color,(1.0,1.0,1.0,1.0)); // set transparent -> not used + ADD_PROPERTY(Visibility,(true)); } short Item::mustExecute() const diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index a572526304c3..fde89873923c 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -50,6 +50,17 @@ class AssemblyExport Item : public Part::Feature App::PropertyString Description ; //@} + /** @name base properties of all Assembly Items */ + //@{ + /** Base color of the Item + If the transparency value is 1.0 + the color or the next hirachy is used + */ + App::PropertyColor Color; + /// Visibility + App::PropertyBool Visibility; + //@} + /** @name methods override feature */ //@{ /// recalculate the feature diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h index 80acb8303724..bc472a4737ff 100644 --- a/src/Mod/Assembly/App/ItemPart.h +++ b/src/Mod/Assembly/App/ItemPart.h @@ -45,10 +45,10 @@ class AssemblyExport ItemPart : public Assembly::Item /// recalculate the feature App::DocumentObjectExecReturn *execute(void); short mustExecute() const; - /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "ItemPartDesignGui::ViewProviderItemPart"; - //} + // returns the type name of the view provider + const char* getViewProviderName(void) const { + return "ItemPartDesignGui::ViewProviderItemPart"; + } //@} }; diff --git a/src/Mod/Assembly/App/gcs3d/GCS.cpp b/src/Mod/Assembly/App/gcs3d/GCS.cpp index 1a5fc76a0370..8f8592883a76 100644 --- a/src/Mod/Assembly/App/gcs3d/GCS.cpp +++ b/src/Mod/Assembly/App/gcs3d/GCS.cpp @@ -291,6 +291,7 @@ int System::solve(SubSystem *subsys, bool isFine, Algorithm alg) int System::solve_EX(SubSystem* subsys) { + return 0; } diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index 86d1bf70076a..95fbc16fe5e5 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -30,6 +30,11 @@ #include #include #include "Workbench.h" + +#include "ViewProvider.h" +#include "ViewProviderPart.h" +#include "ViewProviderAssembly.h" + //#include "resources/qrc_Assembly.cpp" // use a different name to CreateCommand() @@ -62,6 +67,10 @@ void AssemblyGuiExport initAssemblyGui() CreateAssemblyCommands(); AssemblyGui::Workbench::init(); + AssemblyGui::ViewProviderItem ::init(); + AssemblyGui::ViewProviderItemPart ::init(); + AssemblyGui::ViewProviderItemAssembly::init(); + // add resources and reloads the translators loadAssemblyResource(); } diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 6487b35f04c7..683333564203 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -31,6 +31,10 @@ qt4_add_resources(AssemblyGui_SRCS Resources/Assembly.qrc) SET(AssemblyGuiViewProvider_SRCS ViewProvider.cpp ViewProvider.h + ViewProviderPart.cpp + ViewProviderPart.h + ViewProviderAssembly.cpp + ViewProviderAssembly.h ) SOURCE_GROUP("ViewProvider" FILES ${AssemblyGuiViewProvider_SRCS}) diff --git a/src/Mod/Assembly/Gui/ViewProvider.cpp b/src/Mod/Assembly/Gui/ViewProvider.cpp index 8193335ab4ba..160f3daa39de 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.cpp +++ b/src/Mod/Assembly/Gui/ViewProvider.cpp @@ -32,17 +32,17 @@ using namespace AssemblyGui; -PROPERTY_SOURCE(AssemblyGui::ViewProvider,PartGui::ViewProviderPart) +PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) -ViewProvider::ViewProvider() +ViewProviderItem::ViewProviderItem() { } -ViewProvider::~ViewProvider() +ViewProviderItem::~ViewProviderItem() { } -bool ViewProvider::doubleClicked(void) +bool ViewProviderItem::doubleClicked(void) { return true; } diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h index 8f75eb8a430d..03fb5d42e279 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.h +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -21,23 +21,23 @@ ***************************************************************************/ -#ifndef PARTGUI_ViewProvider_H -#define PARTGUI_ViewProvider_H +#ifndef ASSEMBLYGUI_ViewProvider_H +#define ASSEMBLYGUI_ViewProvider_H #include namespace AssemblyGui { -class AssemblyGuiExport ViewProvider : public PartGui::ViewProviderPart +class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart { - PROPERTY_HEADER(PartGui::ViewProvider); + PROPERTY_HEADER(AssemblyGui::ViewProviderItem); public: /// constructor - ViewProvider(); + ViewProviderItem(); /// destructor - virtual ~ViewProvider(); + virtual ~ViewProviderItem(); virtual bool doubleClicked(void); @@ -48,4 +48,4 @@ class AssemblyGuiExport ViewProvider : public PartGui::ViewProviderPart } // namespace AssemblyGui -#endif // PARTGUI_ViewProviderHole_H +#endif // ASSEMBLYGUI_ViewProvider_H diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 95e4992f8d03..73eeefac9c5a 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -26,23 +26,23 @@ #ifndef _PreComp_ #endif -#include "ViewProvider.h" -#include +#include "ViewProviderAssembly.h" +//#include //#include using namespace AssemblyGui; -PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) +PROPERTY_SOURCE(AssemblyGui::ViewProviderItemAssembly,AssemblyGui::ViewProviderItem) -ViewProviderItem::ViewProvider() +ViewProviderItemAssembly::ViewProviderItemAssembly() { } -ViewProviderItem::~ViewProvider() +ViewProviderItemAssembly::~ViewProviderItemAssembly() { } -bool ViewProviderItem::doubleClicked(void) +bool ViewProviderItemAssembly::doubleClicked(void) { return true; } diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index 0ebf8ad1173c..3fff1a9bacfb 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -21,23 +21,23 @@ ***************************************************************************/ -#ifndef PARTGUI_ViewProvider_H -#define PARTGUI_ViewProvider_H +#ifndef ASSEMBLYGUI_ViewProviderAssembly_H +#define ASSEMBLYGUI_ViewProviderAssembly_H -#include +#include "ViewProvider.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart +class AssemblyGuiExport ViewProviderItemAssembly : public AssemblyGui::ViewProviderItem { - PROPERTY_HEADER(PartGui::ViewProviderItem); + PROPERTY_HEADER(PartGui::ViewProviderItemAssembly); public: /// constructor - ViewProviderItem(); + ViewProviderItemAssembly(); /// destructor - virtual ~ViewProviderItem(); + virtual ~ViewProviderItemAssembly(); virtual bool doubleClicked(void); @@ -48,4 +48,4 @@ class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart } // namespace AssemblyGui -#endif // PARTGUI_ViewProviderHole_H +#endif // ASSEMBLYGUI_ViewProviderAssembly_H diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.cpp b/src/Mod/Assembly/Gui/ViewProviderPart.cpp index 95e4992f8d03..73988a966cf9 100644 --- a/src/Mod/Assembly/Gui/ViewProviderPart.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderPart.cpp @@ -26,23 +26,23 @@ #ifndef _PreComp_ #endif -#include "ViewProvider.h" -#include +#include "ViewProviderPart.h" +//#include //#include using namespace AssemblyGui; -PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) +PROPERTY_SOURCE(AssemblyGui::ViewProviderItemPart,AssemblyGui::ViewProviderItem) -ViewProviderItem::ViewProvider() +ViewProviderItemPart::ViewProviderItemPart() { } -ViewProviderItem::~ViewProvider() +ViewProviderItemPart::~ViewProviderItemPart() { } -bool ViewProviderItem::doubleClicked(void) +bool ViewProviderItemPart::doubleClicked(void) { return true; } diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.h b/src/Mod/Assembly/Gui/ViewProviderPart.h index 0ebf8ad1173c..8f60075b4d1f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderPart.h +++ b/src/Mod/Assembly/Gui/ViewProviderPart.h @@ -21,23 +21,23 @@ ***************************************************************************/ -#ifndef PARTGUI_ViewProvider_H -#define PARTGUI_ViewProvider_H +#ifndef ASSEMBLYGUI_ViewProviderPart_H +#define ASSEMBLYGUI_ViewProviderPart_H -#include +#include "ViewProvider.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart +class AssemblyGuiExport ViewProviderItemPart : public AssemblyGui::ViewProviderItem { - PROPERTY_HEADER(PartGui::ViewProviderItem); + PROPERTY_HEADER(PartGui::ViewProviderItemPart); public: /// constructor - ViewProviderItem(); + ViewProviderItemPart(); /// destructor - virtual ~ViewProviderItem(); + virtual ~ViewProviderItemPart(); virtual bool doubleClicked(void); @@ -48,4 +48,4 @@ class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart } // namespace AssemblyGui -#endif // PARTGUI_ViewProviderHole_H +#endif // ASSEMBLYGUI_ViewProviderPart_H From 23285e6fd22a90e55fc8da2268549ab7c897a4aa Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 20 Jan 2012 16:28:18 +0100 Subject: [PATCH 009/664] add ProjectView --- src/Gui/ProjectView.cpp | 2 +- src/Gui/ProjectView.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Gui/ProjectView.cpp b/src/Gui/ProjectView.cpp index 66b6a30cefd6..327ac4bc697f 100644 --- a/src/Gui/ProjectView.cpp +++ b/src/Gui/ProjectView.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2012 Jürgen Riegel * + * Copyright (c) 2012 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Gui/ProjectView.h b/src/Gui/ProjectView.h index 7b45386184cf..c6085fc94c6c 100644 --- a/src/Gui/ProjectView.h +++ b/src/Gui/ProjectView.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2012 Jürgen Riegel * + * Copyright (c) 2012 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * From 79cb8362a0781d971cf72a32abc876d38b14173b Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 27 Jan 2012 11:20:15 +0100 Subject: [PATCH 010/664] duplicate zoom node to Gui and add doc tool module --- src/Gui/Inventor/SoZoomTranslation.cpp | 154 +++++++++++++++++++++++++ src/Gui/Inventor/SoZoomTranslation.h | 58 ++++++++++ src/Mod/Assembly/FCDocTool.py | 5 +- 3 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 src/Gui/Inventor/SoZoomTranslation.cpp create mode 100644 src/Gui/Inventor/SoZoomTranslation.h diff --git a/src/Gui/Inventor/SoZoomTranslation.cpp b/src/Gui/Inventor/SoZoomTranslation.cpp new file mode 100644 index 000000000000..30e3d2197ed0 --- /dev/null +++ b/src/Gui/Inventor/SoZoomTranslation.cpp @@ -0,0 +1,154 @@ +/*************************************************************************** + * Copyright (c)2011 Luke Parry * + * * + * 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 +# include +# include +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include "SoZoomTranslation.h" + +// ************************************************************************* + +using namespace Gui; + +// ------------------------------------------------------ + +SO_NODE_SOURCE(SoZoomTranslation); + +void SoZoomTranslation::initClass() +{ + SO_NODE_INIT_CLASS(SoZoomTranslation, SoTranslation, "Translation"); +} + +float SoZoomTranslation::getScaleFactor() +{ + // Dividing by 5 seems to work well + + Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView(); + if (mdi && mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { + Gui::View3DInventorViewer *viewer = static_cast(mdi)->getViewer(); + this->scale = viewer->getCamera()->getViewVolume(viewer->getCamera()->aspectRatio.getValue()).getWorldToScreenScale(SbVec3f(0.f, 0.f, 0.f), 0.1f) / 5; + return this->scale; + } else { + return this->scale; + } +} + +SoZoomTranslation::SoZoomTranslation() +{ + SO_NODE_CONSTRUCTOR(SoZoomTranslation); + SO_NODE_ADD_FIELD(abPos, (SbVec3f(0.f,0.f,0.f))); + this->scale = -1; +} + +void SoZoomTranslation::GLRender(SoGLRenderAction * action) +{ + SoZoomTranslation::doAction((SoAction *)action); +} + +// Doc in superclass. +void SoZoomTranslation::doAction(SoAction * action) +{ + SbVec3f v; + if(this->translation.getValue() == SbVec3f(0.0f, 0.0f, 0.0f) && this->abPos.getValue() == SbVec3f(0.0f, 0.0f, 0.0f)) { + return; + } else { + SbVec3f absVtr = this->abPos.getValue(); + SbVec3f relVtr = this->translation.getValue(); + + float sf = this->getScaleFactor(); + // For Sketcher Keep Z value the same + relVtr[0] = (relVtr[0] != 0) ? sf * relVtr[0] : 0; + relVtr[1] = (relVtr[1] != 0) ? sf * relVtr[1] : 0; + + v = absVtr + relVtr; + } + + SoModelMatrixElement::translateBy(action->getState(), this, v); +} + +void SoZoomTranslation::getMatrix(SoGetMatrixAction * action) +{ + SbVec3f v; + if(this->translation.getValue() == SbVec3f(0.0f, 0.0f, 0.0f) && this->abPos.getValue() == SbVec3f(0.0f, 0.0f, 0.0f)) { + return; + } else { + SbVec3f absVtr = this->abPos.getValue(); + SbVec3f relVtr = this->translation.getValue(); + + float sf = this->getScaleFactor(); + // For Sketcher Keep Z value the same + relVtr[0] = (relVtr[0] != 0) ? sf * relVtr[0] : 0; + relVtr[1] = (relVtr[1] != 0) ? sf * relVtr[1] : 0; + + v = absVtr + relVtr; + } + + SbMatrix m; + m.setTranslate(v); + action->getMatrix().multLeft(m); + m.setTranslate(-v); + action->getInverse().multRight(m); + +} + +void SoZoomTranslation::callback(SoCallbackAction * action) +{ + SoZoomTranslation::doAction((SoAction *)action); +} + +void SoZoomTranslation::getBoundingBox(SoGetBoundingBoxAction * action) +{ + SoZoomTranslation::doAction((SoAction *)action); +} + +void SoZoomTranslation::pick(SoPickAction * action) +{ + SoZoomTranslation::doAction((SoAction *)action); +} + +// Doc in superclass. +void SoZoomTranslation::getPrimitiveCount(SoGetPrimitiveCountAction * action) +{ + SoZoomTranslation::doAction((SoAction *)action); +} \ No newline at end of file diff --git a/src/Gui/Inventor/SoZoomTranslation.h b/src/Gui/Inventor/SoZoomTranslation.h new file mode 100644 index 000000000000..08050a89e17b --- /dev/null +++ b/src/Gui/Inventor/SoZoomTranslation.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * (c) 2011 Luke Parry * + * * + * 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 GUI_SOZOOMTRANSLATION_H +#define GUI_SOZOOMTRANSLATION_H + +#include +#include +#include + +namespace Gui { + +class GuiExport SoZoomTranslation : public SoTranslation { + typedef SoTranslation inherited; + + SO_NODE_HEADER(SoZoomTranslation); + +public: + static void initClass(); + SoZoomTranslation(); + SoSFVec3f abPos; + float getScaleFactor(); + +protected: + virtual ~SoZoomTranslation() {}; + virtual void doAction(SoAction * action); + virtual void getPrimitiveCount(SoGetPrimitiveCountAction * action); + virtual void getMatrix(SoGetMatrixAction * action); + virtual void GLRender(SoGLRenderAction *action); + virtual void getBoundingBox(SoGetBoundingBoxAction * action); + virtual void callback(SoCallbackAction * action); + virtual void pick(SoPickAction * action); + +private: + float scale; +}; + +} +#endif // SKETCHERGUI_SOZOOMTRANSLATION_H diff --git a/src/Mod/Assembly/FCDocTool.py b/src/Mod/Assembly/FCDocTool.py index 02951285ca6d..92c10eed4780 100644 --- a/src/Mod/Assembly/FCDocTool.py +++ b/src/Mod/Assembly/FCDocTool.py @@ -3,15 +3,16 @@ # (c) 2007 Juergen Riegel LGPL import zipfile +from xml.dom.minidom import parse, parseString + class Document: """ Document representation """ def __init__(self,DocFile): self.FileName = DocFile - print "Parsing: ",DocFile self.ZFile = zipfile.ZipFile(DocFile,'r') DStr = self.ZFile.read('Document.xml') - print DStr + self.DDom = parseString(DStr) def fileInfo(self): ret = '' From ed5a055444b9e260add11ea44c8308205cf873e2 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 28 Jan 2012 17:59:45 +0100 Subject: [PATCH 011/664] implementing PlacementObject --- src/Gui/Application.cpp | 2 +- src/Gui/Inventor/SoAutoZoomTranslation.cpp | 16 +-- src/Gui/Inventor/SoZoomTranslation.cpp | 154 --------------------- src/Gui/Inventor/SoZoomTranslation.h | 58 -------- src/Gui/ViewProviderPlacement.cpp | 62 +++++++++ src/Gui/ViewProviderPlacement.h | 2 + 6 files changed, 73 insertions(+), 221 deletions(-) delete mode 100644 src/Gui/Inventor/SoZoomTranslation.cpp delete mode 100644 src/Gui/Inventor/SoZoomTranslation.h diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 1be3a9d48f93..5fbca951d921 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2004 Jürgen Riegel * + * Copyright (c) 2004 Juergen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * diff --git a/src/Gui/Inventor/SoAutoZoomTranslation.cpp b/src/Gui/Inventor/SoAutoZoomTranslation.cpp index 5137d7f74a01..896e35dd68db 100644 --- a/src/Gui/Inventor/SoAutoZoomTranslation.cpp +++ b/src/Gui/Inventor/SoAutoZoomTranslation.cpp @@ -25,7 +25,7 @@ #ifndef _PreComp_ # include # include -# include +# include # include #endif @@ -96,7 +96,7 @@ SoAutoZoomTranslation::SoAutoZoomTranslation() void SoAutoZoomTranslation::GLRender(SoGLRenderAction * action) { - //Base::Console().Log("Draw\n"); + Base::Console().Log("Draw\n"); SoAutoZoomTranslation::doAction((SoAction *)action); inherited::GLRender(action); } @@ -107,7 +107,7 @@ void SoAutoZoomTranslation::doAction(SoAction * action) float sf = this->getScaleFactor(action); SoModelMatrixElement::scaleBy(action->getState(), this, SbVec3f(sf,sf,sf)); - //Base::Console().Log("Scale: %f\n",sf); + Base::Console().Log("Scale: %f\n",sf); } // set the auto scale factor. @@ -123,7 +123,7 @@ void SoAutoZoomTranslation::doAction(SoAction * action) void SoAutoZoomTranslation::getMatrix(SoGetMatrixAction * action) { - //Base::Console().Log("Matrix\n"); + Base::Console().Log("Matrix\n"); float sf = this->getScaleFactor(action); SbVec3f scalevec = SbVec3f(sf,sf,sf); @@ -138,25 +138,25 @@ void SoAutoZoomTranslation::getMatrix(SoGetMatrixAction * action) void SoAutoZoomTranslation::callback(SoCallbackAction * action) { - // Base::Console().Log("callback\n"); + Base::Console().Log("callback\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } void SoAutoZoomTranslation::getBoundingBox(SoGetBoundingBoxAction * action) { - //Base::Console().Log("getBoundingBox\n"); + Base::Console().Log("getBoundingBox\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } void SoAutoZoomTranslation::pick(SoPickAction * action) { - //Base::Console().Log("pick\n"); + Base::Console().Log("pick\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } // Doc in superclass. void SoAutoZoomTranslation::getPrimitiveCount(SoGetPrimitiveCountAction * action) { - //Base::Console().Log("getPrimitiveCount\n"); + Base::Console().Log("getPrimitiveCount\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } diff --git a/src/Gui/Inventor/SoZoomTranslation.cpp b/src/Gui/Inventor/SoZoomTranslation.cpp deleted file mode 100644 index 30e3d2197ed0..000000000000 --- a/src/Gui/Inventor/SoZoomTranslation.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/*************************************************************************** - * Copyright (c)2011 Luke Parry * - * * - * 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 -# include -# include -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -#include "SoZoomTranslation.h" - -// ************************************************************************* - -using namespace Gui; - -// ------------------------------------------------------ - -SO_NODE_SOURCE(SoZoomTranslation); - -void SoZoomTranslation::initClass() -{ - SO_NODE_INIT_CLASS(SoZoomTranslation, SoTranslation, "Translation"); -} - -float SoZoomTranslation::getScaleFactor() -{ - // Dividing by 5 seems to work well - - Gui::MDIView *mdi = Gui::Application::Instance->activeDocument()->getActiveView(); - if (mdi && mdi->isDerivedFrom(Gui::View3DInventor::getClassTypeId())) { - Gui::View3DInventorViewer *viewer = static_cast(mdi)->getViewer(); - this->scale = viewer->getCamera()->getViewVolume(viewer->getCamera()->aspectRatio.getValue()).getWorldToScreenScale(SbVec3f(0.f, 0.f, 0.f), 0.1f) / 5; - return this->scale; - } else { - return this->scale; - } -} - -SoZoomTranslation::SoZoomTranslation() -{ - SO_NODE_CONSTRUCTOR(SoZoomTranslation); - SO_NODE_ADD_FIELD(abPos, (SbVec3f(0.f,0.f,0.f))); - this->scale = -1; -} - -void SoZoomTranslation::GLRender(SoGLRenderAction * action) -{ - SoZoomTranslation::doAction((SoAction *)action); -} - -// Doc in superclass. -void SoZoomTranslation::doAction(SoAction * action) -{ - SbVec3f v; - if(this->translation.getValue() == SbVec3f(0.0f, 0.0f, 0.0f) && this->abPos.getValue() == SbVec3f(0.0f, 0.0f, 0.0f)) { - return; - } else { - SbVec3f absVtr = this->abPos.getValue(); - SbVec3f relVtr = this->translation.getValue(); - - float sf = this->getScaleFactor(); - // For Sketcher Keep Z value the same - relVtr[0] = (relVtr[0] != 0) ? sf * relVtr[0] : 0; - relVtr[1] = (relVtr[1] != 0) ? sf * relVtr[1] : 0; - - v = absVtr + relVtr; - } - - SoModelMatrixElement::translateBy(action->getState(), this, v); -} - -void SoZoomTranslation::getMatrix(SoGetMatrixAction * action) -{ - SbVec3f v; - if(this->translation.getValue() == SbVec3f(0.0f, 0.0f, 0.0f) && this->abPos.getValue() == SbVec3f(0.0f, 0.0f, 0.0f)) { - return; - } else { - SbVec3f absVtr = this->abPos.getValue(); - SbVec3f relVtr = this->translation.getValue(); - - float sf = this->getScaleFactor(); - // For Sketcher Keep Z value the same - relVtr[0] = (relVtr[0] != 0) ? sf * relVtr[0] : 0; - relVtr[1] = (relVtr[1] != 0) ? sf * relVtr[1] : 0; - - v = absVtr + relVtr; - } - - SbMatrix m; - m.setTranslate(v); - action->getMatrix().multLeft(m); - m.setTranslate(-v); - action->getInverse().multRight(m); - -} - -void SoZoomTranslation::callback(SoCallbackAction * action) -{ - SoZoomTranslation::doAction((SoAction *)action); -} - -void SoZoomTranslation::getBoundingBox(SoGetBoundingBoxAction * action) -{ - SoZoomTranslation::doAction((SoAction *)action); -} - -void SoZoomTranslation::pick(SoPickAction * action) -{ - SoZoomTranslation::doAction((SoAction *)action); -} - -// Doc in superclass. -void SoZoomTranslation::getPrimitiveCount(SoGetPrimitiveCountAction * action) -{ - SoZoomTranslation::doAction((SoAction *)action); -} \ No newline at end of file diff --git a/src/Gui/Inventor/SoZoomTranslation.h b/src/Gui/Inventor/SoZoomTranslation.h deleted file mode 100644 index 08050a89e17b..000000000000 --- a/src/Gui/Inventor/SoZoomTranslation.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - * (c) 2011 Luke Parry * - * * - * 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 GUI_SOZOOMTRANSLATION_H -#define GUI_SOZOOMTRANSLATION_H - -#include -#include -#include - -namespace Gui { - -class GuiExport SoZoomTranslation : public SoTranslation { - typedef SoTranslation inherited; - - SO_NODE_HEADER(SoZoomTranslation); - -public: - static void initClass(); - SoZoomTranslation(); - SoSFVec3f abPos; - float getScaleFactor(); - -protected: - virtual ~SoZoomTranslation() {}; - virtual void doAction(SoAction * action); - virtual void getPrimitiveCount(SoGetPrimitiveCountAction * action); - virtual void getMatrix(SoGetMatrixAction * action); - virtual void GLRender(SoGLRenderAction *action); - virtual void getBoundingBox(SoGetBoundingBoxAction * action); - virtual void callback(SoCallbackAction * action); - virtual void pick(SoPickAction * action); - -private: - float scale; -}; - -} -#endif // SKETCHERGUI_SOZOOMTRANSLATION_H diff --git a/src/Gui/ViewProviderPlacement.cpp b/src/Gui/ViewProviderPlacement.cpp index 2d94c730b3e9..d475e96ef4e0 100644 --- a/src/Gui/ViewProviderPlacement.cpp +++ b/src/Gui/ViewProviderPlacement.cpp @@ -44,6 +44,7 @@ #include #include #include "ViewProviderPlacement.h" +#include "SoFCSelection.h" #include "Application.h" #include "Document.h" #include "View3DInventorViewer.h" @@ -161,11 +162,72 @@ void ViewProviderPlacement::attach(App::DocumentObject* pcObject) lineSep->addChild(pCoords); lineSep->addChild(pLines); + // Making the whole measurement object selectable by 3d view can + // become cumbersome since it has influence to any raypick action. + // Thus, it's only selectable by its text label + //SoFCSelection* textsep = new SoFCSelection(); + //textsep->objectName = pcObject->getNameInDocument(); + //textsep->documentName = pcObject->getDocument()->getName(); + //textsep->subElementName = "Main"; + ////SoSeparator* textsep = new SoSeparator(); + //textsep->addChild(pTranslation); + //textsep->addChild(pTextColor); + //textsep->addChild(pFont); + //textsep->addChild(pLabel); + + //SoSeparator* sep = new SoSeparator(); + //sep->addChild(lineSep); + //sep->addChild(textsep); addDisplayMaskMode(lineSep, "Base"); } void ViewProviderPlacement::updateData(const App::Property* prop) { + //if (prop->getTypeId() == App::PropertyVector::getClassTypeId() || + // prop == &Mirror || prop == &DistFactor) { + // if (strcmp(prop->getName(),"P1") == 0) { + // Base::Vector3f v = static_cast(prop)->getValue(); + // pCoords->point.set1Value(0, SbVec3f(v.x,v.y,v.z)); + // } + // else if (strcmp(prop->getName(),"P2") == 0) { + // Base::Vector3f v = static_cast(prop)->getValue(); + // pCoords->point.set1Value(1, SbVec3f(v.x,v.y,v.z)); + // } + + // SbVec3f pt1 = pCoords->point[0]; + // SbVec3f pt2 = pCoords->point[1]; + // SbVec3f dif = pt1-pt2; + + // float length = fabs(dif.length())*DistFactor.getValue(); + // if (Mirror.getValue()) + // length = -length; + + // if (dif.sqrLength() < 10.0e-6f) { + // pCoords->point.set1Value(2, pt1+SbVec3f(0.0f,0.0f,length)); + // pCoords->point.set1Value(3, pt2+SbVec3f(0.0f,0.0f,length)); + // } + // else { + // SbVec3f dir = dif.cross(SbVec3f(1.0f,0.0f,0.0f)); + // if (dir.sqrLength() < 10.0e-6f) + // dir = dif.cross(SbVec3f(0.0f,1.0f,0.0f)); + // if (dir.sqrLength() < 10.0e-6f) + // dir = dif.cross(SbVec3f(0.0f,0.0f,1.0f)); + // dir.normalize(); + // if (dir.dot(SbVec3f(0.0f,0.0f,1.0f)) < 0.0f) + // length = -length; + // pCoords->point.set1Value(2, pt1 + length*dir); + // pCoords->point.set1Value(3, pt2 + length*dir); + // } + + // SbVec3f pos = (pCoords->point[2]+pCoords->point[3])/2.0f; + // pTranslation->translation.setValue(pos); + + // std::stringstream s; + // s.precision(3); + // s.setf(std::ios::fixed | std::ios::showpoint); + // s << dif.length(); + // pLabel->string.setValue(s.str().c_str()); + //} ViewProviderGeometryObject::updateData(prop); } diff --git a/src/Gui/ViewProviderPlacement.h b/src/Gui/ViewProviderPlacement.h index d4a44f625bbe..5bcc887e92f0 100644 --- a/src/Gui/ViewProviderPlacement.h +++ b/src/Gui/ViewProviderPlacement.h @@ -62,6 +62,8 @@ class GuiExport ViewProviderPlacement : public ViewProviderGeometryObject virtual std::string getElement(const SoDetail *) const; virtual SoDetail* getDetail(const char*) const; + static void measureDistanceCallback(void * ud, SoEventCallback * n); + protected: void onChanged(const App::Property* prop); From 4f0f3e8c94094024d7f9d68c66edc10123aaaf99 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 28 Jan 2012 22:37:34 +0100 Subject: [PATCH 012/664] implementing Plane visual --- src/App/GeoFeature.cpp | 4 +- src/App/GeoFeature.h | 4 +- src/Gui/Inventor/SoAutoZoomTranslation.cpp | 14 ++-- src/Gui/ViewProviderPlacement.cpp | 75 ++-------------------- src/Gui/ViewProviderPlacement.h | 6 +- src/Gui/ViewProviderPlane.cpp | 3 +- 6 files changed, 22 insertions(+), 84 deletions(-) diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index 053e0e2cf4ba..cc55fe77d7aa 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) Juergen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * @@ -45,7 +45,7 @@ GeoFeature::GeoFeature(void) GeoFeature::~GeoFeature(void) { -} +} void GeoFeature::transformPlacement(const Base::Placement &transform) { diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index ba9f9d88d486..6a886c5b3a2b 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) Juergen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * @@ -52,4 +52,4 @@ class AppExport GeoFeature : public App::DocumentObject } //namespace App -#endif // APP_GEOFEATURE_H +#endif // APP_GEOFEATURE_H diff --git a/src/Gui/Inventor/SoAutoZoomTranslation.cpp b/src/Gui/Inventor/SoAutoZoomTranslation.cpp index 896e35dd68db..b4cfcc68bd93 100644 --- a/src/Gui/Inventor/SoAutoZoomTranslation.cpp +++ b/src/Gui/Inventor/SoAutoZoomTranslation.cpp @@ -96,7 +96,7 @@ SoAutoZoomTranslation::SoAutoZoomTranslation() void SoAutoZoomTranslation::GLRender(SoGLRenderAction * action) { - Base::Console().Log("Draw\n"); + //Base::Console().Log("Draw\n"); SoAutoZoomTranslation::doAction((SoAction *)action); inherited::GLRender(action); } @@ -107,7 +107,7 @@ void SoAutoZoomTranslation::doAction(SoAction * action) float sf = this->getScaleFactor(action); SoModelMatrixElement::scaleBy(action->getState(), this, SbVec3f(sf,sf,sf)); - Base::Console().Log("Scale: %f\n",sf); + //Base::Console().Log("Scale: %f\n",sf); } // set the auto scale factor. @@ -123,7 +123,7 @@ void SoAutoZoomTranslation::doAction(SoAction * action) void SoAutoZoomTranslation::getMatrix(SoGetMatrixAction * action) { - Base::Console().Log("Matrix\n"); + //Base::Console().Log("Matrix\n"); float sf = this->getScaleFactor(action); SbVec3f scalevec = SbVec3f(sf,sf,sf); @@ -138,25 +138,25 @@ void SoAutoZoomTranslation::getMatrix(SoGetMatrixAction * action) void SoAutoZoomTranslation::callback(SoCallbackAction * action) { - Base::Console().Log("callback\n"); + // Base::Console().Log("callback\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } void SoAutoZoomTranslation::getBoundingBox(SoGetBoundingBoxAction * action) { - Base::Console().Log("getBoundingBox\n"); + //Base::Console().Log("getBoundingBox\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } void SoAutoZoomTranslation::pick(SoPickAction * action) { - Base::Console().Log("pick\n"); + //Base::Console().Log("pick\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } // Doc in superclass. void SoAutoZoomTranslation::getPrimitiveCount(SoGetPrimitiveCountAction * action) { - Base::Console().Log("getPrimitiveCount\n"); + //Base::Console().Log("getPrimitiveCount\n"); SoAutoZoomTranslation::doAction((SoAction*)action); } diff --git a/src/Gui/ViewProviderPlacement.cpp b/src/Gui/ViewProviderPlacement.cpp index d475e96ef4e0..c272bd56bcef 100644 --- a/src/Gui/ViewProviderPlacement.cpp +++ b/src/Gui/ViewProviderPlacement.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2012 * + * Copyright (c) Juergen Riegel (juergen.riegel@web.de) 2012 * * * * This file is part of the FreeCAD CAx development system. * * * @@ -62,15 +62,15 @@ using namespace Gui; PROPERTY_SOURCE(Gui::ViewProviderPlacement, Gui::ViewProviderGeometryObject) -ViewProviderPlacement::ViewProviderPlacement() +ViewProviderPlacement::ViewProviderPlacement() { - + pMat = new SoMaterial(); pMat->ref(); const float dist = 2; const float size = 6; - const float pSize = 4; + const float pSize = 4; static const SbVec3f verts[13] = { @@ -161,73 +161,12 @@ void ViewProviderPlacement::attach(App::DocumentObject* pcObject) lineSep->addChild(pMat); lineSep->addChild(pCoords); lineSep->addChild(pLines); - - // Making the whole measurement object selectable by 3d view can - // become cumbersome since it has influence to any raypick action. - // Thus, it's only selectable by its text label - //SoFCSelection* textsep = new SoFCSelection(); - //textsep->objectName = pcObject->getNameInDocument(); - //textsep->documentName = pcObject->getDocument()->getName(); - //textsep->subElementName = "Main"; - ////SoSeparator* textsep = new SoSeparator(); - //textsep->addChild(pTranslation); - //textsep->addChild(pTextColor); - //textsep->addChild(pFont); - //textsep->addChild(pLabel); - - //SoSeparator* sep = new SoSeparator(); - //sep->addChild(lineSep); - //sep->addChild(textsep); + addDisplayMaskMode(lineSep, "Base"); } void ViewProviderPlacement::updateData(const App::Property* prop) { - //if (prop->getTypeId() == App::PropertyVector::getClassTypeId() || - // prop == &Mirror || prop == &DistFactor) { - // if (strcmp(prop->getName(),"P1") == 0) { - // Base::Vector3f v = static_cast(prop)->getValue(); - // pCoords->point.set1Value(0, SbVec3f(v.x,v.y,v.z)); - // } - // else if (strcmp(prop->getName(),"P2") == 0) { - // Base::Vector3f v = static_cast(prop)->getValue(); - // pCoords->point.set1Value(1, SbVec3f(v.x,v.y,v.z)); - // } - - // SbVec3f pt1 = pCoords->point[0]; - // SbVec3f pt2 = pCoords->point[1]; - // SbVec3f dif = pt1-pt2; - - // float length = fabs(dif.length())*DistFactor.getValue(); - // if (Mirror.getValue()) - // length = -length; - - // if (dif.sqrLength() < 10.0e-6f) { - // pCoords->point.set1Value(2, pt1+SbVec3f(0.0f,0.0f,length)); - // pCoords->point.set1Value(3, pt2+SbVec3f(0.0f,0.0f,length)); - // } - // else { - // SbVec3f dir = dif.cross(SbVec3f(1.0f,0.0f,0.0f)); - // if (dir.sqrLength() < 10.0e-6f) - // dir = dif.cross(SbVec3f(0.0f,1.0f,0.0f)); - // if (dir.sqrLength() < 10.0e-6f) - // dir = dif.cross(SbVec3f(0.0f,0.0f,1.0f)); - // dir.normalize(); - // if (dir.dot(SbVec3f(0.0f,0.0f,1.0f)) < 0.0f) - // length = -length; - // pCoords->point.set1Value(2, pt1 + length*dir); - // pCoords->point.set1Value(3, pt2 + length*dir); - // } - - // SbVec3f pos = (pCoords->point[2]+pCoords->point[3])/2.0f; - // pTranslation->translation.setValue(pos); - - // std::stringstream s; - // s.precision(3); - // s.setf(std::ios::fixed | std::ios::showpoint); - // s << dif.length(); - // pLabel->string.setValue(s.str().c_str()); - //} ViewProviderGeometryObject::updateData(prop); } @@ -255,7 +194,7 @@ std::string ViewProviderPlacement::getElement(const SoDetail* detail) const SoDetail* ViewProviderPlacement::getDetail(const char* subelement) const { SoLineDetail* detail = 0; - std::string subelem(subelement); + std::string subelem(subelement); int edge = -1; if(subelem == "X-Axis") edge = 0; @@ -274,7 +213,7 @@ SoDetail* ViewProviderPlacement::getDetail(const char* subelement) const return detail; } -bool ViewProviderPlacement::isSelectable(void) const +bool ViewProviderPlacement::isSelectable(void) const { return true; } diff --git a/src/Gui/ViewProviderPlacement.h b/src/Gui/ViewProviderPlacement.h index 5bcc887e92f0..a14ee6776330 100644 --- a/src/Gui/ViewProviderPlacement.h +++ b/src/Gui/ViewProviderPlacement.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2012 * + * Copyright (c) Juergen Riegel (juergen.riegel@web.de) 2012 * * * * This file is part of the FreeCAD CAx development system. * * * @@ -54,7 +54,7 @@ class GuiExport ViewProviderPlacement : public ViewProviderGeometryObject std::vector getDisplayModes(void) const; void setDisplayMode(const char* ModeName); - /// indicates if the ViewProvider use the new Selection model + /// indicates if the ViewProvider use the new Selection model virtual bool useNewSelectionModel(void) const {return true;} /// indicates if the ViewProvider can be selected virtual bool isSelectable(void) const ; @@ -62,8 +62,6 @@ class GuiExport ViewProviderPlacement : public ViewProviderGeometryObject virtual std::string getElement(const SoDetail *) const; virtual SoDetail* getDetail(const char*) const; - static void measureDistanceCallback(void * ud, SoEventCallback * n); - protected: void onChanged(const App::Property* prop); diff --git a/src/Gui/ViewProviderPlane.cpp b/src/Gui/ViewProviderPlane.cpp index 2363f03805ce..979469d19ca8 100644 --- a/src/Gui/ViewProviderPlane.cpp +++ b/src/Gui/ViewProviderPlane.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2012 * + * Copyright (c) Juergen Riegel (juergen.riegel@web.de) 2012 * * * * This file is part of the FreeCAD CAx development system. * * * @@ -44,6 +44,7 @@ #include #include #include "ViewProviderPlane.h" +#include "SoFCSelection.h" #include "Application.h" #include "Document.h" #include "View3DInventorViewer.h" From 6700512efe8b48d2ec9e90a39ecda8a002efd084 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 8 Feb 2012 22:29:34 +0100 Subject: [PATCH 013/664] Add some commands to assembly --- src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 3 + src/Mod/Assembly/Gui/CMakeLists.txt | 1 + src/Mod/Assembly/Gui/Command.cpp | 66 +++++++++++++++++--- src/Mod/Assembly/Gui/CommandConstraints.cpp | 67 +++++++++++++++++++++ src/Mod/Assembly/Gui/Workbench.cpp | 4 ++ src/Mod/Part/App/AppPart.cpp | 2 + src/Mod/Part/App/Body.cpp | 60 ++++++++++++++++++ src/Mod/Part/App/Body.h | 64 ++++++++++++++++++++ src/Mod/Part/App/CMakeLists.txt | 2 + src/Mod/PartDesign/App/Body.cpp | 4 +- src/Mod/PartDesign/App/Body.h | 7 +-- src/Mod/PartDesign/Gui/CMakeLists.txt | 2 + src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 54 +++++++++++++++++ src/Mod/PartDesign/Gui/ViewProviderBody.h | 51 ++++++++++++++++ 14 files changed, 373 insertions(+), 14 deletions(-) create mode 100644 src/Mod/Assembly/Gui/CommandConstraints.cpp create mode 100644 src/Mod/Part/App/Body.cpp create mode 100644 src/Mod/Part/App/Body.h create mode 100644 src/Mod/PartDesign/Gui/ViewProviderBody.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderBody.h diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index 95fbc16fe5e5..a5973f1d2ee4 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -39,6 +39,7 @@ // use a different name to CreateCommand() void CreateAssemblyCommands(void); +void CreateAssemblyConstraintCommands(void); void loadAssemblyResource() { @@ -65,6 +66,8 @@ void AssemblyGuiExport initAssemblyGui() // instanciating the commands CreateAssemblyCommands(); + CreateAssemblyConstraintCommands(); + AssemblyGui::Workbench::init(); AssemblyGui::ViewProviderItem ::init(); diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 683333564203..21be6e185742 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -42,6 +42,7 @@ SET(AssemblyGuiModule_SRCS AppAssemblyGui.cpp AppAssemblyGuiPy.cpp Command.cpp + CommandConstraints.cpp Resources/Assembly.qrc qrc_Assembly.cxx PreCompiled.cpp diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index a763d90d412d..3fb2de14c420 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -33,33 +33,85 @@ using namespace std; -DEF_STD_CMD(CmdAssemblyConstraintAxle); -CmdAssemblyConstraintAxle::CmdAssemblyConstraintAxle() - :Command("Assembly_ConstraintAxle") + +//=========================================================================== + +DEF_STD_CMD(CmdAssemblyAddNewPart); + +CmdAssemblyAddNewPart::CmdAssemblyAddNewPart() + :Command("Assembly_AddNewPart") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); - sMenuText = QT_TR_NOOP("Constraint Axle..."); - sToolTipText = QT_TR_NOOP("set a axle constraint between two objects"); + sMenuText = QT_TR_NOOP("Add new Part"); + sToolTipText = QT_TR_NOOP("Add a new Part into the active Assembly"); sWhatsThis = "Assembly_ConstraintAxle"; sStatusTip = sToolTipText; sPixmap = "actions/Axle_constraint"; } -void CmdAssemblyConstraintAxle::activated(int iMsg) +void CmdAssemblyAddNewPart::activated(int iMsg) { // load the file with the module //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); } +//=========================================================================== +DEF_STD_CMD(CmdAssemblyAddNewComponent); + +CmdAssemblyAddNewComponent::CmdAssemblyAddNewComponent() + :Command("Assembly_AddNewComponent") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Add new Component"); + sToolTipText = QT_TR_NOOP("Add a new Component into the active Assembly"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "actions/Axle_constraint"; +} + + +void CmdAssemblyAddNewComponent::activated(int iMsg) +{ + // load the file with the module + //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); + +} + +//=========================================================================== + +DEF_STD_CMD(CmdAssemblyAddExistingComponent); + +CmdAssemblyAddExistingComponent::CmdAssemblyAddExistingComponent() + :Command("Assembly_AddExistingComponent") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Add existing Component..."); + sToolTipText = QT_TR_NOOP("Add a existing Component or File into the active Assembly"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "actions/Axle_constraint"; +} + + +void CmdAssemblyAddExistingComponent::activated(int iMsg) +{ + // load the file with the module + //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); + +} void CreateAssemblyCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); - rcCmdMgr.addCommand(new CmdAssemblyConstraintAxle()); + rcCmdMgr.addCommand(new CmdAssemblyAddNewPart()); + rcCmdMgr.addCommand(new CmdAssemblyAddNewComponent()); + rcCmdMgr.addCommand(new CmdAssemblyAddExistingComponent()); } diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp new file mode 100644 index 000000000000..083a9c1dd962 --- /dev/null +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -0,0 +1,67 @@ +/*************************************************************************** + * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * * + * 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 +#include +#include +#include + + +using namespace std; + + + +//=========================================================================== + +DEF_STD_CMD(CmdAssemblyConstraintAxle); + +CmdAssemblyConstraintAxle::CmdAssemblyConstraintAxle() + :Command("Assembly_ConstraintAxle") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint Axle..."); + sToolTipText = QT_TR_NOOP("set a axle constraint between two objects"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "actions/Axle_constraint"; +} + + +void CmdAssemblyConstraintAxle::activated(int iMsg) +{ + // load the file with the module + //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); + +} + +void CreateAssemblyConstraintCommands(void) +{ + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + + rcCmdMgr.addCommand(new CmdAssemblyConstraintAxle()); + } diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index 2d55df865a2b..b50793b24ce5 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -49,6 +49,10 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand(QT_TR_NOOP("Assembly")); *part << "Assembly_ConstraintAxle"; + *part << "Separator"; + *part << "Assembly_AddNewPart"; + *part << "Assembly_AddNewComponent"; + *part << "Assembly_AddExistingComponent"; return root; } diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index f6ae27a6e092..ed1711256ebd 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -49,6 +49,7 @@ #include "FeatureMirroring.h" #include "FeatureRevolution.h" #include "PartFeatures.h" +#include "Body.h" #include "PrimitiveFeature.h" #include "Part2DObject.h" #include "CustomFeature.h" @@ -218,6 +219,7 @@ PyMODINIT_FUNC initPart() Part::Feature ::init(); Part::FeatureExt ::init(); + Part::Body ::init(); Part::FeaturePython ::init(); Part::FeatureGeometrySet ::init(); Part::CustomFeature ::init(); diff --git a/src/Mod/Part/App/Body.cpp b/src/Mod/Part/App/Body.cpp new file mode 100644 index 000000000000..1596c49da73c --- /dev/null +++ b/src/Mod/Part/App/Body.cpp @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "Body.h" + + +using namespace Part; + +namespace Part { + + +PROPERTY_SOURCE(Part::Body, Part::Feature) + +Body::Body() +{ + ADD_PROPERTY(Model,(0)); + ADD_PROPERTY(Tip ,(0)); +} + +short Body::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *Body::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +} \ No newline at end of file diff --git a/src/Mod/Part/App/Body.h b/src/Mod/Part/App/Body.h new file mode 100644 index 000000000000..d5e91d428c3e --- /dev/null +++ b/src/Mod/Part/App/Body.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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_Body_H +#define PART_Body_H + +#include +#include + + +namespace Part +{ +/** Base class of all body objects in FreeCAD + * A body is used, e.g. in PartDesign, to agregate + * some modeling features to one shape. As long as not + * in edit or active on a workbench, the body shows only the + * resulting shape to the outside (Tip link). + */ +class PartExport Body : public Part::Feature +{ + PROPERTY_HEADER(PartDesign::Body); + +public: + Body(); + + App::PropertyLinkList Model; + App::PropertyLink Tip; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + //const char* getViewProviderName(void) const { + // return "PartDesignGui::ViewProviderBody"; + //} + //@} +}; + +} //namespace Part + + +#endif // PART_Body_H diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 98dac14be8ae..4b6efbf1d817 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -134,6 +134,8 @@ SET(Features_SRCS FeatureGeometrySet.cpp CustomFeature.cpp CustomFeature.h + Body.h + Body.cpp ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 5f82a6ad17d8..a5939fdf369d 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -35,11 +35,11 @@ using namespace PartDesign; namespace PartDesign { -PROPERTY_SOURCE(PartDesign::Body, Part::Feature) +PROPERTY_SOURCE(PartDesign::Body, Part::Body) Body::Body() { - ADD_PROPERTY(Model,(0)); + } short Body::mustExecute() const diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 681d71b2f357..b895425c3744 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -25,22 +25,19 @@ #define PARTDESIGN_Body_H #include -#include +#include namespace PartDesign { -class Body : public Part::Feature +class Body : public Part::Body { PROPERTY_HEADER(PartDesign::Body); public: Body(); - App::PropertyLinkList Model; - App::PropertyLink Tip; - /** @name methods override feature */ //@{ /// recalculate the feature diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 186c5f1c41ed..27a94d9e5276 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -71,6 +71,8 @@ qt4_wrap_ui(PartDesignGui_UIC_HDRS ${PartDesignGui_UIC_SRCS}) SET(PartDesignGuiViewProvider_SRCS ViewProvider.cpp ViewProvider.h + ViewProviderBody.cpp + ViewProviderBody.h ViewProviderPad.cpp ViewProviderPad.h ViewProviderHole.cpp diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp new file mode 100644 index 000000000000..08472d0ca823 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 "ViewProviderBody.h" +#include +//#include + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderBody,PartGui::ViewProviderPart) + +ViewProviderBody::ViewProviderBody() +{ +} + +ViewProviderBody::~ViewProviderBody() +{ +} + +bool ViewProviderBody::doubleClicked(void) +{ + std::string Msg("Change "); + Msg += this->pcObject->getNameInDocument(); + Gui::Command::openCommand(Msg.c_str()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); + return true; +} + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h new file mode 100644 index 000000000000..18f7de1cd82a --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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_ViewProviderBody_H +#define PARTGUI_ViewProviderBody_H + +#include + + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart +{ + PROPERTY_HEADER(PartGui::ViewProviderBody); + +public: + /// constructor + ViewProviderBody(); + /// destructor + virtual ~ViewProviderBody(); + + virtual bool doubleClicked(void); + +}; + + + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderHole_H From 80217bf10fcfd3582e91888e9158904b252b341d Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 12 Feb 2012 19:18:29 +0100 Subject: [PATCH 014/664] Commands and object making --- src/Gui/Tree.cpp | 72 ++++++++++++++++------- src/Gui/Tree.h | 1 + src/Mod/Assembly/App/Constraint.h | 2 +- src/Mod/Assembly/App/Item.h | 2 +- src/Mod/Assembly/App/ItemAssembly.h | 2 +- src/Mod/Assembly/App/ItemPart.h | 2 +- src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 3 + src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 37 ++++++++++++ src/Mod/Assembly/Gui/Command.cpp | 6 +- src/Mod/Assembly/Gui/PreCompiled.h | 6 +- src/Mod/Assembly/Gui/Workbench.cpp | 69 ++++++++++++++++++++++ src/Mod/Assembly/Gui/Workbench.h | 11 +++- 12 files changed, 182 insertions(+), 31 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index dba94c0df98e..a17e8fce1e60 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -638,6 +638,23 @@ void TreeWidget::slotActiveDocument(const Gui::Document& Doc) } } +void TreeWidget::markItem(const App::DocumentObject* Obj,bool mark) +{ + // never call without Object! + assert(Obj); + Gui::Document* Doc = Gui::Application::Instance->getDocument(Obj->getDocument()); + + std::map::iterator jt = DocumentMap.find(Doc); + for (std::map::iterator it = DocumentMap.begin(); + it != DocumentMap.end(); ++it) + { + it->second->markItem(Obj,mark); + + QFont f = it->second->font(0); + f.setBold(it == jt); + it->second->setFont(0,f); + } +} void TreeWidget::onTestStatus(void) { @@ -874,7 +891,7 @@ void DocumentItem::slotResetEdit(const Gui::ViewProviderDocumentObject& v) std::string name (v.getObject()->getNameInDocument()); std::map::iterator it = ObjectMap.find(name); if (it != ObjectMap.end()) { - it->second->setData(0, Qt::BackgroundColorRole,QVariant()); + it->second->setData(0, Qt::BackgroundColorRole,QVariant()); } } @@ -1071,6 +1088,21 @@ const Gui::Document* DocumentItem::document() const return this->pDocument; } +void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) +{ + // never call without Object! + assert(Obj); + + + std::map::iterator pos; + pos = ObjectMap.find(Obj->getNameInDocument()); + if (pos != ObjectMap.end()) { + QFont f = pos->second->font(0); + f.setUnderline(mark); + pos->second->setFont(0,f); + } +} + //void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) //{ // // never call without Object! @@ -1185,7 +1217,7 @@ void DocumentItem::selectItems(void) // The document objects in 'objs' is a subset of the document objects stored // in 'items'. Since both arrays are sorted we get the wanted tree items in // linear time. - std::vector common; + std::vector common; std::vector::iterator item_it = items.begin(); for (std::vector::iterator it = objs.begin(); it != objs.end(); ++it) { item_it = std::find_if(item_it, items.end(), std::bind2nd(ObjectItem_Equal(), *it)); @@ -1197,7 +1229,7 @@ void DocumentItem::selectItems(void) // get all unselected items of the given document std::sort(common.begin(), common.end()); std::sort(items.begin(), items.end()); - std::vector diff; + std::vector diff; std::back_insert_iterator > biit(diff); std::set_difference(items.begin(), items.end(), common.begin(), common.end(), biit); @@ -1315,28 +1347,28 @@ void DocumentObjectItem::testStatus() QIcon::Mode mode = QIcon::Normal; if (currentStatus & 1) { // visible - // Note: By default the foreground, i.e. text color is invalid - // to make use of the default color of the tree widget's palette. - // If we temporarily set this color to dark and reset to an invalid - // color again we cannot do it with setTextColor() or setForeground(), - // respectively, because for any reason the color would always switch - // to black which will lead to unreadable text if the system background - // hss already a dark color. + // Note: By default the foreground, i.e. text color is invalid + // to make use of the default color of the tree widget's palette. + // If we temporarily set this color to dark and reset to an invalid + // color again we cannot do it with setTextColor() or setForeground(), + // respectively, because for any reason the color would always switch + // to black which will lead to unreadable text if the system background + // hss already a dark color. // However, it works if we set the appropriate role to an empty QVariant(). -#if QT_VERSION >= 0x040200 - this->setData(0, Qt::ForegroundRole,QVariant()); +#if QT_VERSION >= 0x040200 + this->setData(0, Qt::ForegroundRole,QVariant()); #else - this->setData(0, Qt::TextColorRole,QVariant()); -#endif - } - else { // invisible - QStyleOptionViewItem opt; - opt.initFrom(this->treeWidget()); -#if QT_VERSION >= 0x040200 + this->setData(0, Qt::TextColorRole,QVariant()); +#endif + } + else { // invisible + QStyleOptionViewItem opt; + opt.initFrom(this->treeWidget()); +#if QT_VERSION >= 0x040200 this->setForeground(0, opt.palette.color(QPalette::Disabled,QPalette::Text)); #else this->setTextColor(0, opt.palette.color(QPalette::Disabled,QPalette::Text); -#endif +#endif mode = QIcon::Disabled; } diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index 9319e6bc73cd..8ed57c67e81a 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -149,6 +149,7 @@ class DocumentItem : public QTreeWidgetItem void selectItems(void); void testStatus(void); void setData(int column, int role, const QVariant & value); + void markItem(const App::DocumentObject* Obj,bool mark); protected: /** Adds a view provider to the document item. diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h index 28b8fa086d91..fd3562ce540b 100644 --- a/src/Mod/Assembly/App/Constraint.h +++ b/src/Mod/Assembly/App/Constraint.h @@ -48,7 +48,7 @@ class AssemblyExport Constraint : public App::DocumentObject short mustExecute() const; /// returns the type name of the view provider //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraint"; + // return "AssemblyGui::ViewProviderConstraint"; //} //@} }; diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index fde89873923c..50ada9aee615 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -68,7 +68,7 @@ class AssemblyExport Item : public Part::Feature short mustExecute() const; /// returns the type name of the view provider const char* getViewProviderName(void) const { - return "PartDesignGui::ViewProviderItem"; + return "AssemblyGui::ViewProviderItem"; } //@} }; diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 35e822390482..3011771220d2 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -47,7 +47,7 @@ class AssemblyExport ItemAssembly : public Assembly::Item short mustExecute() const; /// returns the type name of the view provider const char* getViewProviderName(void) const { - return "PartDesignGui::ViewProviderItemAssembly"; + return "AssemblyGui::ViewProviderItemAssembly"; } //@} }; diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h index bc472a4737ff..19dbc8406e6e 100644 --- a/src/Mod/Assembly/App/ItemPart.h +++ b/src/Mod/Assembly/App/ItemPart.h @@ -47,7 +47,7 @@ class AssemblyExport ItemPart : public Assembly::Item short mustExecute() const; // returns the type name of the view provider const char* getViewProviderName(void) const { - return "ItemPartDesignGui::ViewProviderItemPart"; + return "AssemblyGui::ViewProviderItemPart"; } //@} }; diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index a5973f1d2ee4..7185b7acebb5 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -35,6 +35,8 @@ #include "ViewProviderPart.h" #include "ViewProviderAssembly.h" +#include + //#include "resources/qrc_Assembly.cpp" // use a different name to CreateCommand() @@ -52,6 +54,7 @@ void loadAssemblyResource() extern struct PyMethodDef AssemblyGui_Import_methods[]; + /* Python entry */ extern "C" { void AssemblyGuiExport initAssemblyGui() diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index f6cce5f9f369..7ca515bfc16e 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -26,8 +26,45 @@ # include #endif +#include +#include + +#include + +#include + +// pointer to the active assembly object +Assembly::Item *ActiveAsmObject =0; + + +/* module functions */ +static PyObject * setActiveAssembly(PyObject *self, PyObject *args) +{ + PyObject *object; + if (PyArg_ParseTuple(args,"O!",&(Assembly::ItemPy::Type), &object)) { + Assembly::Item* Item = static_cast(object)->getItemPtr(); + // Should be set! + assert(Item); + + if(ActiveAsmObject){ + + ActiveAsmObject = 0; + + } + ActiveAsmObject = Item; + Gui::ViewProvider* vp = Gui::Application::Instance -> getViewProvider(ActiveAsmObject); + //PyErr_SetString(PyExc_Exception, "empty shape"); + + } + + return 0; +} + /* registration table */ struct PyMethodDef AssemblyGui_Import_methods[] = { + {"setActiveAssembly" ,setActiveAssembly ,METH_VARARGS, + "setActiveAssembly(AssemblyObject) -- Set the Assembly object in work."}, + {NULL, NULL} /* end of table marker */ }; diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 3fb2de14c420..453d6f7b6033 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -48,7 +48,7 @@ CmdAssemblyAddNewPart::CmdAssemblyAddNewPart() sToolTipText = QT_TR_NOOP("Add a new Part into the active Assembly"); sWhatsThis = "Assembly_ConstraintAxle"; sStatusTip = sToolTipText; - sPixmap = "actions/Axle_constraint"; + sPixmap = "Part_Box"; } @@ -72,7 +72,7 @@ CmdAssemblyAddNewComponent::CmdAssemblyAddNewComponent() sToolTipText = QT_TR_NOOP("Add a new Component into the active Assembly"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; - sPixmap = "actions/Axle_constraint"; + sPixmap = "Part_Box"; } @@ -96,7 +96,7 @@ CmdAssemblyAddExistingComponent::CmdAssemblyAddExistingComponent() sToolTipText = QT_TR_NOOP("Add a existing Component or File into the active Assembly"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; - sPixmap = "actions/Axle_constraint"; + sPixmap = "Part_Box"; } diff --git a/src/Mod/Assembly/Gui/PreCompiled.h b/src/Mod/Assembly/Gui/PreCompiled.h index 3fe37f681084..2f3bbc999db5 100644 --- a/src/Mod/Assembly/Gui/PreCompiled.h +++ b/src/Mod/Assembly/Gui/PreCompiled.h @@ -28,12 +28,14 @@ // Importing of App classes #ifdef FC_OS_WIN32 -# define AssemblyAppExport __declspec(dllimport) +# define AssemblyExport __declspec(dllimport) # define PartGuiExport __declspec(dllimport) +# define PartExport __declspec(dllimport) # define AssemblyGuiExport __declspec(dllexport) #else // for Linux -# define AssemblyAppExport +# define AssemblyExport # define PartGuiExport +# define PartExport # define AssemblyGuiExport #endif diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index b50793b24ce5..ec04ec9dcd9c 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -28,7 +28,11 @@ #endif #include "Workbench.h" +#include +#include #include +#include +#include using namespace AssemblyGui; @@ -56,6 +60,25 @@ Gui::ToolBarItem* Workbench::setupToolBars() const return root; } +Gui::MenuItem* Workbench::setupMenuBar() const +{ + Gui::MenuItem* root = StdWorkbench::setupMenuBar(); + Gui::MenuItem* item = root->findItem("&Windows"); + + + Gui::MenuItem* asmCmd = new Gui::MenuItem(); + root->insertItem(item, asmCmd); + asmCmd->setCommand("&Assembly"); + *asmCmd << "Assembly_ConstraintAxle" + << "Separator" + << "Assembly_AddNewPart" + << "Assembly_AddNewComponent" + << "Assembly_AddExistingComponent"; + + + return root; +} + Gui::ToolBarItem* Workbench::setupCommandBars() const { // Part tools @@ -63,3 +86,49 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const return root; } +void Workbench::activated() +{ + Gui::Workbench::activated(); + + std::vector Watcher; + + const char* Asm[] = { + "Assembly_AddNewPart", + "PartDesign_Fillet", + "PartDesign_Chamfer", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT Assembly::Item COUNT 1", + Asm, + "Assembly tools", + "Part_Box" + )); + + addTaskWatcher(Watcher); + Gui::Control().showTaskView(); + + App::Document *doc = App::GetApplication().getActiveDocument(); + if(!doc){ + // create a new document + + Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument()"); + doc = App::GetApplication().getActiveDocument(); + + } + // now we should have a document! + assert(doc); + + if(doc->countObjects()==0){ + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); + } + + +} + +void Workbench::deactivated() +{ + Gui::Workbench::deactivated(); + removeTaskWatcher(); + +} + diff --git a/src/Mod/Assembly/Gui/Workbench.h b/src/Mod/Assembly/Gui/Workbench.h index c1d887874079..a9aced5cfcf4 100644 --- a/src/Mod/Assembly/Gui/Workbench.h +++ b/src/Mod/Assembly/Gui/Workbench.h @@ -36,12 +36,19 @@ class AssemblyGuiExport Workbench : public Gui::StdWorkbench TYPESYSTEM_HEADER(); public: - Workbench(); - virtual ~Workbench(); + Workbench(); + virtual ~Workbench(); + + /** Run some actions when the workbench gets activated. */ + virtual void activated(); + /** Run some actions when the workbench gets deactivated. */ + virtual void deactivated(); protected: Gui::ToolBarItem* setupToolBars() const; Gui::ToolBarItem* setupCommandBars() const; + Gui::MenuItem* setupMenuBar() const; + }; } // namespace AssemblyGui From 26afb6ee77181fa42cdf2f9d6a6054d646bfa926 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 4 Mar 2012 21:27:13 +0100 Subject: [PATCH 015/664] Add highlighting of tree view items --- src/Gui/Document.h | 7 ++++--- src/Gui/Tree.cpp | 18 ++++++++--------- src/Gui/Tree.h | 6 +++--- src/Gui/ViewProvider.cpp | 8 +++++++- src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 20 ++++++++++++++----- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 5 +++-- 6 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/Gui/Document.h b/src/Gui/Document.h index b79cba96bdce..b8c6de358d2b 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -51,12 +51,13 @@ class ViewProvider; class ViewProviderDocumentObject; class Application; class DocumentPy; +enum HighlightMode; /** The Gui Document * This is the document on GUI level. Its main responsibility is keeping * track off open windows for a document and warning on unsaved closes. * All handled views on the document must inherit from MDIView - * @see App::Document + * @see App::Document * @see MDIView * @author Jürgen Riegel */ @@ -141,7 +142,7 @@ class GuiExport Document : public Base::Persistence void setModified(bool); bool isModified() const; - /// Getter for the App Document + /// Getter for the App Document App::Document* getDocument(void) const; /** @name methods for View handling */ @@ -152,7 +153,7 @@ class GuiExport Document : public Base::Persistence Gui::MDIView* getViewOfViewProvider(Gui::ViewProvider*) const; /// Create a new view void createView(const Base::Type& typeId); - /** send messages to the active view + /** send messages to the active view * Send a specific massage to the active view and is able to recive a * return massage */ diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index a17e8fce1e60..47ebbd742fd2 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -113,7 +113,7 @@ TreeWidget::TreeWidget(QWidget* parent) this->statusTimer = new QTimer(this); - connect(this->statusTimer, SIGNAL(timeout()), + connect(this->statusTimer, SIGNAL(timeout()), this, SLOT(onTestStatus())); connect(this, SIGNAL(itemEntered(QTreeWidgetItem*, int)), this, SLOT(onItemEntered(QTreeWidgetItem*))); @@ -506,7 +506,7 @@ void TreeWidget::dropEvent(QDropEvent *event) // one of the source items is also the destination item, that's not allowed if (this->isItemSelected(targetitem)) return; - + // filter out the selected items we cannot handle QList items; QList idxs = selectedIndexes(); @@ -640,7 +640,7 @@ void TreeWidget::slotActiveDocument(const Gui::Document& Doc) void TreeWidget::markItem(const App::DocumentObject* Obj,bool mark) { - // never call without Object! + // never call without Object! assert(Obj); Gui::Document* Doc = Gui::Application::Instance->getDocument(Obj->getDocument()); @@ -819,7 +819,7 @@ void TreeWidget::setItemsSelected (const QList items, bool se QItemSelection range; for (QList::const_iterator it = items.begin(); it != items.end(); ++it) range.select(this->indexFromItem(*it),this->indexFromItem(*it)); - selectionModel()->select(range, select ? + selectionModel()->select(range, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); } @@ -836,7 +836,7 @@ TreeDockWidget::TreeDockWidget(Gui::Document* pcDocument,QWidget *parent) ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView"); this->treeWidget->setIndentation(hGrp->GetInt("Indentation", this->treeWidget->indentation())); - QGridLayout* pLayout = new QGridLayout(this); + QGridLayout* pLayout = new QGridLayout(this); pLayout->setSpacing(0); pLayout->setMargin (0); pLayout->addWidget(this->treeWidget, 0, 0 ); @@ -882,7 +882,7 @@ void DocumentItem::slotInEdit(const Gui::ViewProviderDocumentObject& v) { std::string name (v.getObject()->getNameInDocument()); std::map::iterator it = ObjectMap.find(name); - if (it != ObjectMap.end()) + if (it != ObjectMap.end()) it->second->setBackgroundColor(0,Qt::yellow); } @@ -1090,7 +1090,7 @@ const Gui::Document* DocumentItem::document() const void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) { - // never call without Object! + // never call without Object! assert(Obj); @@ -1105,7 +1105,7 @@ void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) //void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) //{ -// // never call without Object! +// // never call without Object! // assert(Obj); // // @@ -1299,7 +1299,7 @@ void DocumentObjectItem::testStatus() App::DocumentObject* pObject = viewObject->getObject(); // if status has changed then continue - int currentStatus = + int currentStatus = ((pObject->isError() ? 1 : 0) << 2) | ((pObject->mustExecute() == 1 ? 1 : 0) << 1) | (viewObject->isShow() ? 1 : 0); diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index 8ed57c67e81a..0b39b9a42c1c 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -44,7 +44,7 @@ enum HighlightMode { Underlined, Italic , Overlined , Bold , - Blue + Blue }; /// highlight modes for the tree items @@ -131,7 +131,7 @@ private Q_SLOTS: }; /** The link between the tree and a document. - * Every document in the application gets its associated DocumentItem which controls + * Every document in the application gets its associated DocumentItem which controls * the visibility and the functions of the document. * \author Jürgen Riegel */ @@ -186,7 +186,7 @@ class DocumentItem : public QTreeWidgetItem }; /** The link between the tree and a document object. - * Every object in the document gets its associated DocumentObjectItem which controls + * Every object in the document gets its associated DocumentObjectItem which controls * the visibility and the functions of the object. * @author Werner Mayer */ diff --git a/src/Gui/ViewProvider.cpp b/src/Gui/ViewProvider.cpp index b4c54ec1eb6b..d7eee8216814 100644 --- a/src/Gui/ViewProvider.cpp +++ b/src/Gui/ViewProvider.cpp @@ -60,7 +60,7 @@ using namespace Gui; PROPERTY_SOURCE_ABSTRACT(Gui::ViewProvider, App::PropertyContainer) -ViewProvider::ViewProvider() +ViewProvider::ViewProvider() : pcAnnotation(0) , pyViewObject(0) , _iActualMode(-1) @@ -144,6 +144,12 @@ void ViewProvider::setUpdatesEnabled (bool enable) _updateData = enable; } +void highlight(const HighlightMode& high) +{ + + +} + void ViewProvider::eventCallback(void * ud, SoEventCallback * node) { const SoEvent * ev = node->getEvent(); diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index 7ca515bfc16e..ef5fda285cb5 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -30,29 +30,39 @@ #include #include +#include +#include +#include #include // pointer to the active assembly object -Assembly::Item *ActiveAsmObject =0; +Assembly::Item *ActiveAsmObject =0; +Gui::Document *ActiveGuiDoc =0; +Gui::ViewProviderDocumentObject *ActiveVp =0; + /* module functions */ static PyObject * setActiveAssembly(PyObject *self, PyObject *args) { - PyObject *object; - if (PyArg_ParseTuple(args,"O!",&(Assembly::ItemPy::Type), &object)) { + PyObject *object=0; + if (PyArg_ParseTuple(args,"|O",&(Assembly::ItemPy::Type), &object)) { Assembly::Item* Item = static_cast(object)->getItemPtr(); // Should be set! assert(Item); + // get the gui document of the Assembly Item + Gui::Document* GuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); + Gui::ViewProviderDocumentObject* vp = dynamic_cast (GuiDoc->getViewProvider(Item)) ; if(ActiveAsmObject){ - + + GuiDoc->signalHighlightObject(*vp,Gui::HiglightMode::None); ActiveAsmObject = 0; } ActiveAsmObject = Item; - Gui::ViewProvider* vp = Gui::Application::Instance -> getViewProvider(ActiveAsmObject); + //Gui::ViewProvider* vp = Gui::Application::Instance -> getViewProvider(ActiveAsmObject); //PyErr_SetString(PyExc_Exception, "empty shape"); } diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 73eeefac9c5a..13a2794bbe97 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -27,8 +27,8 @@ #endif #include "ViewProviderAssembly.h" -//#include -//#include +#include +#include using namespace AssemblyGui; @@ -44,6 +44,7 @@ ViewProviderItemAssembly::~ViewProviderItemAssembly() bool ViewProviderItemAssembly::doubleClicked(void) { + Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.setActiveAssembly(App.activeDocument().%s)",this->getObject()->getNameInDocument()); return true; } From 72b49dbc6b5a4fa355df3a44bcce0fe2a548644e Mon Sep 17 00:00:00 2001 From: jriegel Date: Tue, 6 Mar 2012 00:12:54 +0100 Subject: [PATCH 016/664] fixes in highlight code --- src/Gui/Tree.cpp | 1 - src/Mod/Assembly/App/Item.cpp | 10 ++++++++++ src/Mod/Assembly/App/Item.h | 6 ++++-- src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 4 ++++ src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 18 ++++++++++-------- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 47ebbd742fd2..fdb7fef3cd54 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -1052,7 +1052,6 @@ void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& o default: break; } - jt->second->setFont(0,f); } diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index 0a52687e88d8..b41a0a3273c5 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -28,6 +28,7 @@ #include #include "Item.h" +#include "ItemPy.h" using namespace Assembly; @@ -62,4 +63,13 @@ App::DocumentObjectExecReturn *Item::execute(void) return App::DocumentObject::StdReturn; } +PyObject *Item::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ItemPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index 50ada9aee615..8119b4b36e8c 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -71,9 +71,11 @@ class AssemblyExport Item : public Part::Feature return "AssemblyGui::ViewProviderItem"; } //@} + + PyObject *getPyObject(void); }; -} //namespace PartDesign +} //namespace Assembly -#endif // PART_Item_H +#endif // ASSEMBLY_Item_H diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index 7185b7acebb5..e68b00481721 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -27,6 +27,7 @@ #endif #include +#include #include #include #include "Workbench.h" @@ -67,6 +68,9 @@ void AssemblyGuiExport initAssemblyGui() (void) Py_InitModule("AssemblyGui", AssemblyGui_Import_methods); /* mod name, table ptr */ Base::Console().Log("Loading GUI of Assembly module... done\n"); + // directly load the module for usage in commands + Base::Interpreter().runString("import AssemblyGui"); + // instanciating the commands CreateAssemblyCommands(); CreateAssemblyConstraintCommands(); diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index ef5fda285cb5..f2218e0b36ed 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -47,27 +47,29 @@ Gui::ViewProviderDocumentObject *ActiveVp =0; static PyObject * setActiveAssembly(PyObject *self, PyObject *args) { PyObject *object=0; - if (PyArg_ParseTuple(args,"|O",&(Assembly::ItemPy::Type), &object)) { + if (PyArg_ParseTuple(args,"|O!",&(Assembly::ItemPy::Type), &object)&& object) { Assembly::Item* Item = static_cast(object)->getItemPtr(); // Should be set! assert(Item); // get the gui document of the Assembly Item - Gui::Document* GuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); - Gui::ViewProviderDocumentObject* vp = dynamic_cast (GuiDoc->getViewProvider(Item)) ; if(ActiveAsmObject){ - GuiDoc->signalHighlightObject(*vp,Gui::HiglightMode::None); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::None); ActiveAsmObject = 0; } ActiveAsmObject = Item; - //Gui::ViewProvider* vp = Gui::Application::Instance -> getViewProvider(ActiveAsmObject); - //PyErr_SetString(PyExc_Exception, "empty shape"); - + ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); + ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue); + + }else{ + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::None); + ActiveAsmObject = 0; } - return 0; + Py_Return; } From 58313b085305fd607e6fa5f74cbeb4d85ba8b74f Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 11 Mar 2012 23:59:00 +0100 Subject: [PATCH 017/664] implementing commands --- src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 2 +- src/Mod/Assembly/Gui/Command.cpp | 25 ++++++++++++++++--- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 8 ++++++ src/Mod/Assembly/Gui/ViewProviderAssembly.h | 2 ++ src/Mod/Assembly/Gui/Workbench.cpp | 22 ++++++++-------- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index f2218e0b36ed..de412629ae7f 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -62,7 +62,7 @@ static PyObject * setActiveAssembly(PyObject *self, PyObject *args) ActiveAsmObject = Item; ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined); }else{ ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::None); diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 453d6f7b6033..eaee42af098e 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -23,16 +23,21 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include #include #include #include +#include + +#include using namespace std; +extern Assembly::Item *ActiveAsmObject; //=========================================================================== @@ -78,9 +83,23 @@ CmdAssemblyAddNewComponent::CmdAssemblyAddNewComponent() void CmdAssemblyAddNewComponent::activated(int iMsg) { - // load the file with the module - //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); - + Assembly::ItemAssembly *dest = 0; + + unsigned int n = getSelection().countObjectsOfType(Assembly::ItemAssembly::getClassTypeId()); + if (n >= 1) { + std::vector Sel = getSelection().getObjectsOfType(Assembly::ItemAssembly::getClassTypeId()); + dest = dynamic_cast(Sel.front()); + }else if(ActiveAsmObject && ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { + dest = dynamic_cast(ActiveAsmObject); + } + + openCommand("Insert Component"); + std::string CompName = getUniqueObjectName("Product"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','%s')",CompName.c_str()); + if(dest){ + std::string fatherName = dest->getNameInDocument(); + doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),CompName.c_str()); + } } //=========================================================================== diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 13a2794bbe97..74a475d9f99b 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace AssemblyGui; PROPERTY_SOURCE(AssemblyGui::ViewProviderItemAssembly,AssemblyGui::ViewProviderItem) @@ -49,3 +51,9 @@ bool ViewProviderItemAssembly::doubleClicked(void) } +std::vector ViewProviderItemAssembly::claimChildren(void)const +{ + + return static_cast(getObject())->Items.getValues(); + +} diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index 3fff1a9bacfb..747b28ee8222 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -41,6 +41,8 @@ class AssemblyGuiExport ViewProviderItemAssembly : public AssemblyGui::ViewProvi virtual bool doubleClicked(void); + virtual std::vector claimChildren(void)const; + }; diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index ec04ec9dcd9c..d0032a08781b 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -107,20 +107,20 @@ void Workbench::activated() addTaskWatcher(Watcher); Gui::Control().showTaskView(); - App::Document *doc = App::GetApplication().getActiveDocument(); - if(!doc){ - // create a new document + //App::Document *doc = App::GetApplication().getActiveDocument(); + //if(!doc){ + // // create a new document - Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument()"); - doc = App::GetApplication().getActiveDocument(); + // Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument()"); + // doc = App::GetApplication().getActiveDocument(); - } - // now we should have a document! - assert(doc); + //} + //// now we should have a document! + //assert(doc); - if(doc->countObjects()==0){ - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); - } + //if(doc->countObjects()==0){ + // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); + //} } From 0ec1c40d255bee91c0a745457a4528b612f1fe10 Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 30 Mar 2012 20:37:32 +0200 Subject: [PATCH 018/664] fix startup AssemblyGui --- src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index e68b00481721..97e128262aec 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -70,6 +70,7 @@ void AssemblyGuiExport initAssemblyGui() // directly load the module for usage in commands Base::Interpreter().runString("import AssemblyGui"); + Base::Interpreter().runString("import PartGui"); // instanciating the commands CreateAssemblyCommands(); From 8537926edc8db5d54bf384afa66419c3b46c17ac Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 1 Apr 2012 15:02:40 +0200 Subject: [PATCH 019/664] Finally fixing the highlight code --- src/Gui/Tree.cpp | 63 +++++++++++----------- src/Gui/Tree.h | 2 +- src/Gui/View3DPy.cpp | 4 +- src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 6 +-- src/Mod/Sketcher/Gui/DrawSketchHandler.cpp | 1 + 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index fdb7fef3cd54..bda4f985e56c 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -638,23 +638,23 @@ void TreeWidget::slotActiveDocument(const Gui::Document& Doc) } } -void TreeWidget::markItem(const App::DocumentObject* Obj,bool mark) -{ - // never call without Object! - assert(Obj); - Gui::Document* Doc = Gui::Application::Instance->getDocument(Obj->getDocument()); - - std::map::iterator jt = DocumentMap.find(Doc); - for (std::map::iterator it = DocumentMap.begin(); - it != DocumentMap.end(); ++it) - { - it->second->markItem(Obj,mark); - - QFont f = it->second->font(0); - f.setBold(it == jt); - it->second->setFont(0,f); - } -} +//void TreeWidget::markItem(const App::DocumentObject* Obj,bool mark) +//{ +// // never call without Object! +// assert(Obj); +// Gui::Document* Doc = Gui::Application::Instance->getDocument(Obj->getDocument()); +// +// std::map::iterator jt = DocumentMap.find(Doc); +// for (std::map::iterator it = DocumentMap.begin(); +// it != DocumentMap.end(); ++it) +// { +// it->second->markItem(Obj,mark); +// +// QFont f = it->second->font(0); +// f.setBold(it == jt); +// it->second->setFont(0,f); +// } +//} void TreeWidget::onTestStatus(void) { @@ -1053,6 +1053,7 @@ void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& o break; } jt->second->setFont(0,f); + } void DocumentItem::slotExpandObject (const Gui::ViewProviderDocumentObject& obj,const Gui::TreeItemMode& mode) @@ -1087,20 +1088,20 @@ const Gui::Document* DocumentItem::document() const return this->pDocument; } -void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) -{ - // never call without Object! - assert(Obj); - - - std::map::iterator pos; - pos = ObjectMap.find(Obj->getNameInDocument()); - if (pos != ObjectMap.end()) { - QFont f = pos->second->font(0); - f.setUnderline(mark); - pos->second->setFont(0,f); - } -} +//void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) +//{ +// // never call without Object! +// assert(Obj); +// +// +// std::map::iterator pos; +// pos = ObjectMap.find(Obj->getNameInDocument()); +// if (pos != ObjectMap.end()) { +// QFont f = pos->second->font(0); +// f.setUnderline(mark); +// pos->second->setFont(0,f); +// } +//} //void DocumentItem::markItem(const App::DocumentObject* Obj,bool mark) //{ diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index 0b39b9a42c1c..a10313746096 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -149,7 +149,7 @@ class DocumentItem : public QTreeWidgetItem void selectItems(void); void testStatus(void); void setData(int column, int role, const QVariant & value); - void markItem(const App::DocumentObject* Obj,bool mark); +// void markItem(const App::DocumentObject* Obj,bool mark); protected: /** Adds a view provider to the document item. diff --git a/src/Gui/View3DPy.cpp b/src/Gui/View3DPy.cpp index 9f83361ef00d..eee00ecd60d2 100644 --- a/src/Gui/View3DPy.cpp +++ b/src/Gui/View3DPy.cpp @@ -464,7 +464,7 @@ Py::Object View3DInventorPy::viewRotateLeft(const Py::Tuple& args) SbRotation rot = cam->orientation.getValue(); SbVec3f vdir(0, 0, -1); rot.multVec(vdir, vdir); - SbRotation nrot(vdir,float( M_PI/2)); + SbRotation nrot(vdir, (float)M_PI/2); cam->orientation.setValue(rot*nrot); } catch (const Base::Exception& e) { @@ -490,7 +490,7 @@ Py::Object View3DInventorPy::viewRotateRight(const Py::Tuple& args) SbRotation rot = cam->orientation.getValue(); SbVec3f vdir(0, 0, -1); rot.multVec(vdir, vdir); - SbRotation nrot(vdir, float(-M_PI/2)); + SbRotation nrot(vdir, (float)-M_PI/2); cam->orientation.setValue(rot*nrot); } catch (const Base::Exception& e) { diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index de412629ae7f..0409d69ae205 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -55,17 +55,17 @@ static PyObject * setActiveAssembly(PyObject *self, PyObject *args) // get the gui document of the Assembly Item if(ActiveAsmObject){ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::None); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); ActiveAsmObject = 0; } ActiveAsmObject = Item; ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); }else{ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::None); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); ActiveAsmObject = 0; } diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index 302a64d6f819..c3dfa3c54f52 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -236,6 +236,7 @@ int DrawSketchHandler::seekAutoConstraint(std::vector &suggested int tangId = Constraint::GeoUndef; + float smlTangDist = 1e15f; // Do not consider if distance is more than that. // Decrease this value when a candidate is found. double tangDeviation = 0.1 * sketchgui->getScaleFactor(); From 29507a44eded6a0440dbcc24b6feef9bf9d5dfc3 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 1 Apr 2012 21:47:24 +0200 Subject: [PATCH 020/664] First claimChildren3D implementation and Starting PartItem implementation --- src/Gui/Command.h | 2 - src/Gui/Document.cpp | 1 + src/Gui/Tree.cpp | 19 +--------- src/Gui/Tree.h | 1 - src/Gui/View3DInventorViewer.cpp | 1 + src/Mod/Assembly/Gui/Command.cpp | 28 ++++++++++++-- src/Mod/Assembly/Gui/ViewProvider.cpp | 7 ++++ src/Mod/Assembly/Gui/ViewProvider.h | 7 ++++ src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 37 +++++++++++++++++++ src/Mod/Assembly/Gui/ViewProviderAssembly.h | 6 +++ src/Mod/Assembly/Gui/Workbench.cpp | 22 +++++------ 11 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/Gui/Command.h b/src/Gui/Command.h index 36e9f3a175c8..9907ecda9545 100644 --- a/src/Gui/Command.h +++ b/src/Gui/Command.h @@ -252,8 +252,6 @@ class GuiExport Command : public CommandBase static void copyVisual(const char* to, const char* attr_to, const char* from, const char* attr_from); /// Get Python tuple from object and sub-elements static std::string getPythonTuple(const std::string& name, const std::vector& subnames); - /// import an external module only once - //static void addModule(const char* sModuleName); /// translate a string to a python string literal (needed e.g. in file names for windows...) const std::string strToPython(const char* Str); const std::string strToPython(const std::string &Str){return strToPython(Str.c_str());}; diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index b0391a1ef8a8..6cb877102d18 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -423,6 +423,7 @@ void Document::slotNewObject(const App::DocumentObject& Obj) Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument()); } #endif + std::list::iterator vIt; // cycling to all views of the document for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) { diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index bda4f985e56c..37d29016216c 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -638,23 +638,6 @@ void TreeWidget::slotActiveDocument(const Gui::Document& Doc) } } -//void TreeWidget::markItem(const App::DocumentObject* Obj,bool mark) -//{ -// // never call without Object! -// assert(Obj); -// Gui::Document* Doc = Gui::Application::Instance->getDocument(Obj->getDocument()); -// -// std::map::iterator jt = DocumentMap.find(Doc); -// for (std::map::iterator it = DocumentMap.begin(); -// it != DocumentMap.end(); ++it) -// { -// it->second->markItem(Obj,mark); -// -// QFont f = it->second->font(0); -// f.setBold(it == jt); -// it->second->setFont(0,f); -// } -//} void TreeWidget::onTestStatus(void) { @@ -672,7 +655,7 @@ void TreeWidget::onTestStatus(void) void TreeWidget::onItemEntered(QTreeWidgetItem * item) { // object item selected - if (item && item->type() == TreeWidget::ObjectType) { + if ( item && item->type() == TreeWidget::ObjectType ) { DocumentObjectItem* obj = static_cast(item); obj->displayStatusInfo(); } diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index a10313746096..2a8fa840e6e3 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -149,7 +149,6 @@ class DocumentItem : public QTreeWidgetItem void selectItems(void); void testStatus(void); void setData(int column, int role, const QVariant & value); -// void markItem(const App::DocumentObject* Obj,bool mark); protected: /** Adds a view provider to the document item. diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 0e2b4a515d7d..573556409736 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -642,6 +642,7 @@ void View3DInventorViewer::removeViewProvider(ViewProvider* pcProvider) _ViewProviderSet.erase(pcProvider); } + SbBool View3DInventorViewer::setEditingViewProvider(Gui::ViewProvider* p, int ModNum) { if (this->editViewProvider) diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index eaee42af098e..02fcac0f6085 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -59,9 +59,29 @@ CmdAssemblyAddNewPart::CmdAssemblyAddNewPart() void CmdAssemblyAddNewPart::activated(int iMsg) { - // load the file with the module - //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); - + Assembly::ItemAssembly *dest = 0; + + unsigned int n = getSelection().countObjectsOfType(Assembly::ItemAssembly::getClassTypeId()); + if (n >= 1) { + std::vector Sel = getSelection().getObjectsOfType(Assembly::ItemAssembly::getClassTypeId()); + dest = dynamic_cast(Sel.front()); + }else if(ActiveAsmObject && ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { + dest = dynamic_cast(ActiveAsmObject); + } + + openCommand("Insert Part"); + std::string PartName = getUniqueObjectName("Part.0"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",PartName.c_str()); + if(dest){ + std::string fatherName = dest->getNameInDocument(); + doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),PartName.c_str()); + } + Command::addModule(App,"PartDesign"); + Command::addModule(Gui,"PartDesignGui"); + std::string BodyName = getUniqueObjectName("Body"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Items = App.activeDocument().%s ",BodyName.c_str(),BodyName.c_str(),BodyName.c_str()); + } //=========================================================================== @@ -94,7 +114,7 @@ void CmdAssemblyAddNewComponent::activated(int iMsg) } openCommand("Insert Component"); - std::string CompName = getUniqueObjectName("Product"); + std::string CompName = getUniqueObjectName("Product.0"); doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','%s')",CompName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); diff --git a/src/Mod/Assembly/Gui/ViewProvider.cpp b/src/Mod/Assembly/Gui/ViewProvider.cpp index 160f3daa39de..5b0fd1474fb7 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.cpp +++ b/src/Mod/Assembly/Gui/ViewProvider.cpp @@ -24,22 +24,29 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include "ViewProvider.h" #include //#include + using namespace AssemblyGui; PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) ViewProviderItem::ViewProviderItem() { + pcChildren = new SoGroup(); + pcChildren->ref(); + } ViewProviderItem::~ViewProviderItem() { + pcChildren->unref(); + pcChildren = 0; } bool ViewProviderItem::doubleClicked(void) diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h index 03fb5d42e279..a28bb51a38b6 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.h +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -26,6 +26,7 @@ #include +class SoGroup; namespace AssemblyGui { @@ -39,7 +40,13 @@ class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart /// destructor virtual ~ViewProviderItem(); + // returns the root node where the children gets collected(3D) + virtual SoGroup* getChildRoot(void) const {return pcChildren;} + + virtual bool doubleClicked(void); +private: + SoGroup *pcChildren; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 74a475d9f99b..23af658abfdb 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include "ViewProviderAssembly.h" @@ -50,6 +51,35 @@ bool ViewProviderItemAssembly::doubleClicked(void) return true; } +void ViewProviderItemAssembly::attach(App::DocumentObject *pcFeat) +{ + // call parent attach method + ViewProviderGeometryObject::attach(pcFeat); + + + // putting all together with the switch + addDisplayMaskMode(getChildRoot(), "Main"); +} + +void ViewProviderItemAssembly::setDisplayMode(const char* ModeName) +{ + if ( strcmp("Main",ModeName)==0 ) + setDisplayMaskMode("Main"); + + ViewProviderGeometryObject::setDisplayMode( ModeName ); +} + +std::vector ViewProviderItemAssembly::getDisplayModes(void) const +{ + // get the modes of the father + std::vector StrList = ViewProviderGeometryObject::getDisplayModes(); + + // add your own modes + StrList.push_back("Main"); + + return StrList; +} + std::vector ViewProviderItemAssembly::claimChildren(void)const { @@ -57,3 +87,10 @@ std::vector ViewProviderItemAssembly::claimChildren(void)c return static_cast(getObject())->Items.getValues(); } + +std::vector ViewProviderItemAssembly::claimChildren3D(void)const +{ + + return static_cast(getObject())->Items.getValues(); + +} diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index 747b28ee8222..1e3fe40ccff3 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -40,9 +40,15 @@ class AssemblyGuiExport ViewProviderItemAssembly : public AssemblyGui::ViewProvi virtual ~ViewProviderItemAssembly(); virtual bool doubleClicked(void); + virtual void attach(App::DocumentObject *); + virtual void setDisplayMode(const char* ModeName); + /// returns a list of all possible modes + virtual std::vector getDisplayModes(void) const; virtual std::vector claimChildren(void)const; + virtual std::vector claimChildren3D(void)const; + }; diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index d0032a08781b..ec04ec9dcd9c 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -107,20 +107,20 @@ void Workbench::activated() addTaskWatcher(Watcher); Gui::Control().showTaskView(); - //App::Document *doc = App::GetApplication().getActiveDocument(); - //if(!doc){ - // // create a new document + App::Document *doc = App::GetApplication().getActiveDocument(); + if(!doc){ + // create a new document - // Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument()"); - // doc = App::GetApplication().getActiveDocument(); + Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument()"); + doc = App::GetApplication().getActiveDocument(); - //} - //// now we should have a document! - //assert(doc); + } + // now we should have a document! + assert(doc); - //if(doc->countObjects()==0){ - // Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); - //} + if(doc->countObjects()==0){ + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); + } } From d5663b4122b0c04d899b6efaa4e9cf27c2ab5c9d Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 5 Apr 2012 20:47:02 +0200 Subject: [PATCH 021/664] Slightly change start up code to run Workbench activate later and some implementations --- src/Gui/Application.cpp | 5 ++++- src/Mod/Assembly/App/ItemPart.h | 3 ++- src/Mod/Assembly/Gui/Command.cpp | 7 +++++-- src/Mod/Assembly/Gui/ViewProviderPart.cpp | 24 +++++++++++++++++++++++ src/Mod/Assembly/Gui/ViewProviderPart.h | 4 ++++ src/Mod/Assembly/Gui/Workbench.cpp | 7 ++++--- 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 5fbca951d921..7bc4521f36cd 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1734,7 +1734,7 @@ void Application::runApplication(void) // Call this before showing the main window because otherwise: // 1. it shows a white window for a few seconds which doesn't look nice // 2. the layout of the toolbars is completely broken - app.activateWorkbench(start.c_str()); + //app.activateWorkbench(start.c_str()); // show the main window if (!hidden) { @@ -1766,6 +1766,9 @@ void Application::runApplication(void) SoDebugError::setHandlerCallback( messageHandlerCoin, 0 ); #endif + app.activateWorkbench(start.c_str()); + + Instance->d->startingUp = false; diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h index 19dbc8406e6e..f2854d9ed5c9 100644 --- a/src/Mod/Assembly/App/ItemPart.h +++ b/src/Mod/Assembly/App/ItemPart.h @@ -38,7 +38,8 @@ class AssemblyExport ItemPart : public Assembly::Item public: ItemPart(); - App::PropertyLink Model; + App::PropertyLink Model; + App::PropertyLinkList Annotation; /** @name methods override feature */ //@{ diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 02fcac0f6085..ac89d7cc04a9 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -67,10 +67,13 @@ void CmdAssemblyAddNewPart::activated(int iMsg) dest = dynamic_cast(Sel.front()); }else if(ActiveAsmObject && ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { dest = dynamic_cast(ActiveAsmObject); + }else { + + } openCommand("Insert Part"); - std::string PartName = getUniqueObjectName("Part.0"); + std::string PartName = getUniqueObjectName("Part"); doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",PartName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); @@ -80,7 +83,7 @@ void CmdAssemblyAddNewPart::activated(int iMsg) Command::addModule(Gui,"PartDesignGui"); std::string BodyName = getUniqueObjectName("Body"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Items = App.activeDocument().%s ",BodyName.c_str(),BodyName.c_str(),BodyName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); } diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.cpp b/src/Mod/Assembly/Gui/ViewProviderPart.cpp index 73988a966cf9..2efa6ef1d969 100644 --- a/src/Mod/Assembly/Gui/ViewProviderPart.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderPart.cpp @@ -29,6 +29,7 @@ #include "ViewProviderPart.h" //#include //#include +#include using namespace AssemblyGui; @@ -48,3 +49,26 @@ bool ViewProviderItemPart::doubleClicked(void) } +std::vector ViewProviderItemPart::claimChildren(void)const +{ + std::vector res; + + if(static_cast(getObject())->Model.getValue()) + res.push_back( static_cast(getObject())->Model.getValue()); + res.insert( res.end(), static_cast(getObject())->Annotation.getValues().begin(),static_cast(getObject())->Annotation.getValues().end()); + + return res; + +} + +std::vector ViewProviderItemPart::claimChildren3D(void)const +{ + std::vector res; + + if(static_cast(getObject())->Model.getValue()) + res.push_back( static_cast(getObject())->Model.getValue()); + res.insert( res.end(), static_cast(getObject())->Annotation.getValues().begin(),static_cast(getObject())->Annotation.getValues().end()); + + return res; + +} diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.h b/src/Mod/Assembly/Gui/ViewProviderPart.h index 8f60075b4d1f..5a3c4b309b7e 100644 --- a/src/Mod/Assembly/Gui/ViewProviderPart.h +++ b/src/Mod/Assembly/Gui/ViewProviderPart.h @@ -41,6 +41,10 @@ class AssemblyGuiExport ViewProviderItemPart : public AssemblyGui::ViewProviderI virtual bool doubleClicked(void); + virtual std::vector claimChildren(void)const; + + virtual std::vector claimChildren3D(void)const; + }; diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index ec04ec9dcd9c..8b183a449845 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -110,8 +110,8 @@ void Workbench::activated() App::Document *doc = App::GetApplication().getActiveDocument(); if(!doc){ // create a new document - - Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument()"); + std::string uniqueName = App::GetApplication().getUniqueDocumentName("Assembly1"); + Gui::Command::doCommand(Gui::Command::Doc,"App.newDocument('%s')",uniqueName.c_str()); doc = App::GetApplication().getActiveDocument(); } @@ -120,9 +120,10 @@ void Workbench::activated() if(doc->countObjects()==0){ Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); + Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.setActiveAssembly(App.activeDocument().Product)"); } - + Gui::Control().showModelView(); } void Workbench::deactivated() From 09f199ed9e3ac2a7862e5f8bd5673984212d1324 Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 5 Apr 2012 22:51:07 +0200 Subject: [PATCH 022/664] View nesting working! --- src/Mod/Assembly/App/ItemPart.cpp | 3 +- src/Mod/Assembly/Gui/Command.cpp | 50 +++++++++++++++++++++-- src/Mod/Assembly/Gui/ViewProviderPart.cpp | 33 ++++++++++++++- src/Mod/Assembly/Gui/ViewProviderPart.h | 5 +++ 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index 3e909a2955eb..a74d6c527633 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -39,7 +39,8 @@ PROPERTY_SOURCE(Assembly::ItemPart, Assembly::Item) ItemPart::ItemPart() { - ADD_PROPERTY(Model,(0)); + ADD_PROPERTY(Model, (0)); + ADD_PROPERTY(Annotation,(0)); } short ItemPart::mustExecute() const diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index ac89d7cc04a9..b626b2e66b80 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -69,7 +69,7 @@ void CmdAssemblyAddNewPart::activated(int iMsg) dest = dynamic_cast(ActiveAsmObject); }else { - + return; } openCommand("Insert Part"); @@ -81,10 +81,29 @@ void CmdAssemblyAddNewPart::activated(int iMsg) } Command::addModule(App,"PartDesign"); Command::addModule(Gui,"PartDesignGui"); + +#if 1 // test code for children nesting + Command::addModule(App,"Part"); + std::string BodyName = getUniqueObjectName("Box"); + doCommand(Doc,"App.activeDocument().addObject('Part::Box','%s')",BodyName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); +#else + std::string BodyName = getUniqueObjectName("Body"); + // add the standard planes + std::string Plane1Name = BodyName + "_PlaneXY"; + std::string Plane2Name = BodyName + "_PlaneYZ"; + std::string Plane3Name = BodyName + "_PlaneXZ"; + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane1Name.c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane2Name.c_str()); + doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(-0.707107,0.000000,0.000000,-0.707107))",Plane2Name.c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane3Name.c_str()); + doCommand(Doc,"App.activeDocument().%s.Annotation = [App.activeDocument().%s,App.activeDocument().%s,App.activeDocument().%s] ",PartName.c_str(),Plane1Name.c_str(),Plane2Name.c_str(),Plane3Name.c_str()); + // add the main body doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); - +#endif # + this->updateActive(); } //=========================================================================== @@ -144,8 +163,31 @@ CmdAssemblyAddExistingComponent::CmdAssemblyAddExistingComponent() void CmdAssemblyAddExistingComponent::activated(int iMsg) { - // load the file with the module - //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); + Assembly::ItemAssembly *dest = 0; + + unsigned int n = getSelection().countObjectsOfType(Assembly::ItemAssembly::getClassTypeId()); + if (n >= 1) { + std::vector Sel = getSelection().getObjectsOfType(Assembly::ItemAssembly::getClassTypeId()); + dest = dynamic_cast(Sel.front()); + }else if(ActiveAsmObject && ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { + dest = dynamic_cast(ActiveAsmObject); + }else { + + return; + } + + openCommand("Insert TestPart"); + std::string PartName = getUniqueObjectName("Part"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",PartName.c_str()); + if(dest){ + std::string fatherName = dest->getNameInDocument(); + doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),PartName.c_str()); + } + Command::addModule(App,"PartDesign"); + Command::addModule(Gui,"PartDesignGui"); + std::string BodyName = getUniqueObjectName("Body"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); } diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.cpp b/src/Mod/Assembly/Gui/ViewProviderPart.cpp index 2efa6ef1d969..943846e2fe31 100644 --- a/src/Mod/Assembly/Gui/ViewProviderPart.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderPart.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include "ViewProviderPart.h" @@ -48,14 +49,42 @@ bool ViewProviderItemPart::doubleClicked(void) return true; } +void ViewProviderItemPart::attach(App::DocumentObject *pcFeat) +{ + // call parent attach method + ViewProviderGeometryObject::attach(pcFeat); + + + // putting all together with the switch + addDisplayMaskMode(getChildRoot(), "Main"); +} + +void ViewProviderItemPart::setDisplayMode(const char* ModeName) +{ + if ( strcmp("Main",ModeName)==0 ) + setDisplayMaskMode("Main"); + + ViewProviderGeometryObject::setDisplayMode( ModeName ); +} + +std::vector ViewProviderItemPart::getDisplayModes(void) const +{ + // get the modes of the father + std::vector StrList = ViewProviderGeometryObject::getDisplayModes(); + + // add your own modes + StrList.push_back("Main"); + + return StrList; +} std::vector ViewProviderItemPart::claimChildren(void)const { std::vector res; + res.insert( res.end(), static_cast(getObject())->Annotation.getValues().begin(),static_cast(getObject())->Annotation.getValues().end()); if(static_cast(getObject())->Model.getValue()) res.push_back( static_cast(getObject())->Model.getValue()); - res.insert( res.end(), static_cast(getObject())->Annotation.getValues().begin(),static_cast(getObject())->Annotation.getValues().end()); return res; @@ -65,9 +94,9 @@ std::vector ViewProviderItemPart::claimChildren3D(void)con { std::vector res; + res.insert( res.end(), static_cast(getObject())->Annotation.getValues().begin(),static_cast(getObject())->Annotation.getValues().end()); if(static_cast(getObject())->Model.getValue()) res.push_back( static_cast(getObject())->Model.getValue()); - res.insert( res.end(), static_cast(getObject())->Annotation.getValues().begin(),static_cast(getObject())->Annotation.getValues().end()); return res; diff --git a/src/Mod/Assembly/Gui/ViewProviderPart.h b/src/Mod/Assembly/Gui/ViewProviderPart.h index 5a3c4b309b7e..720b81ff574d 100644 --- a/src/Mod/Assembly/Gui/ViewProviderPart.h +++ b/src/Mod/Assembly/Gui/ViewProviderPart.h @@ -41,6 +41,11 @@ class AssemblyGuiExport ViewProviderItemPart : public AssemblyGui::ViewProviderI virtual bool doubleClicked(void); + virtual void attach(App::DocumentObject *); + virtual void setDisplayMode(const char* ModeName); + /// returns a list of all possible modes + virtual std::vector getDisplayModes(void) const; + virtual std::vector claimChildren(void)const; virtual std::vector claimChildren3D(void)const; From ea57c041178eb38ec38d7a69d19a567d0ede66bd Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 6 Apr 2012 16:19:11 +0200 Subject: [PATCH 023/664] fix in Plane and Placement visual --- src/Mod/Assembly/App/ItemAssembly.cpp | 4 +++- src/Mod/Assembly/Gui/Command.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index e6210ca3b8cd..159a11abb289 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -60,7 +60,9 @@ App::DocumentObjectExecReturn *ItemAssembly::execute(void) std::vector::iterator it; for (it = obj.begin(); it != obj.end(); ++it) { if ((*it)->getTypeId().isDerivedFrom(Assembly::Item::getClassTypeId())) { - s.push_back(static_cast(*it)->Shape.getValue()); + TopoDS_Shape aShape = static_cast(*it)->Shape.getValue(); + if (!aShape.IsNull()) + s.push_back(aShape); } } diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index b626b2e66b80..65d004f72f43 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -82,7 +82,7 @@ void CmdAssemblyAddNewPart::activated(int iMsg) Command::addModule(App,"PartDesign"); Command::addModule(Gui,"PartDesignGui"); -#if 1 // test code for children nesting +#if 0 // test code for children nesting Command::addModule(App,"Part"); std::string BodyName = getUniqueObjectName("Box"); doCommand(Doc,"App.activeDocument().addObject('Part::Box','%s')",BodyName.c_str()); From e5c4d2aa7001938a347fbbb23d1c1bafa6ad9289 Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 6 Apr 2012 16:50:51 +0200 Subject: [PATCH 024/664] testing selection --- src/Mod/Assembly/Gui/Command.cpp | 2 +- src/Mod/Assembly/Gui/ViewProvider.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 65d004f72f43..b626b2e66b80 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -82,7 +82,7 @@ void CmdAssemblyAddNewPart::activated(int iMsg) Command::addModule(App,"PartDesign"); Command::addModule(Gui,"PartDesignGui"); -#if 0 // test code for children nesting +#if 1 // test code for children nesting Command::addModule(App,"Part"); std::string BodyName = getUniqueObjectName("Box"); doCommand(Doc,"App.activeDocument().addObject('Part::Box','%s')",BodyName.c_str()); diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h index a28bb51a38b6..e3462c28cce2 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.h +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -40,6 +40,8 @@ class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart /// destructor virtual ~ViewProviderItem(); + virtual bool useNewSelectionModel(void) const {return false;} + // returns the root node where the children gets collected(3D) virtual SoGroup* getChildRoot(void) const {return pcChildren;} From 117238da50192657c1b8431978133d87454bccab Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 12 Apr 2012 18:52:14 +0200 Subject: [PATCH 025/664] make SoFCUnifiedSelection work with nested children in 3DView --- src/Gui/Document.h | 2 +- src/Gui/SoFCUnifiedSelection.h | 12 +- src/Gui/View3DInventor.cpp | 1 + src/Gui/View3DInventorViewer.cpp | 10 +- src/Gui/View3DInventorViewer.cpp.orig | 2759 +++++++++++++++++++++++++ src/Gui/View3DInventorViewer.h | 2 +- 6 files changed, 2773 insertions(+), 13 deletions(-) create mode 100644 src/Gui/View3DInventorViewer.cpp.orig diff --git a/src/Gui/Document.h b/src/Gui/Document.h index b8c6de358d2b..67f5160522a9 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -168,7 +168,7 @@ class GuiExport Document : public Base::Persistence /// Attach a view (get called by the MDIView constructor) void attachView(Gui::BaseView* pcView, bool bPassiv=false); /// Detach a view (get called by the MDIView destructor) - void detachView(Gui::BaseView* pcView, bool bPassiv=false); + void detachView(Gui::BaseView* pcView, bool bPassiv=false); /// helper for selection ViewProvider* getViewProviderByPathFromTail(SoPath * path) const; /// call update on all attached views diff --git a/src/Gui/SoFCUnifiedSelection.h b/src/Gui/SoFCUnifiedSelection.h index 894ab1c8ca2d..aa3aaa7f93ee 100644 --- a/src/Gui/SoFCUnifiedSelection.h +++ b/src/Gui/SoFCUnifiedSelection.h @@ -23,15 +23,15 @@ #ifndef GUI_SOFCUNIFIEDSELECTION_H #define GUI_SOFCUNIFIEDSELECTION_H -# ifdef FC_OS_MACOSX -# include -# else +# ifdef FC_OS_MACOSX +# include +# else # ifdef FC_OS_WIN32 # define NOMINMAX # include -# endif -# include -# endif +# endif +# include +# endif #include #include diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 691a2bd54e93..d9e3fc97558d 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -156,6 +156,7 @@ View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent, // create the inventor widget and set the defaults _viewer->setDocument(this->_pcDocument); + _viewer->setDocument(this->_pcDocument); stack->addWidget(_viewer->getWidget()); // http://forum.freecadweb.org/viewtopic.php?f=3&t=6055&sid=150ed90cbefba50f1e2ad4b4e6684eba // describes a minor error but trying to fix it leads to a major issue diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 573556409736..4e05bba9aac5 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -513,16 +513,16 @@ void View3DInventorViewer::init() } catch (...) { Base::Console().Warning("Failed to set up gestures. Unknown error.\n"); } - + //create the cursors QBitmap cursor = QBitmap::fromData(QSize(ROTATE_WIDTH, ROTATE_HEIGHT), rotate_bitmap); QBitmap mask = QBitmap::fromData(QSize(ROTATE_WIDTH, ROTATE_HEIGHT), rotate_mask_bitmap); spinCursor = QCursor(cursor, mask, ROTATE_HOT_X, ROTATE_HOT_Y); - + cursor = QBitmap::fromData(QSize(ZOOM_WIDTH, ZOOM_HEIGHT), zoom_bitmap); mask = QBitmap::fromData(QSize(ZOOM_WIDTH, ZOOM_HEIGHT), zoom_mask_bitmap); zoomCursor = QCursor(cursor, mask, ZOOM_HOT_X, ZOOM_HOT_Y); - + cursor = QBitmap::fromData(QSize(PAN_WIDTH, PAN_HEIGHT), pan_bitmap); mask = QBitmap::fromData(QSize(PAN_WIDTH, PAN_HEIGHT), pan_mask_bitmap); panCursor = QCursor(cursor, mask, PAN_HOT_X, PAN_HOT_Y); @@ -858,7 +858,7 @@ void View3DInventorViewer::setSceneGraph(SoNode* root) SoSearchAction sa; sa.setNode(this->backlight); - //we want the rendered scene with all lights and cameras, viewer->getSceneGraph would return + //we want the rendered scene with all lights and cameras, viewer->getSceneGraph would return //the geometry scene only SoNode* scene = this->getSoRenderManager()->getSceneGraph(); if (scene && scene->getTypeId().isDerivedFrom(SoSeparator::getClassTypeId())) { @@ -1462,7 +1462,7 @@ void View3DInventorViewer::renderScene(void) for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) (*it)->paintGL(); - + //fps rendering if (fpsEnabled) { std::stringstream stream; diff --git a/src/Gui/View3DInventorViewer.cpp.orig b/src/Gui/View3DInventorViewer.cpp.orig new file mode 100644 index 000000000000..a078cf5566ea --- /dev/null +++ b/src/Gui/View3DInventorViewer.cpp.orig @@ -0,0 +1,2759 @@ +/*************************************************************************** + * Copyright (c) 2004 Juergen Riegel * + * * + * 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 +# ifdef FC_OS_WIN32 +# include +# endif +# ifdef FC_OS_MACOSX +# include +# else +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include +#include +#include +#include + +#include "View3DInventorViewer.h" +#include "ViewProviderDocumentObject.h" +#include "SoFCBackgroundGradient.h" +#include "SoFCColorBar.h" +#include "SoFCColorLegend.h" +#include "SoFCColorGradient.h" +#include "SoFCOffscreenRenderer.h" +#include "SoFCSelection.h" +#include "SoFCUnifiedSelection.h" +#include "SoFCInteractiveElement.h" +#include "SoFCBoundingBox.h" +#include "SoAxisCrossKit.h" +#include "View3DInventorRiftViewer.h" + +#include "Selection.h" +#include "SoFCSelectionAction.h" +#include "SoFCVectorizeU3DAction.h" +#include "SoFCVectorizeSVGAction.h" +#include "SoFCDB.h" +#include "Application.h" +#include "MainWindow.h" +#include "NavigationStyle.h" +#include "ViewProvider.h" +#include "SpaceballEvent.h" +#include "GLPainter.h" +#include +#include +#include "View3DViewerPy.h" + +#include +#include +#include + +#include "SoTouchEvents.h" +#include "WinNativeGestureRecognizers.h" + +//#define FC_LOGGING_CB + +using namespace Gui; + +/*** zoom-style cursor ******/ + +#define ZOOM_WIDTH 16 +#define ZOOM_HEIGHT 16 +#define ZOOM_BYTES ((ZOOM_WIDTH + 7) / 8) * ZOOM_HEIGHT +#define ZOOM_HOT_X 5 +#define ZOOM_HOT_Y 7 + +static unsigned char zoom_bitmap[ZOOM_BYTES] = +{ + 0x00, 0x0f, 0x80, 0x1c, 0x40, 0x38, 0x20, 0x70, + 0x90, 0xe4, 0xc0, 0xcc, 0xf0, 0xfc, 0x00, 0x0c, + 0x00, 0x0c, 0xf0, 0xfc, 0xc0, 0xcc, 0x90, 0xe4, + 0x20, 0x70, 0x40, 0x38, 0x80, 0x1c, 0x00, 0x0f +}; + +static unsigned char zoom_mask_bitmap[ZOOM_BYTES] = +{ + 0x00,0x0f,0x80,0x1f,0xc0,0x3f,0xe0,0x7f,0xf0,0xff,0xf0,0xff,0xf0,0xff,0x00, + 0x0f,0x00,0x0f,0xf0,0xff,0xf0,0xff,0xf0,0xff,0xe0,0x7f,0xc0,0x3f,0x80,0x1f, + 0x00,0x0f +}; + +/*** pan-style cursor *******/ + +#define PAN_WIDTH 16 +#define PAN_HEIGHT 16 +#define PAN_BYTES ((PAN_WIDTH + 7) / 8) * PAN_HEIGHT +#define PAN_HOT_X 7 +#define PAN_HOT_Y 7 + +static unsigned char pan_bitmap[PAN_BYTES] = +{ + 0xc0, 0x03, 0x60, 0x02, 0x20, 0x04, 0x10, 0x08, + 0x68, 0x16, 0x54, 0x2a, 0x73, 0xce, 0x01, 0x80, + 0x01, 0x80, 0x73, 0xce, 0x54, 0x2a, 0x68, 0x16, + 0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0xc0, 0x03 +}; + +static unsigned char pan_mask_bitmap[PAN_BYTES] = +{ + 0xc0,0x03,0xe0,0x03,0xe0,0x07,0xf0,0x0f,0xe8,0x17,0xdc,0x3b,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xdc,0x3b,0xe8,0x17,0xf0,0x0f,0xe0,0x07,0xc0,0x03, + 0xc0,0x03 +}; + +/*** rotate-style cursor ****/ + +#define ROTATE_WIDTH 16 +#define ROTATE_HEIGHT 16 +#define ROTATE_BYTES ((ROTATE_WIDTH + 7) / 8) * ROTATE_HEIGHT +#define ROTATE_HOT_X 6 +#define ROTATE_HOT_Y 8 + +static unsigned char rotate_bitmap[ROTATE_BYTES] = { + 0xf0, 0xef, 0x18, 0xb8, 0x0c, 0x90, 0xe4, 0x83, + 0x34, 0x86, 0x1c, 0x83, 0x00, 0x81, 0x00, 0xff, + 0xff, 0x00, 0x81, 0x00, 0xc1, 0x38, 0x61, 0x2c, + 0xc1, 0x27, 0x09, 0x30, 0x1d, 0x18, 0xf7, 0x0f +}; + +static unsigned char rotate_mask_bitmap[ROTATE_BYTES] = { + 0xf0,0xef,0xf8,0xff,0xfc,0xff,0xfc,0xff,0x3c,0xfe,0x1c,0xff,0x00,0xff,0x00, + 0xff,0xff,0x00,0xff,0x00,0xff,0x38,0x7f,0x3c,0xff,0x3f,0xff,0x3f,0xff,0x1f, + 0xf7,0x0f +}; + + +/*! +As ProgressBar has no chance to control the incoming Qt events of Quarter so we need to stop +the event handling to prevent the scenegraph from being selected or deselected +while the progress bar is running. +*/ +class Gui::ViewerEventFilter : public QObject +{ +public: + ViewerEventFilter() {} + ~ViewerEventFilter() {} + + + + bool eventFilter(QObject* obj, QEvent* event) { + +#ifdef GESTURE_MESS + if (obj->isWidgetType()) { + View3DInventorViewer* v = dynamic_cast(obj); + if(v) { + /* Internally, Qt seems to set up the gestures upon showing the + * widget (but after this event is processed), thus invalidating + * our settings. This piece takes care to retune gestures on the + * next event after the show event. + */ + if(v->winGestureTuneState == View3DInventorViewer::ewgtsNeedTuning) { + try{ + WinNativeGestureRecognizerPinch::TuneWindowsGestures(v); + v->winGestureTuneState = View3DInventorViewer::ewgtsTuned; + } catch (Base::Exception &e) { + Base::Console().Warning("Failed to TuneWindowsGestures. Error: %s\n",e.what()); + v->winGestureTuneState = View3DInventorViewer::ewgtsDisabled; + } catch (...) { + Base::Console().Warning("Failed to TuneWindowsGestures. Unknown error.\n"); + v->winGestureTuneState = View3DInventorViewer::ewgtsDisabled; + } + } + if (event->type() == QEvent::Show && v->winGestureTuneState == View3DInventorViewer::ewgtsTuned) + v->winGestureTuneState = View3DInventorViewer::ewgtsNeedTuning; + + } + } +#endif + + // Bug #0000607: Some mices also support horizontal scrolling which however might + // lead to some unwanted zooming when pressing the MMB for panning. + // Thus, we filter out horizontal scrolling. + if (event->type() == QEvent::Wheel) { + QWheelEvent* we = static_cast(event); + if (we->orientation() == Qt::Horizontal) + return true; + } + else if (event->type() == QEvent::KeyPress) { + QKeyEvent* ke = static_cast(event); + if (ke->matches(QKeySequence::SelectAll)) { + static_cast(obj)->selectAll(); + return true; + } + } + if (Base::Sequencer().isRunning() && Base::Sequencer().isBlocking()) + return false; + + if (event->type() == Spaceball::ButtonEvent::ButtonEventType) { + Spaceball::ButtonEvent* buttonEvent = static_cast(event); + if (!buttonEvent) { + Base::Console().Log("invalid spaceball button event\n"); + return true; + } + } + else if (event->type() == Spaceball::MotionEvent::MotionEventType) { + Spaceball::MotionEvent* motionEvent = static_cast(event); + if (!motionEvent) { + Base::Console().Log("invalid spaceball motion event\n"); + return true; + } + } + + return false; + } +}; + +class SpaceNavigatorDevice : public Quarter::InputDevice { +public: + SpaceNavigatorDevice(void) {} + virtual ~SpaceNavigatorDevice() {} + virtual const SoEvent* translateEvent(QEvent* event) { + + if (event->type() == Spaceball::MotionEvent::MotionEventType) { + Spaceball::MotionEvent* motionEvent = static_cast(event); + if (!motionEvent) { + Base::Console().Log("invalid spaceball motion event\n"); + return NULL; + } + + motionEvent->setHandled(true); + + float xTrans, yTrans, zTrans; + xTrans = static_cast(motionEvent->translationX()); + yTrans = static_cast(motionEvent->translationY()); + zTrans = static_cast(motionEvent->translationZ()); + SbVec3f translationVector(xTrans, yTrans, zTrans); + + static float rotationConstant(.0001f); + SbRotation xRot, yRot, zRot; + xRot.setValue(SbVec3f(1.0, 0.0, 0.0), static_cast(motionEvent->rotationX()) * rotationConstant); + yRot.setValue(SbVec3f(0.0, 1.0, 0.0), static_cast(motionEvent->rotationY()) * rotationConstant); + zRot.setValue(SbVec3f(0.0, 0.0, 1.0), static_cast(motionEvent->rotationZ()) * rotationConstant); + + SoMotion3Event* motion3Event = new SoMotion3Event; + motion3Event->setTranslation(translationVector); + motion3Event->setRotation(xRot * yRot * zRot); + + return motion3Event; + } + + return NULL; + }; +}; + +/** \defgroup View3D 3D Viewer + * \ingroup GUI + * + * The 3D Viewer is one of the major components in a CAD/CAE systems. + * Therefore an overview and some remarks to the FreeCAD 3D viewing system. + * + * \section overview Overview + * \todo Overview and complements for the 3D Viewer + */ + + +// ************************************************************************* +View3DInventorViewer::View3DInventorViewer(QWidget* parent, const QGLWidget* sharewidget) + : Quarter::SoQTQuarterAdaptor(parent, sharewidget), editViewProvider(0), navigation(0), + renderType(Native), framebuffer(0), axisCross(0), axisGroup(0), editing(false), redirected(false), + allowredir(false), overrideMode("As Is"), _viewerPy(0) +{ + init(); +} + +View3DInventorViewer::View3DInventorViewer(const QGLFormat& format, QWidget* parent, const QGLWidget* sharewidget) + : Quarter::SoQTQuarterAdaptor(format, parent, sharewidget), editViewProvider(0), navigation(0), + renderType(Native), framebuffer(0), axisCross(0), axisGroup(0), editing(false), redirected(false), + allowredir(false), overrideMode("As Is"), _viewerPy(0) +{ + init(); +} + +void View3DInventorViewer::init() +{ + Gui::Selection().Attach(this); + + // Coin should not clear the pixel-buffer, so the background image + // is not removed. + this->setClearWindow(false); + + // setting up the defaults for the spin rotation + initialize(); + + SoOrthographicCamera* cam = new SoOrthographicCamera; + cam->position = SbVec3f(0, 0, 1); + cam->height = 1; + cam->nearDistance = 0.5; + cam->farDistance = 1.5; + + // setup light sources + SoDirectionalLight* hl = this->getHeadlight(); + backlight = new SoDirectionalLight(); + backlight->ref(); + backlight->setName("backlight"); + backlight->direction.setValue(-hl->direction.getValue()); + backlight->on.setValue(false); // by default off + + // Set up background scenegraph with image in it. + backgroundroot = new SoSeparator; + backgroundroot->ref(); + this->backgroundroot->addChild(cam); + + // Background stuff + pcBackGround = new SoFCBackgroundGradient; + pcBackGround->ref(); + + // Set up foreground, overlayed scenegraph. + this->foregroundroot = new SoSeparator; + this->foregroundroot->ref(); + + SoLightModel* lm = new SoLightModel; + lm->model = SoLightModel::BASE_COLOR; + + SoBaseColor* bc = new SoBaseColor; + bc->rgb = SbColor(1, 1, 0); + + cam = new SoOrthographicCamera; + cam->position = SbVec3f(0, 0, 5); + cam->height = 10; + cam->nearDistance = 0; + cam->farDistance = 10; + + // dragger + //SoSeparator * dragSep = new SoSeparator(); + //SoScale *scale = new SoScale(); + //scale->scaleFactor = SbVec3f (0.2,0.2,0.2); + //dragSep->addChild(scale); + //SoCenterballDragger *dragger = new SoCenterballDragger(); + //dragger->center = SbVec3f (0.8,0.8,0); + ////dragger->rotation = SbRotation(rrot[0],rrot[1],rrot[2],rrot[3]); + //dragSep->addChild(dragger); + + this->foregroundroot->addChild(cam); + this->foregroundroot->addChild(lm); + this->foregroundroot->addChild(bc); + //this->foregroundroot->addChild(dragSep); + +#if 0 + // NOTE: For every mouse click event the SoSelection searches for the picked + // point which causes a certain slow-down because for all objects the primitives + // must be created. Using an SoSeparator avoids this drawback. + SoSelection* selectionRoot = new SoSelection(); + selectionRoot->addSelectionCallback(View3DInventorViewer::selectCB, this); + selectionRoot->addDeselectionCallback(View3DInventorViewer::deselectCB, this); + selectionRoot->setPickFilterCallback(View3DInventorViewer::pickFilterCB, this); +#else + // NOTE: For every mouse click event the SoFCUnifiedSelection searches for the picked + // point which causes a certain slow-down because for all objects the primitives + // must be created. Using an SoSeparator avoids this drawback. + selectionRoot = new Gui::SoFCUnifiedSelection(); + selectionRoot->applySettings(); +#endif + // set the ViewProvider root node + pcViewProviderRoot = selectionRoot; + + // increase refcount before passing it to setScenegraph(), to avoid + // premature destruction + pcViewProviderRoot->ref(); + // is not really working with Coin3D. + //redrawOverlayOnSelectionChange(pcSelection); + setSceneGraph(pcViewProviderRoot); + // Event callback node + pEventCallback = new SoEventCallback(); + pEventCallback->setUserData(this); + pEventCallback->ref(); + pcViewProviderRoot->addChild(pEventCallback); + pEventCallback->addEventCallback(SoEvent::getClassTypeId(), handleEventCB, this); + + dimensionRoot = new SoSwitch(SO_SWITCH_NONE); + pcViewProviderRoot->addChild(dimensionRoot); + dimensionRoot->addChild(new SoSwitch()); //first one will be for the 3d dimensions. + dimensionRoot->addChild(new SoSwitch()); //second one for the delta dimensions. + + // This is a callback node that logs all action that traverse the Inventor tree. +#if defined (FC_DEBUG) && defined(FC_LOGGING_CB) + SoCallback* cb = new SoCallback; + cb->setCallback(interactionLoggerCB, this); + pcViewProviderRoot->addChild(cb); +#endif + + // Set our own render action which show a bounding box if + // the SoFCSelection::BOX style is set + // + // Important note: + // When creating a new GL render action we have to copy over the cache context id + // because otherwise we may get strange rendering behaviour. For more details see + // http://forum.freecadweb.org/viewtopic.php?f=10&t=7486&start=120#p74398 and for + // the fix and some details what happens behind the scene have a look at this + // http://forum.freecadweb.org/viewtopic.php?f=10&t=7486&p=74777#p74736 + uint32_t id = this->getSoRenderManager()->getGLRenderAction()->getCacheContext(); + this->getSoRenderManager()->setGLRenderAction(new SoBoxSelectionRenderAction); + this->getSoRenderManager()->getGLRenderAction()->setCacheContext(id); + + // set the transperency and antialiasing settings +// getGLRenderAction()->setTransparencyType(SoGLRenderAction::SORTED_OBJECT_BLEND); + getSoRenderManager()->getGLRenderAction()->setTransparencyType(SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND); +// getGLRenderAction()->setSmoothing(true); + + // Settings + setSeekTime(0.4f); + + if(isSeekValuePercentage() == false) + setSeekValueAsPercentage(true); + + setSeekDistance(100); + setViewing(false); + + setBackgroundColor(QColor(25, 25, 25)); + setGradientBackground(true); + + // set some callback functions for user interaction + addStartCallback(interactionStartCB); + addFinishCallback(interactionFinishCB); + + //filter a few qt events + viewerEventFilter = new ViewerEventFilter; + installEventFilter(viewerEventFilter); + getEventFilter()->registerInputDevice(new SpaceNavigatorDevice); + getEventFilter()->registerInputDevice(new GesturesDevice(this)); + + this->winGestureTuneState = View3DInventorViewer::ewgtsDisabled; + try{ + this->grabGesture(Qt::PanGesture); + this->grabGesture(Qt::PinchGesture); + #ifdef GESTURE_MESS + { + static WinNativeGestureRecognizerPinch* recognizer;//static to avoid creating more than one recognizer, thus causing memory leak and gradual slowdown + if(recognizer == 0){ + recognizer = new WinNativeGestureRecognizerPinch; + recognizer->registerRecognizer(recognizer); //From now on, Qt owns the pointer. + } + } + this->winGestureTuneState = View3DInventorViewer::ewgtsNeedTuning; + #endif + } catch (Base::Exception &e) { + Base::Console().Warning("Failed to set up gestures. Error: %s\n", e.what()); + } catch (...) { + Base::Console().Warning("Failed to set up gestures. Unknown error.\n"); + } + + //create the cursors + QBitmap cursor = QBitmap::fromData(QSize(ROTATE_WIDTH, ROTATE_HEIGHT), rotate_bitmap); + QBitmap mask = QBitmap::fromData(QSize(ROTATE_WIDTH, ROTATE_HEIGHT), rotate_mask_bitmap); + spinCursor = QCursor(cursor, mask, ROTATE_HOT_X, ROTATE_HOT_Y); + + cursor = QBitmap::fromData(QSize(ZOOM_WIDTH, ZOOM_HEIGHT), zoom_bitmap); + mask = QBitmap::fromData(QSize(ZOOM_WIDTH, ZOOM_HEIGHT), zoom_mask_bitmap); + zoomCursor = QCursor(cursor, mask, ZOOM_HOT_X, ZOOM_HOT_Y); + + cursor = QBitmap::fromData(QSize(PAN_WIDTH, PAN_HEIGHT), pan_bitmap); + mask = QBitmap::fromData(QSize(PAN_WIDTH, PAN_HEIGHT), pan_mask_bitmap); + panCursor = QCursor(cursor, mask, PAN_HOT_X, PAN_HOT_Y); +} + +View3DInventorViewer::~View3DInventorViewer() +{ + // cleanup + this->backgroundroot->unref(); + this->backgroundroot = 0; + this->foregroundroot->unref(); + this->foregroundroot = 0; + this->pcBackGround->unref(); + this->pcBackGround = 0; + + setSceneGraph(0); + this->pEventCallback->unref(); + this->pEventCallback = 0; + this->pcViewProviderRoot->unref(); + this->pcViewProviderRoot = 0; + this->backlight->unref(); + this->backlight = 0; + + delete this->navigation; + + // Note: When closing the application the main window doesn't exist any more. + if (getMainWindow()) + getMainWindow()->setPaneText(2, QLatin1String("")); + + Gui::Selection().Detach(this); + + removeEventFilter(viewerEventFilter); + delete viewerEventFilter; + + if (_viewerPy) { + static_cast(_viewerPy)->_viewer = 0; + Py_DECREF(_viewerPy); + } +} + +void View3DInventorViewer::setDocument(Gui::Document* pcDocument) +{ + // write the document the viewer belongs to to the selection node + selectionRoot->pcDocument = pcDocument; +} + +void View3DInventorViewer::initialize() +{ + navigation = new CADNavigationStyle(); + navigation->setViewer(this); + + this->axiscrossEnabled = true; + this->axiscrossSize = 10; +} + +/// @cond DOXERR +void View3DInventorViewer::OnChange(Gui::SelectionSingleton::SubjectType& rCaller, + Gui::SelectionSingleton::MessageType Reason) +{ + if (Reason.Type == SelectionChanges::AddSelection || + Reason.Type == SelectionChanges::RmvSelection || + Reason.Type == SelectionChanges::SetSelection || + Reason.Type == SelectionChanges::ClrSelection) { + SoFCSelectionAction cAct(Reason); + cAct.apply(pcViewProviderRoot); + } +} +/// @endcond + +SbBool View3DInventorViewer::hasViewProvider(ViewProvider* pcProvider) const +{ + return _ViewProviderSet.find(pcProvider) != _ViewProviderSet.end(); +} + +/// adds an ViewProvider to the view, e.g. from a feature +void View3DInventorViewer::addViewProvider(ViewProvider* pcProvider) +{ + SoSeparator* root = pcProvider->getRoot(); + + if (root) { + pcViewProviderRoot->addChild(root); + _ViewProviderMap[root] = pcProvider; + } + + SoSeparator* fore = pcProvider->getFrontRoot(); + + if (fore) + foregroundroot->addChild(fore); + + SoSeparator* back = pcProvider->getBackRoot(); + + if (back) + backgroundroot->addChild(back); + + pcProvider->setOverrideMode(this->getOverrideMode()); + _ViewProviderSet.insert(pcProvider); +} + +void View3DInventorViewer::removeViewProvider(ViewProvider* pcProvider) +{ + if (this->editViewProvider == pcProvider) + resetEditingViewProvider(); + + SoSeparator* root = pcProvider->getRoot(); + + if (root) { + pcViewProviderRoot->removeChild(root); + _ViewProviderMap.erase(root); + } + + SoSeparator* fore = pcProvider->getFrontRoot(); + + if (fore) + foregroundroot->removeChild(fore); + + SoSeparator* back = pcProvider->getBackRoot(); + + if (back) + backgroundroot->removeChild(back); + + _ViewProviderSet.erase(pcProvider); +} + + +SbBool View3DInventorViewer::setEditingViewProvider(Gui::ViewProvider* p, int ModNum) +{ + if (this->editViewProvider) + return false; // only one view provider is editable at a time + + bool ok = p->startEditing(ModNum); + + if (ok) { + this->editViewProvider = p; + this->editViewProvider->setEditViewer(this, ModNum); + addEventCallback(SoEvent::getClassTypeId(), Gui::ViewProvider::eventCallback,this->editViewProvider); + } + + return ok; +} + +/// reset from edit mode +void View3DInventorViewer::resetEditingViewProvider() +{ + if (this->editViewProvider) { + this->editViewProvider->unsetEditViewer(this); + removeEventCallback(SoEvent::getClassTypeId(), Gui::ViewProvider::eventCallback,this->editViewProvider); + this->editViewProvider = 0; + } +} + +/// reset from edit mode +SbBool View3DInventorViewer::isEditingViewProvider() const +{ + return this->editViewProvider ? true : false; +} + +/// display override mode +void View3DInventorViewer::setOverrideMode(const std::string& mode) +{ + if (mode == overrideMode) + return; + + overrideMode = mode; + + for (std::set::iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) + (*it)->setOverrideMode(mode); +} + +/// update override mode. doesn't affect providers +void View3DInventorViewer::updateOverrideMode(const std::string& mode) +{ + if (mode == overrideMode) + return; + + overrideMode = mode; +} + +void View3DInventorViewer::setViewportCB(void* userdata, SoAction* action) +{ + // Make sure to override the value set inside SoOffscreenRenderer::render() + if (action->isOfType(SoGLRenderAction::getClassTypeId())) { + SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance(); + const SbViewportRegion& vp = renderer.getViewportRegion(); + SoViewportRegionElement::set(action->getState(), vp); + static_cast(action)->setViewportRegion(vp); + } +} + +void View3DInventorViewer::clearBufferCB(void* userdata, SoAction* action) +{ + if (action->isOfType(SoGLRenderAction::getClassTypeId())) { + // do stuff specific for GL rendering here. + glClear(GL_DEPTH_BUFFER_BIT); + } +} + +void View3DInventorViewer::setGLWidgetCB(void* userdata, SoAction* action) +{ + //FIXME: This causes the Coin error message: + // Coin error in SoNode::GLRenderS(): GL error: 'GL_STACK_UNDERFLOW', nodetype: + // Separator (set envvar COIN_GLERROR_DEBUGGING=1 and re-run to get more information) + if (action->isOfType(SoGLRenderAction::getClassTypeId())) { + QWidget* gl = reinterpret_cast(userdata); + SoGLWidgetElement::set(action->getState(), qobject_cast(gl)); + } +} + +void View3DInventorViewer::handleEventCB(void* ud, SoEventCallback* n) +{ + View3DInventorViewer* that = reinterpret_cast(ud); + SoGLRenderAction* glra = that->getSoRenderManager()->getGLRenderAction(); + SoAction* action = n->getAction(); + SoGLRenderActionElement::set(action->getState(), glra); + SoGLWidgetElement::set(action->getState(), qobject_cast(that->getGLWidget())); +} + +void View3DInventorViewer::setGradientBackground(bool on) +{ + if (on && backgroundroot->findChild(pcBackGround) == -1) + backgroundroot->addChild(pcBackGround); + else if(!on && backgroundroot->findChild(pcBackGround) != -1) + backgroundroot->removeChild(pcBackGround); +} + +bool View3DInventorViewer::hasGradientBackground() const +{ + return (backgroundroot->findChild(pcBackGround) != -1); +} + +void View3DInventorViewer::setGradientBackgroundColor(const SbColor& fromColor, + const SbColor& toColor) +{ + pcBackGround->setColorGradient(fromColor, toColor); +} + +void View3DInventorViewer::setGradientBackgroundColor(const SbColor& fromColor, + const SbColor& toColor, + const SbColor& midColor) +{ + pcBackGround->setColorGradient(fromColor, toColor, midColor); +} + +void View3DInventorViewer::setEnabledFPSCounter(bool on) +{ + fpsEnabled = on; +} + +void View3DInventorViewer::setAxisCross(bool on) +{ + SoNode* scene = getSceneGraph(); + SoSeparator* sep = static_cast(scene); + + if (on) { + if (!axisGroup) { + axisCross = new Gui::SoShapeScale; + Gui::SoAxisCrossKit* axisKit = new Gui::SoAxisCrossKit(); + axisKit->set("xAxis.appearance.drawStyle", "lineWidth 2"); + axisKit->set("yAxis.appearance.drawStyle", "lineWidth 2"); + axisKit->set("zAxis.appearance.drawStyle", "lineWidth 2"); + axisCross->setPart("shape", axisKit); + axisCross->scaleFactor = 1.0f; + axisGroup = new SoSkipBoundingGroup; + axisGroup->addChild(axisCross); + + sep->addChild(axisGroup); + } + } + else { + if (axisGroup) { + sep->removeChild(axisGroup); + axisGroup = 0; + } + } +} + +bool View3DInventorViewer::hasAxisCross(void) +{ + return axisGroup; +} + +void View3DInventorViewer::setNavigationType(Base::Type t) +{ + if (t.isBad()) + return; + + if (this->navigation && this->navigation->getTypeId() == t) + return; // nothing to do + + Base::BaseClass* base = static_cast(t.createInstance()); + + if (!base) + return; + + if (!base->getTypeId().isDerivedFrom(NavigationStyle::getClassTypeId())) { + delete base; + return; + } + + NavigationStyle* ns = static_cast(base); + ns->operator = (*this->navigation); + delete this->navigation; + this->navigation = ns; + this->navigation->setViewer(this); +} + +NavigationStyle* View3DInventorViewer::navigationStyle() const +{ + return this->navigation; +} + +SoDirectionalLight* View3DInventorViewer::getBacklight(void) const +{ + return this->backlight; +} + +void View3DInventorViewer::setBacklight(SbBool on) +{ + this->backlight->on = on; +} + +SbBool View3DInventorViewer::isBacklight(void) const +{ + return this->backlight->on.getValue(); +} + +void View3DInventorViewer::setSceneGraph(SoNode* root) +{ + inherited::setSceneGraph(root); + + SoSearchAction sa; + sa.setNode(this->backlight); + //we want the rendered scene with all lights and cameras, viewer->getSceneGraph would return + //the geometry scene only + SoNode* scene = this->getSoRenderManager()->getSceneGraph(); + if (scene && scene->getTypeId().isDerivedFrom(SoSeparator::getClassTypeId())) { + sa.apply(scene); + if (!sa.getPath()) + static_cast(scene)->insertChild(this->backlight, 0); + } +} + +void View3DInventorViewer::savePicture(int w, int h, const QColor& bg, QImage& img) const +{ + // If 'QGLPixelBuffer::hasOpenGLPbuffers()' returns false then + // SoQtOffscreenRenderer won't work. In this case we try to use + // Coin's implementation of the off-screen rendering. + bool useCoinOffscreenRenderer = !QGLPixelBuffer::hasOpenGLPbuffers(); + useCoinOffscreenRenderer = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Document")-> + GetBool("CoinOffscreenRenderer", useCoinOffscreenRenderer); + + // if no valid color use the current background + bool useBackground = false; + SbViewportRegion vp(getSoRenderManager()->getViewportRegion()); + + if (w>0 && h>0) + vp.setWindowSize((short)w, (short)h); + + //NOTE: To support pixels per inch we must use SbViewportRegion::setPixelsPerInch( ppi ); + //The default value is 72.0. + //If we need to support grayscale images with must either use SoOffscreenRenderer::LUMINANCE or + //SoOffscreenRenderer::LUMINANCE_TRANSPARENCY. + + SoCallback* cb = 0; + + // for an invalid color use the viewer's current background color + QColor bgColor; + if (!bg.isValid()) { + if (backgroundroot->findChild(pcBackGround) == -1) { + bgColor = this->backgroundColor(); + } + else { + useBackground = true; + cb = new SoCallback; + cb->setCallback(clearBufferCB); + } + } + else { + bgColor = bg; + } + + SoSeparator* root = new SoSeparator; + root->ref(); + +#if (COIN_MAJOR_VERSION >= 4) + // The behaviour in Coin4 has changed so that when using the same instance of 'SoFCOffscreenRenderer' + // multiple times internally the biggest viewport size is stored and set to the SoGLRenderAction. + // The trick is to add a callback node and override the viewport size with what we want. + if (useCoinOffscreenRenderer) { + SoCallback* cbvp = new SoCallback; + cbvp->setCallback(setViewportCB); + root->addChild(cbvp); + } +#endif + + SoCamera* camera = getSoRenderManager()->getCamera(); + + if (useBackground) { + root->addChild(backgroundroot); + root->addChild(cb); + } + + root->addChild(getHeadlight()); + root->addChild(camera); + SoCallback* gl = new SoCallback; + gl->setCallback(setGLWidgetCB, this->getGLWidget()); + root->addChild(gl); + root->addChild(pcViewProviderRoot); + + if (useBackground) + root->addChild(cb); + + root->addChild(foregroundroot); + + try { + // render the scene + if (!useCoinOffscreenRenderer) { + SoQtOffscreenRenderer renderer(vp); + renderer.setNumPasses(4); + if (bgColor.isValid()) + renderer.setBackgroundColor(SbColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF())); + if (!renderer.render(root)) + throw Base::Exception("Offscreen rendering failed"); + + renderer.writeToImage(img); + root->unref(); + } + else { + SoFCOffscreenRenderer& renderer = SoFCOffscreenRenderer::instance(); + renderer.setViewportRegion(vp); + if (bgColor.isValid()) + renderer.setBackgroundColor(SbColor(bgColor.redF(), bgColor.greenF(), bgColor.blueF())); + if (!renderer.render(root)) + throw Base::Exception("Offscreen rendering failed"); + + renderer.writeToImage(img); + root->unref(); + } + } + catch (...) { + root->unref(); + throw; // re-throw exception + } +} + +void View3DInventorViewer::saveGraphic(int pagesize, const QColor& bgcolor, SoVectorizeAction* va) const +{ + if (bgcolor.isValid()) + va->setBackgroundColor(true, SbColor(bgcolor.redF(), bgcolor.greenF(), bgcolor.blueF())); + + float border = 10.0f; + SbVec2s vpsize = this->getSoRenderManager()->getViewportRegion().getViewportSizePixels(); + float vpratio = ((float)vpsize[0]) / ((float)vpsize[1]); + + if (vpratio > 1.0f) { + va->setOrientation(SoVectorizeAction::LANDSCAPE); + vpratio = 1.0f / vpratio; + } + else { + va->setOrientation(SoVectorizeAction::PORTRAIT); + } + + va->beginStandardPage(SoVectorizeAction::PageSize(pagesize), border); + + // try to fill as much "paper" as possible + SbVec2f size = va->getPageSize(); + + float pageratio = size[0] / size[1]; + float xsize, ysize; + + if (pageratio < vpratio) { + xsize = size[0]; + ysize = xsize / vpratio; + } + else { + ysize = size[1]; + xsize = ysize * vpratio; + } + + float offx = border + (size[0]-xsize) * 0.5f; + float offy = border + (size[1]-ysize) * 0.5f; + + va->beginViewport(SbVec2f(offx, offy), SbVec2f(xsize, ysize)); + va->calibrate(this->getSoRenderManager()->getViewportRegion()); + + va->apply(this->getSoRenderManager()->getSceneGraph()); + + va->endViewport(); + va->endPage(); +} + +void View3DInventorViewer::startSelection(View3DInventorViewer::SelectionMode mode) +{ + navigation->startSelection(NavigationStyle::SelectionMode(mode)); +} + +void View3DInventorViewer::stopSelection() +{ + navigation->stopSelection(); +} + +bool View3DInventorViewer::isSelecting() const +{ + return navigation->isSelecting(); +} + +const std::vector& View3DInventorViewer::getPolygon(SbBool* clip_inner) const +{ + return navigation->getPolygon(clip_inner); +} + +SbVec2f View3DInventorViewer::screenCoordsOfPath(SoPath* path) const +{ + // Generate a matrix (well, a SoGetMatrixAction) that + // moves us to the picked object's coordinate space. + SoGetMatrixAction gma(getSoRenderManager()->getViewportRegion()); + gma.apply(path); + + // Use that matrix to translate the origin in the picked + // object's coordinate space into object space + SbVec3f imageCoords(0, 0, 0); + SbMatrix m = gma.getMatrix().transpose(); + m.multMatrixVec(imageCoords, imageCoords); + + // Now, project the object space coordinates of the object + // into "normalized" screen coordinates. + SbViewVolume vol = getSoRenderManager()->getCamera()->getViewVolume(); + vol.projectToScreen(imageCoords, imageCoords); + + // Translate "normalized" screen coordinates to pixel coords. + // + // Note: for some reason, projectToScreen() doesn't seem to + // handle non-square viewports properly. The X and Y are + // scaled such that [0,1] fits within the smaller of the window + // width or height. For instance, in a window that's 400px + // tall and 800px wide, the Y will be within [0,1], but X can + // vary within [-0.5,1.5]... + int width = getGLWidget()->width(), + height = getGLWidget()->height(); + + if (width >= height) { + // "Landscape" orientation, to square + imageCoords[0] *= height; + imageCoords[0] += (width-height) / 2.0; + imageCoords[1] *= height; + + } + else { + // "Portrait" orientation + imageCoords[0] *= width; + imageCoords[1] *= width; + imageCoords[1] += (height-width) / 2.0; + } + + return SbVec2f(imageCoords[0], imageCoords[1]); +} + +std::vector View3DInventorViewer::getGLPolygon(const std::vector& pnts) const +{ + const SbViewportRegion& vp = this->getSoRenderManager()->getViewportRegion(); + const SbVec2s& sz = vp.getWindowSize(); + short w,h; + sz.getValue(w,h); + const SbVec2s& sp = vp.getViewportSizePixels(); + const SbVec2s& op = vp.getViewportOriginPixels(); + const SbVec2f& siz = vp.getViewportSize(); + float dX, dY; + siz.getValue(dX, dY); + float fRatio = vp.getViewportAspectRatio(); + + std::vector poly; + + for (std::vector::const_iterator it = pnts.begin(); it != pnts.end(); ++it) { + SbVec2s loc = *it - op; + SbVec2f pos((float)loc[0]/(float)sp[0], (float)loc[1]/(float)sp[1]); + float pX,pY; + pos.getValue(pX,pY); + + // now calculate the real points respecting aspect ratio information + // + if (fRatio > 1.0f) { + pX = (pX - 0.5f*dX) * fRatio + 0.5f*dX; + pos.setValue(pX,pY); + } + else if(fRatio < 1.0f) { + pY = (pY - 0.5f*dY) / fRatio + 0.5f*dY; + pos.setValue(pX,pY); + } + + poly.push_back(pos); + } + + return poly; +} + +std::vector View3DInventorViewer::getGLPolygon(SbBool* clip_inner) const +{ + const std::vector& pnts = navigation->getPolygon(clip_inner); + return getGLPolygon(pnts); +} + +bool View3DInventorViewer::dumpToFile(SoNode* node, const char* filename, bool binary) const +{ + bool ret = false; + Base::FileInfo fi(filename); + + if (fi.hasExtension("idtf") || fi.hasExtension("svg")) { + int ps=4; + QColor c = Qt::white; + std::auto_ptr vo; + + if (fi.hasExtension("svg")) { + vo = std::auto_ptr(new SoFCVectorizeSVGAction()); + } + else if(fi.hasExtension("idtf")) { + vo = std::auto_ptr(new SoFCVectorizeU3DAction()); + } + else { + throw Base::Exception("Not supported vector graphic"); + } + + SoVectorOutput* out = vo->getOutput(); + + if (!out || !out->openFile(filename)) { + std::ostringstream a_out; + a_out << "Cannot open file '" << filename << "'"; + throw Base::Exception(a_out.str()); + } + + saveGraphic(ps,c,vo.get()); + out->closeFile(); + } + else { + // Try VRML and Inventor format + ret = SoFCDB::writeToFile(node, filename, binary); + } + + return ret; +} + +/** + * Sets the SoFCInteractiveElement to \a true. + */ +void View3DInventorViewer::interactionStartCB(void* data, SoQTQuarterAdaptor* viewer) +{ + SoGLRenderAction* glra = viewer->getSoRenderManager()->getGLRenderAction(); + SoFCInteractiveElement::set(glra->getState(), viewer->getSceneGraph(), true); +} + +/** + * Sets the SoFCInteractiveElement to \a false and forces a redraw. + */ +void View3DInventorViewer::interactionFinishCB(void* data, SoQTQuarterAdaptor* viewer) +{ + SoGLRenderAction* glra = viewer->getSoRenderManager()->getGLRenderAction(); + SoFCInteractiveElement::set(glra->getState(), viewer->getSceneGraph(), false); + viewer->redraw(); +} + +/** + * Logs the type of the action that traverses the Inventor tree. + */ +void View3DInventorViewer::interactionLoggerCB(void* ud, SoAction* action) +{ + Base::Console().Log("%s\n", action->getTypeId().getName().getString()); +} + +void View3DInventorViewer::addGraphicsItem(GLGraphicsItem* item) +{ + this->graphicsItems.push_back(item); +} + +void View3DInventorViewer::removeGraphicsItem(GLGraphicsItem* item) +{ + this->graphicsItems.remove(item); +} + +std::list View3DInventorViewer::getGraphicsItems() const +{ + return graphicsItems; +} + +std::list View3DInventorViewer::getGraphicsItemsOfType(const Base::Type& type) const +{ + std::list items; + + for(std::list::const_iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) { + if((*it)->isDerivedFrom(type)) + items.push_back(*it); + } + + return items; +} + +void View3DInventorViewer::clearGraphicsItems() +{ + this->graphicsItems.clear(); +} + +void View3DInventorViewer::setRenderType(const RenderType type) +{ + renderType = type; + + glImage = QImage(); + if (type != Framebuffer) { + delete framebuffer; + framebuffer = 0; + } + + switch (type) { + case Native: + break; + case Framebuffer: + if (!framebuffer) { + const SbViewportRegion vp = this->getSoRenderManager()->getViewportRegion(); + SbVec2s size = vp.getViewportSizePixels(); + + QGLWidget* gl = static_cast(this->viewport()); + gl->makeCurrent(); + framebuffer = new QGLFramebufferObject(size[0],size[1],QGLFramebufferObject::Depth); + renderToFramebuffer(framebuffer); + } + break; + case Image: + { + QGLWidget* gl = static_cast(this->viewport()); + gl->makeCurrent(); + int w = gl->width(); + int h = gl->height(); + QImage img(QSize(w,h), QImage::Format_RGB32); + glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); + glImage = img; + } + break; + } +} + +void View3DInventorViewer::renderToFramebuffer(QGLFramebufferObject* fbo) +{ + static_cast(this->viewport())->makeCurrent(); + fbo->bind(); + int width = fbo->size().width(); + int height = fbo->size().height(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LINE_SMOOTH); + + const QColor col = this->backgroundColor(); + glViewport(0, 0, width, height); + glClearColor(col.redF(), col.greenF(), col.blueF(), 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDepthRange(0.1,1.0); + + SoGLRenderAction gl(SbViewportRegion(width, height)); + // When creating a new GL render action we have to copy over the cache context id + // For further details see init(). + uint32_t id = this->getSoRenderManager()->getGLRenderAction()->getCacheContext(); + gl.setCacheContext(id); + gl.setTransparencyType(SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND); + gl.apply(this->backgroundroot); + gl.apply(this->getSoRenderManager()->getSceneGraph()); + gl.apply(this->foregroundroot); + + if (this->axiscrossEnabled) { + this->drawAxisCross(); + } + + fbo->release(); +} + +void View3DInventorViewer::actualRedraw() +{ + switch (renderType) { + case Native: + renderScene(); + break; + case Framebuffer: + renderFramebuffer(); + break; + case Image: + renderGLImage(); + break; + } +} + +void View3DInventorViewer::renderFramebuffer() +{ + const SbViewportRegion vp = this->getSoRenderManager()->getViewportRegion(); + SbVec2s size = vp.getViewportSizePixels(); + + glDisable(GL_LIGHTING); + glViewport(0, 0, size[0], size[1]); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glDisable(GL_DEPTH_TEST); + + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, this->framebuffer->texture()); + glColor3f(1.0, 1.0, 1.0); + + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(-1.0, -1.0f); + glTexCoord2f(1.0f, 0.0f); + glVertex2f(1.0f, -1.0f); + glTexCoord2f(1.0f, 1.0f); + glVertex2f(1.0f, 1.0f); + glTexCoord2f(0.0f, 1.0f); + glVertex2f(-1.0f, 1.0f); + glEnd(); + + printDimension(); + navigation->redraw(); + + for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) + (*it)->paintGL(); + + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +} + +void View3DInventorViewer::renderGLImage() +{ + const SbViewportRegion vp = this->getSoRenderManager()->getViewportRegion(); + SbVec2s size = vp.getViewportSizePixels(); + + glDisable(GL_LIGHTING); + glViewport(0, 0, size[0], size[1]); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, size[0], 0, size[1], 0, 100); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + glClear(GL_COLOR_BUFFER_BIT); + + glRasterPos2f(0,0); + glDrawPixels(glImage.width(),glImage.height(),GL_RGBA,GL_UNSIGNED_BYTE,glImage.bits()); + + printDimension(); + navigation->redraw(); + + for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) + (*it)->paintGL(); + + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +} + +//#define ENABLE_GL_DEPTH_RANGE +// The calls of glDepthRange inside renderScene() causes problems with transparent objects +// so that's why it is disabled now: http://forum.freecadweb.org/viewtopic.php?f=3&t=6037&hilit=transparency + +// Documented in superclass. Overrides this method to be able to draw +// the axis cross, if selected, and to keep a continuous animation +// upon spin. +void View3DInventorViewer::renderScene(void) +{ + // Must set up the OpenGL viewport manually, as upon resize + // operations, Coin won't set it up until the SoGLRenderAction is + // applied again. And since we need to do glClear() before applying + // the action.. + const SbViewportRegion vp = this->getSoRenderManager()->getViewportRegion(); + SbVec2s origin = vp.getViewportOriginPixels(); + SbVec2s size = vp.getViewportSizePixels(); + glViewport(origin[0], origin[1], size[0], size[1]); + + const QColor col = this->backgroundColor(); + glClearColor(col.redF(), col.greenF(), col.blueF(), 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + +#if defined(ENABLE_GL_DEPTH_RANGE) + // using 90% of the z-buffer for the background and the main node + glDepthRange(0.1,1.0); +#endif + + // Render our scenegraph with the image. + SoGLRenderAction* glra = this->getSoRenderManager()->getGLRenderAction(); + SoGLWidgetElement::set(glra->getState(), qobject_cast(this->getGLWidget())); + SoGLRenderActionElement::set(glra->getState(), glra); + glra->apply(this->backgroundroot); + + navigation->updateAnimation(); + + try { + // Render normal scenegraph. + inherited::actualRedraw(); + } + catch(const Base::MemoryException&) { + // FIXME: If this exception appears then the background and camera position get broken somehow. (Werner 2006-02-01) + for (std::set::iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) + (*it)->hide(); + + inherited::actualRedraw(); + QMessageBox::warning(parentWidget(), QObject::tr("Out of memory"), + QObject::tr("Not enough memory available to display the data.")); + } + +#if defined (ENABLE_GL_DEPTH_RANGE) + // using 10% of the z-buffer for the foreground node + glDepthRange(0.0,0.1); +#endif + + // Render overlay front scenegraph. + glra->apply(this->foregroundroot); + + if (this->axiscrossEnabled) { + this->drawAxisCross(); + } + +#if defined (ENABLE_GL_DEPTH_RANGE) + // using the main portion of z-buffer again (for frontbuffer highlighting) + glDepthRange(0.1,1.0); +#endif + + // Immediately reschedule to get continous spin animation. + if (this->isAnimating()) { + this->getSoRenderManager()->scheduleRedraw(); + } + +#if 0 // this breaks highlighting of edges + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); +#endif + + printDimension(); + navigation->redraw(); + + for (std::list::iterator it = this->graphicsItems.begin(); it != this->graphicsItems.end(); ++it) + (*it)->paintGL(); + + //fps rendering + if (fpsEnabled) { + std::stringstream stream; + stream.precision(1); + stream.setf(std::ios::fixed | std::ios::showpoint); + stream << renderTime << " ms / " << 1000./renderTime << " fps"; + draw2DString(stream.str().c_str(), SbVec2s(10,10), SbVec2f(0.1f,0.1f)); + } + +#if 0 // this breaks highlighting of edges + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +#endif +} + +void View3DInventorViewer::setSeekMode(SbBool on) +{ + // Overrides this method to make sure any animations are stopped + // before we go into seek mode. + + // Note: this method is almost identical to the setSeekMode() in the + // SoQtFlyViewer and SoQtPlaneViewer, so migrate any changes. + + if (this->isAnimating()) { + this->stopAnimating(); + } + + inherited::setSeekMode(on); + navigation->setViewingMode(on ? NavigationStyle::SEEK_WAIT_MODE : + (this->isViewing() ? + NavigationStyle::IDLE : NavigationStyle::INTERACT)); +} + +void View3DInventorViewer::printDimension() +{ + SoCamera* cam = getSoRenderManager()->getCamera(); + + if (!cam) return; // no camera there + + SoType t = getSoRenderManager()->getCamera()->getTypeId(); + + if (t.isDerivedFrom(SoOrthographicCamera::getClassTypeId())) { + const SbViewportRegion& vp = getSoRenderManager()->getViewportRegion(); + const SbVec2s& size = vp.getWindowSize(); + short dimX, dimY; + size.getValue(dimX, dimY); + + float fHeight = static_cast(getSoRenderManager()->getCamera())->height.getValue(); + float fWidth = fHeight; + + if (dimX > dimY) + fWidth *= ((float)dimX)/((float)dimY); + else if(dimX < dimY) + fHeight *= ((float)dimY)/((float)dimX); + + float fLog = float(log10(fWidth)), fFac; + int nExp = int(fLog); + QString unit; + + if (nExp >= 6) { + fFac = 1.0e+6f; + unit = QLatin1String("km"); + } + else if (nExp >= 3) { + fFac = 1.0e+3f; + unit = QLatin1String("m"); + } + else if ((nExp >= 0) && (fLog > 0.0f)) { + fFac = 1.0e+0f; + unit = QLatin1String("mm"); + } + else if (nExp >= -3) { + fFac = 1.0e-3f; + unit = QLatin1String("um"); + } + else { + fFac = 1.0e-6f; + unit = QLatin1String("nm"); + } + + QString dim = QString::fromLatin1("%1 x %2 %3") + .arg(fWidth / fFac,0,'f',2) + .arg(fHeight / fFac,0,'f',2) + .arg(unit); + getMainWindow()->setPaneText(2, dim); + } + else + getMainWindow()->setPaneText(2, QLatin1String("")); +} + +void View3DInventorViewer::selectAll() +{ + std::vector objs; + + for (std::set::iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) { + ViewProviderDocumentObject* vp = static_cast(*it); + App::DocumentObject* obj = vp->getObject(); + + if (obj) objs.push_back(obj); + } + } + + if (!objs.empty()) + Gui::Selection().setSelection(objs.front()->getDocument()->getName(), objs); +} + + +bool View3DInventorViewer::processSoEvent(const SoEvent* ev) +{ + if (isRedirectedToSceneGraph()) { + SbBool processed = inherited::processSoEvent(ev); + + if(!processed) + processed = navigation->processEvent(ev); + + return processed; + } + + if (ev->getTypeId().isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { + // filter out 'Q' and 'ESC' keys + const SoKeyboardEvent* const ke = static_cast(ev); + + switch(ke->getKey()) { + case SoKeyboardEvent::ESCAPE: + case SoKeyboardEvent::Q: // ignore 'Q' keys (to prevent app from being closed) + return inherited::processSoEvent(ev); + + default: + break; + } + } + + return navigation->processEvent(ev); +} + +SbBool View3DInventorViewer::processSoEventBase(const SoEvent* const ev) +{ + return inherited::processSoEvent(ev); +} + +SbVec3f View3DInventorViewer::getViewDirection() const +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) return SbVec3f(0,0,-1); // this is the default + + SbRotation camrot = cam->orientation.getValue(); + SbVec3f lookat(0, 0, -1); // init to default view direction vector + camrot.multVec(lookat, lookat); + return lookat; +} + +void View3DInventorViewer::setViewDirection(SbVec3f dir) +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + if (cam) + cam->orientation.setValue(SbRotation(SbVec3f(0, 0, -1), dir)); +} + + +SbVec3f View3DInventorViewer::getUpDirection() const +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) return SbVec3f(0,1,0); + + SbRotation camrot = cam->orientation.getValue(); + SbVec3f upvec(0, 1, 0); // init to default up vector + camrot.multVec(upvec, upvec); + return upvec; +} + +SbRotation View3DInventorViewer::getCameraOrientation() const +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) + return SbRotation(0,0,0,1); // this is the default + + return cam->orientation.getValue(); +} + +SbVec3f View3DInventorViewer::getPointOnScreen(const SbVec2s& pnt) const +{ + const SbViewportRegion& vp = this->getSoRenderManager()->getViewportRegion(); + + short x,y; + pnt.getValue(x,y); + SbVec2f siz = vp.getViewportSize(); + float dX, dY; + siz.getValue(dX, dY); + + float fRatio = vp.getViewportAspectRatio(); + float pX = (float)x / float(vp.getViewportSizePixels()[0]); + float pY = (float)y / float(vp.getViewportSizePixels()[1]); + + // now calculate the real points respecting aspect ratio information + // + if (fRatio > 1.0f) { + pX = (pX - 0.5f*dX) * fRatio + 0.5f*dX; + } + else if(fRatio < 1.0f) { + pY = (pY - 0.5f*dY) / fRatio + 0.5f*dY; + } + + SoCamera* pCam = this->getSoRenderManager()->getCamera(); + + if (!pCam) return SbVec3f(); // return invalid point + + SbViewVolume vol = pCam->getViewVolume(); + + float nearDist = pCam->nearDistance.getValue(); + float farDist = pCam->farDistance.getValue(); + float focalDist = pCam->focalDistance.getValue(); + + if (focalDist < nearDist || focalDist > farDist) + focalDist = 0.5f*(nearDist + farDist); + + SbLine line; + SbVec3f pt; + SbPlane focalPlane = vol.getPlane(focalDist); + vol.projectPointToLine(SbVec2f(pX,pY), line); + focalPlane.intersect(line, pt); + + return pt; +} + +void View3DInventorViewer::getNearPlane(SbVec3f& rcPt, SbVec3f& rcNormal) const +{ + SoCamera* pCam = getSoRenderManager()->getCamera(); + + if (!pCam) return; // just do nothing + + SbViewVolume vol = pCam->getViewVolume(); + + // get the normal of the front clipping plane + SbPlane nearPlane = vol.getPlane(vol.nearDist); + float d = nearPlane.getDistanceFromOrigin(); + rcNormal = nearPlane.getNormal(); + rcNormal.normalize(); + float nx, ny, nz; + rcNormal.getValue(nx, ny, nz); + rcPt.setValue(d*rcNormal[0], d*rcNormal[1], d*rcNormal[2]); +} + +void View3DInventorViewer::getFarPlane(SbVec3f& rcPt, SbVec3f& rcNormal) const +{ + SoCamera* pCam = getSoRenderManager()->getCamera(); + + if (!pCam) return; // just do nothing + + SbViewVolume vol = pCam->getViewVolume(); + + // get the normal of the back clipping plane + SbPlane farPlane = vol.getPlane(vol.nearDist+vol.nearToFar); + float d = farPlane.getDistanceFromOrigin(); + rcNormal = farPlane.getNormal(); + rcNormal.normalize(); + float nx, ny, nz; + rcNormal.getValue(nx, ny, nz); + rcPt.setValue(d*rcNormal[0], d*rcNormal[1], d*rcNormal[2]); +} + +SbVec3f View3DInventorViewer::projectOnNearPlane(const SbVec2f& pt) const +{ + SbVec3f pt1, pt2; + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) return SbVec3f(); // return invalid point + + SbViewVolume vol = cam->getViewVolume(); + vol.projectPointToLine(pt, pt1, pt2); + return pt1; +} + +SbVec3f View3DInventorViewer::projectOnFarPlane(const SbVec2f& pt) const +{ + SbVec3f pt1, pt2; + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) return SbVec3f(); // return invalid point + + SbViewVolume vol = cam->getViewVolume(); + vol.projectPointToLine(pt, pt1, pt2); + return pt2; +} + +void View3DInventorViewer::toggleClippingPlane() +{ + if (pcViewProviderRoot->getNumChildren() > 0 && + pcViewProviderRoot->getChild(0)->getTypeId() == + SoClipPlaneManip::getClassTypeId()) { + pcViewProviderRoot->removeChild(0); + } + else { + SoClipPlaneManip* clip = new SoClipPlaneManip; + SoGetBoundingBoxAction action(this->getSoRenderManager()->getViewportRegion()); + action.apply(this->getSoRenderManager()->getSceneGraph()); + SbBox3f box = action.getBoundingBox(); + + if (!box.isEmpty()) { + // adjust to overall bounding box of the scene + clip->setValue(box, SbVec3f(0.0f,0.0f,1.0f), 1.0f); + } + + pcViewProviderRoot->insertChild(clip,0); + } +} + +bool View3DInventorViewer::hasClippingPlane() const +{ + if (pcViewProviderRoot && pcViewProviderRoot->getNumChildren() > 0) { + return (pcViewProviderRoot->getChild(0)->getTypeId() + == SoClipPlaneManip::getClassTypeId()); + } + + return false; +} + +/** + * This method picks the closest point to the camera in the underlying scenegraph + * and returns its location and normal. + * If no point was picked false is returned. + */ +bool View3DInventorViewer::pickPoint(const SbVec2s& pos,SbVec3f& point,SbVec3f& norm) const +{ + // attempting raypick in the event_cb() callback method + SoRayPickAction rp(getSoRenderManager()->getViewportRegion()); + rp.setPoint(pos); + rp.apply(getSoRenderManager()->getSceneGraph()); + SoPickedPoint* Point = rp.getPickedPoint(); + + if (Point) { + point = Point->getObjectPoint(); + norm = Point->getObjectNormal(); + return true; + } + + return false; +} + +/** + * This method is provided for convenience and does basically the same as method + * above unless that it returns an SoPickedPoint object with additional information. + * \note It is in the response of the client programmer to delete the returned + * SoPickedPoint object. + */ +SoPickedPoint* View3DInventorViewer::pickPoint(const SbVec2s& pos) const +{ + SoRayPickAction rp(getSoRenderManager()->getViewportRegion()); + rp.setPoint(pos); + rp.apply(getSoRenderManager()->getSceneGraph()); + + // returns a copy of the point + SoPickedPoint* pick = rp.getPickedPoint(); + //return (pick ? pick->copy() : 0); // needs the same instance of CRT under MS Windows + return (pick ? new SoPickedPoint(*pick) : 0); +} + +const SoPickedPoint* View3DInventorViewer::getPickedPoint(SoEventCallback* n) const +{ + if (selectionRoot) + return selectionRoot->getPickedPoint(n->getAction()); + else + return n->getPickedPoint(); +} + +SbBool View3DInventorViewer::pubSeekToPoint(const SbVec2s& pos) +{ + return this->seekToPoint(pos); +} + +void View3DInventorViewer::pubSeekToPoint(const SbVec3f& pos) +{ + this->seekToPoint(pos); +} + +void View3DInventorViewer::setCameraOrientation(const SbRotation& rot, SbBool moveTocenter) +{ + navigation->setCameraOrientation(rot, moveTocenter); +} + +void View3DInventorViewer::setCameraType(SoType t) +{ + inherited::setCameraType(t); + + if (t.isDerivedFrom(SoPerspectiveCamera::getClassTypeId())) { + // When doing a viewAll() for an orthographic camera and switching + // to perspective the scene looks completely strange because of the + // heightAngle. Setting it to 45 deg also causes an issue with a too + // close camera but we don't have this other ugly effect. + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if(cam == 0) return; + + static_cast(cam)->heightAngle = (float)(M_PI / 4.0); + } +} + +void View3DInventorViewer::moveCameraTo(const SbRotation& rot, const SbVec3f& pos, int steps, int ms) +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (cam == 0) return; + + SbVec3f campos = cam->position.getValue(); + SbRotation camrot = cam->orientation.getValue(); + + QEventLoop loop; + QTimer timer; + timer.setSingleShot(true); + QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + + for (int i=0; iorientation.setValue(currot); + cam->position.setValue(curpos); + timer.start(Base::clamp(ms,0,5000)); + loop.exec(QEventLoop::ExcludeUserInputEvents); + } + + cam->orientation.setValue(rot); + cam->position.setValue(pos); +} + +void View3DInventorViewer::animatedViewAll(int steps, int ms) +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) + return; + + SbVec3f campos = cam->position.getValue(); + SbRotation camrot = cam->orientation.getValue(); + SbViewportRegion vp = this->getSoRenderManager()->getViewportRegion(); + SoGetBoundingBoxAction action(vp); + action.apply(this->getSoRenderManager()->getSceneGraph()); + SbBox3f box = action.getBoundingBox(); + +#if (COIN_MAJOR_VERSION >= 3) + float aspectRatio = vp.getViewportAspectRatio(); +#endif + + if (box.isEmpty()) + return; + + SbSphere sphere; + sphere.circumscribe(box); + + SbVec3f direction, pos; + camrot.multVec(SbVec3f(0, 0, -1), direction); + + bool isOrthographic = false; + float height = 0; + float diff = 0; + + if (cam->isOfType(SoOrthographicCamera::getClassTypeId())) { + isOrthographic = true; + height = static_cast(cam)->height.getValue(); +#if (COIN_MAJOR_VERSION >= 3) + if (aspectRatio < 1.0f) + diff = sphere.getRadius() * 2 - height * aspectRatio; + else +#endif + diff = sphere.getRadius() * 2 - height; + pos = (box.getCenter() - direction * sphere.getRadius()); + } + else if (cam->isOfType(SoPerspectiveCamera::getClassTypeId())) { + float movelength = sphere.getRadius()/float(tan(static_cast + (cam)->heightAngle.getValue() / 2.0)); + pos = box.getCenter() - direction * movelength; + } + + QEventLoop loop; + QTimer timer; + timer.setSingleShot(true); + QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + + for (int i=0; i(cam)->height.setValue(camHeight); + } + + SbVec3f curpos = campos * (1.0f-s) + pos * s; + cam->position.setValue(curpos); + timer.start(Base::clamp(ms,0,5000)); + loop.exec(QEventLoop::ExcludeUserInputEvents); + } +} + +#if BUILD_VR +extern View3DInventorRiftViewer* oculusStart(void); +extern bool oculusUp (void); +extern void oculusStop (void); +void oculusSetTestScene(View3DInventorRiftViewer *window); +#endif + +void View3DInventorViewer::viewVR(void) +{ +#if BUILD_VR +<<<<<<< b5cee108f51944ec0e4e42f663a543f235e65665 + if (oculusUp()) { + oculusStop(); + } + else { +======= + if(oculusUp()) + oculusStop(); + else{ +>>>>>>> make SoFCUnifiedSelection work with nested children in 3DView + View3DInventorRiftViewer* riftWin = oculusStart(); + riftWin->setSceneGraph(pcViewProviderRoot); + } +#endif +} + +void View3DInventorViewer::boxZoom(const SbBox2s& box) +{ + navigation->boxZoom(box); +} + +void View3DInventorViewer::viewAll() +{ + // in the scene graph we may have objects which we want to exlcude + // when doing a fit all. Such objects must be part of the group + // SoSkipBoundingGroup. + SoSearchAction sa; + sa.setType(SoSkipBoundingGroup::getClassTypeId()); + sa.setInterest(SoSearchAction::ALL); + sa.apply(this->getSoRenderManager()->getSceneGraph()); + const SoPathList& pathlist = sa.getPaths(); + + for (int i = 0; i < pathlist.getLength(); i++) { + SoPath* path = pathlist[i]; + SoSkipBoundingGroup* group = static_cast(path->getTail()); + group->mode = SoSkipBoundingGroup::EXCLUDE_BBOX; + } + + // Set the height angle to 45 deg + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (cam && cam->getTypeId().isDerivedFrom(SoPerspectiveCamera::getClassTypeId())) + static_cast(cam)->heightAngle = (float)(M_PI / 4.0); + + if (isAnimationEnabled()) + animatedViewAll(10, 20); + + // make sure everything is visible + if (cam) + cam->viewAll(getSoRenderManager()->getSceneGraph(), this->getSoRenderManager()->getViewportRegion()); + + for (int i = 0; i < pathlist.getLength(); i++) { + SoPath* path = pathlist[i]; + SoSkipBoundingGroup* group = static_cast(path->getTail()); + group->mode = SoSkipBoundingGroup::INCLUDE_BBOX; + } +} + +void View3DInventorViewer::viewAll(float factor) +{ + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + if (!cam) return; + + if (factor <= 0.0f) return; + + if (factor != 1.0f) { + SoSearchAction sa; + sa.setType(SoSkipBoundingGroup::getClassTypeId()); + sa.setInterest(SoSearchAction::ALL); + sa.apply(this->getSoRenderManager()->getSceneGraph()); + const SoPathList& pathlist = sa.getPaths(); + + for(int i = 0; i < pathlist.getLength(); i++) { + SoPath* path = pathlist[i]; + SoSkipBoundingGroup* group = static_cast(path->getTail()); + group->mode = SoSkipBoundingGroup::EXCLUDE_BBOX; + } + + SoGetBoundingBoxAction action(this->getSoRenderManager()->getViewportRegion()); + action.apply(this->getSoRenderManager()->getSceneGraph()); + SbBox3f box = action.getBoundingBox(); + float minx,miny,minz,maxx,maxy,maxz; + box.getBounds(minx,miny,minz,maxx,maxy,maxz); + + for (int i = 0; i < pathlist.getLength(); i++) { + SoPath* path = pathlist[i]; + SoSkipBoundingGroup* group = static_cast(path->getTail()); + group->mode = SoSkipBoundingGroup::INCLUDE_BBOX; + } + + SoCube* cube = new SoCube(); + cube->width = factor*(maxx-minx); + cube->height = factor*(maxy-miny); + cube->depth = factor*(maxz-minz); + + // fake a scenegraph with the desired bounding size + SoSeparator* graph = new SoSeparator(); + graph->ref(); + SoTranslation* tr = new SoTranslation(); + tr->translation.setValue(box.getCenter()); + + graph->addChild(tr); + graph->addChild(cube); + cam->viewAll(graph, this->getSoRenderManager()->getViewportRegion()); + graph->unref(); + } + else { + viewAll(); + } +} + +void View3DInventorViewer::viewSelection() +{ +#if 0 + // Search for all SoFCSelection nodes + SoSearchAction searchAction; + searchAction.setType(SoFCSelection::getClassTypeId()); + searchAction.setInterest(SoSearchAction::ALL); + searchAction.apply(pcViewProviderRoot); + + SoPathList& paths = searchAction.getPaths(); + int countPaths = paths.getLength(); + + SoGroup* root = new SoGroup(); + root->ref(); + + for(int i=0; igetTail(); + + if (!node || node->getTypeId() != SoFCSelection::getClassTypeId()) + continue; // should not happen + + SoFCSelection* select = static_cast(node); + + // Check only document and object name but not sub-element name + if (Selection().isSelected(select->documentName.getValue().getString(), + select->objectName.getValue().getString())) { + root->addChild(select); + } + } + +#else + SoGroup* root = new SoGroup(); + root->ref(); + + std::vector selection = Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + + for (std::vector::iterator it = selection.begin(); it != selection.end(); ++it) { + ViewProvider* vp = Application::Instance->getViewProvider(*it); + + if (vp) { + root->addChild(vp->getRoot()); + } + } + +#endif + + SoCamera* cam = this->getSoRenderManager()->getCamera(); + if (cam) + cam->viewAll(root, this->getSoRenderManager()->getViewportRegion()); + + root->unref(); +} + +/*! + Decide if it should be possible to start a spin animation of the + model in the viewer by releasing the mouse button while dragging. + + If the \a enable flag is \c false and we're currently animating, the + spin will be stopped. +*/ +void +View3DInventorViewer::setAnimationEnabled(const SbBool enable) +{ + navigation->setAnimationEnabled(enable); +} + +/*! + Query whether or not it is possible to start a spinning animation by + releasing the left mouse button while dragging the mouse. +*/ + +SbBool +View3DInventorViewer::isAnimationEnabled(void) const +{ + return navigation->isAnimationEnabled(); +} + +/*! + Query if the model in the viewer is currently in spinning mode after + a user drag. +*/ +SbBool View3DInventorViewer::isAnimating(void) const +{ + return navigation->isAnimating(); +} + +/*! + * Starts programmatically the viewer in animation mode. The given axis direction + * is always in screen coordinates, not in world coordinates. + */ +void View3DInventorViewer::startAnimating(const SbVec3f& axis, float velocity) +{ + navigation->startAnimating(axis, velocity); +} + +void View3DInventorViewer::stopAnimating(void) +{ + navigation->stopAnimating(); +} + +void View3DInventorViewer::setPopupMenuEnabled(const SbBool on) +{ + navigation->setPopupMenuEnabled(on); +} + +SbBool View3DInventorViewer::isPopupMenuEnabled(void) const +{ + return navigation->isPopupMenuEnabled(); +} + +/*! + Set the flag deciding whether or not to show the axis cross. +*/ + +void +View3DInventorViewer::setFeedbackVisibility(const SbBool enable) +{ + if (enable == this->axiscrossEnabled) { + return; + } + + this->axiscrossEnabled = enable; + + if (this->isViewing()) { + this->getSoRenderManager()->scheduleRedraw(); + } +} + +/*! + Check if the feedback axis cross is visible. +*/ + +SbBool +View3DInventorViewer::isFeedbackVisible(void) const +{ + return this->axiscrossEnabled; +} + +/*! + Set the size of the feedback axiscross. The value is interpreted as + an approximate percentage chunk of the dimensions of the total + canvas. +*/ +void +View3DInventorViewer::setFeedbackSize(const int size) +{ + if (size < 1) { + return; + } + + this->axiscrossSize = size; + + if (this->isFeedbackVisible() && this->isViewing()) { + this->getSoRenderManager()->scheduleRedraw(); + } +} + +/*! + Return the size of the feedback axis cross. Default is 10. +*/ + +int +View3DInventorViewer::getFeedbackSize(void) const +{ + return this->axiscrossSize; +} + +/*! + Decide whether or not the mouse pointer cursor should be visible in + the rendering canvas. +*/ +void View3DInventorViewer::setCursorEnabled(SbBool enable) +{ + this->setCursorRepresentation(navigation->getViewingMode()); +} + +void View3DInventorViewer::afterRealizeHook(void) +{ + inherited::afterRealizeHook(); + this->setCursorRepresentation(navigation->getViewingMode()); +} + +// Documented in superclass. This method overridden from parent class +// to make sure the mouse pointer cursor is updated. +void View3DInventorViewer::setViewing(SbBool enable) +{ + + if (this->isViewing() == enable) { + return; + } + + navigation->setViewingMode(enable ? + NavigationStyle::IDLE : NavigationStyle::INTERACT); + inherited::setViewing(enable); +} + +//**************************************************************************** + +// Bitmap representations of an "X", a "Y" and a "Z" for the axis cross. +static GLubyte xbmp[] = { 0x11,0x11,0x0a,0x04,0x0a,0x11,0x11 }; +static GLubyte ybmp[] = { 0x04,0x04,0x04,0x04,0x0a,0x11,0x11 }; +static GLubyte zbmp[] = { 0x1f,0x10,0x08,0x04,0x02,0x01,0x1f }; + +void View3DInventorViewer::drawAxisCross(void) +{ + // FIXME: convert this to a superimposition scenegraph instead of + // OpenGL calls. 20020603 mortene. + + // Store GL state. + glPushAttrib(GL_ALL_ATTRIB_BITS); + GLfloat depthrange[2]; + glGetFloatv(GL_DEPTH_RANGE, depthrange); + GLdouble projectionmatrix[16]; + glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix); + + glDepthFunc(GL_ALWAYS); + glDepthMask(GL_TRUE); + glDepthRange(0, 0); + glEnable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + glDisable(GL_BLEND); // Kills transparency. + + // Set the viewport in the OpenGL canvas. Dimensions are calculated + // as a percentage of the total canvas size. + SbVec2s view = this->getSoRenderManager()->getSize(); + const int pixelarea = + int(float(this->axiscrossSize)/100.0f * std::min(view[0], view[1])); +#if 0 // middle of canvas + SbVec2s origin(view[0]/2 - pixelarea/2, view[1]/2 - pixelarea/2); +#endif // middle of canvas +#if 1 // lower right of canvas + SbVec2s origin(view[0] - pixelarea, 0); +#endif // lower right of canvas + glViewport(origin[0], origin[1], pixelarea, pixelarea); + + // Set up the projection matrix. + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + const float NEARVAL = 0.1f; + const float FARVAL = 10.0f; + const float dim = NEARVAL * float(tan(M_PI / 8.0)); // FOV is 45? (45/360 = 1/8) + glFrustum(-dim, dim, -dim, dim, NEARVAL, FARVAL); + + + // Set up the model matrix. + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + SbMatrix mx; + SoCamera* cam = this->getSoRenderManager()->getCamera(); + + // If there is no camera (like for an empty scene, for instance), + // just use an identity rotation. + if (cam) { + mx = cam->orientation.getValue(); + } + else { + mx = SbMatrix::identity(); + } + + mx = mx.inverse(); + mx[3][2] = -3.5; // Translate away from the projection point (along z axis). + glLoadMatrixf((float*)mx); + + + // Find unit vector end points. + SbMatrix px; + glGetFloatv(GL_PROJECTION_MATRIX, (float*)px); + SbMatrix comb = mx.multRight(px); + + SbVec3f xpos; + comb.multVecMatrix(SbVec3f(1,0,0), xpos); + xpos[0] = (1 + xpos[0]) * view[0]/2; + xpos[1] = (1 + xpos[1]) * view[1]/2; + SbVec3f ypos; + comb.multVecMatrix(SbVec3f(0,1,0), ypos); + ypos[0] = (1 + ypos[0]) * view[0]/2; + ypos[1] = (1 + ypos[1]) * view[1]/2; + SbVec3f zpos; + comb.multVecMatrix(SbVec3f(0,0,1), zpos); + zpos[0] = (1 + zpos[0]) * view[0]/2; + zpos[1] = (1 + zpos[1]) * view[1]/2; + + + // Render the cross. + { + glLineWidth(2.0); + + enum { XAXIS, YAXIS, ZAXIS }; + int idx[3] = { XAXIS, YAXIS, ZAXIS }; + float val[3] = { xpos[2], ypos[2], zpos[2] }; + + // Bubble sort.. :-} + if (val[0] < val[1]) { + std::swap(val[0], val[1]); + std::swap(idx[0], idx[1]); + } + + if (val[1] < val[2]) { + std::swap(val[1], val[2]); + std::swap(idx[1], idx[2]); + } + + if (val[0] < val[1]) { + std::swap(val[0], val[1]); + std::swap(idx[0], idx[1]); + } + + assert((val[0] >= val[1]) && (val[1] >= val[2])); // Just checking.. + + for(int i=0; i < 3; i++) { + glPushMatrix(); + + if (idx[i] == XAXIS) { // X axis. + if(stereoMode() != Quarter::SoQTQuarterAdaptor::MONO) + glColor3f(0.500f, 0.5f, 0.5f); + else + glColor3f(0.500f, 0.125f, 0.125f); + } + else if (idx[i] == YAXIS) { // Y axis. + glRotatef(90, 0, 0, 1); + + if (stereoMode() != Quarter::SoQTQuarterAdaptor::MONO) + glColor3f(0.400f, 0.4f, 0.4f); + else + glColor3f(0.125f, 0.500f, 0.125f); + } + else { // Z axis. + glRotatef(-90, 0, 1, 0); + + if (stereoMode() != Quarter::SoQTQuarterAdaptor::MONO) + glColor3f(0.300f, 0.3f, 0.3f); + else + glColor3f(0.125f, 0.125f, 0.500f); + } + + this->drawArrow(); + glPopMatrix(); + } + } + + // Render axis notation letters ("X", "Y", "Z"). + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, view[0], 0, view[1], -1, 1); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLint unpack; + glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + if (stereoMode() != Quarter::SoQTQuarterAdaptor::MONO) + glColor3fv(SbVec3f(1.0f, 1.0f, 1.0f).getValue()); + else + glColor3fv(SbVec3f(0.0f, 0.0f, 0.0f).getValue()); + + glRasterPos2d(xpos[0], xpos[1]); + glBitmap(8, 7, 0, 0, 0, 0, xbmp); + glRasterPos2d(ypos[0], ypos[1]); + glBitmap(8, 7, 0, 0, 0, 0, ybmp); + glRasterPos2d(zpos[0], zpos[1]); + glBitmap(8, 7, 0, 0, 0, 0, zbmp); + + glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); + glPopMatrix(); + + // Reset original state. + + // FIXME: are these 3 lines really necessary, as we push + // GL_ALL_ATTRIB_BITS at the start? 20000604 mortene. + glDepthRange(depthrange[0], depthrange[1]); + glMatrixMode(GL_PROJECTION); + glLoadMatrixd(projectionmatrix); + + glPopAttrib(); +} + +// Draw an arrow for the axis representation directly through OpenGL. +void View3DInventorViewer::drawArrow(void) +{ + glBegin(GL_LINES); + glVertex3f(0.0f, 0.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 0.0f); + glEnd(); + glDisable(GL_CULL_FACE); + glBegin(GL_TRIANGLES); + glVertex3f(1.0f, 0.0f, 0.0f); + glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f); + glVertex3f(1.0f - 1.0f / 3.0f, -0.5f / 4.0f, 0.0f); + glVertex3f(1.0f, 0.0f, 0.0f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, +0.5f / 4.0f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, -0.5f / 4.0f); + glEnd(); + glBegin(GL_QUADS); + glVertex3f(1.0f - 1.0f / 3.0f, +0.5f / 4.0f, 0.0f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, +0.5f / 4.0f); + glVertex3f(1.0f - 1.0f / 3.0f, -0.5f / 4.0f, 0.0f); + glVertex3f(1.0f - 1.0f / 3.0f, 0.0f, -0.5f / 4.0f); + glEnd(); +} + +// ************************************************************************ +#if 0 +#define HAND_WITH 24 +#define HAND_HEIGHT 24 +#define HAND_HOT_X 9 +#define HAND_HOT_Y 0 + +static unsigned char hand_bitmap[] = { + 0x00,0x03,0x00,0x80,0x04,0x00,0x80,0x04,0x00,0x80,0x04,0x00,0x80,0x04,0x00, + 0x80,0x1c,0x00,0x80,0xe4,0x00,0x80,0x24,0x01,0x80,0x24,0x07,0x8e,0x24,0x09, + 0x92,0x24,0x09,0xa4,0x00,0x09,0xc4,0x00,0x08,0x08,0x00,0x08,0x08,0x00,0x08, + 0x10,0x00,0x08,0x10,0x00,0x04,0x20,0x00,0x04,0x20,0x00,0x04,0x40,0x00,0x02, + 0x80,0x00,0x02,0x00,0x01,0x01,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0xab,0xab, + 0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02, + 0x00,0x1b,0x00,0xee,0x04,0xee +}; + +static unsigned char hand_mask_bitmap[] = { + 0x00,0x03,0x00,0x80,0x07,0x00,0x80,0x07,0x00,0x80,0x07,0x00,0x80,0x07,0x00, + 0x80,0x1f,0x00,0x80,0xff,0x00,0x80,0xff,0x01,0x80,0xff,0x07,0x8e,0xff,0x0f, + 0x9e,0xff,0x0f,0xbc,0xff,0x0f,0xfc,0xff,0x0f,0xf8,0xff,0x0f,0xf8,0xff,0x0f, + 0xf0,0xff,0x0f,0xf0,0xff,0x07,0xe0,0xff,0x07,0xe0,0xff,0x07,0xc0,0xff,0x03, + 0x80,0xff,0x03,0x00,0xff,0x01,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0xab,0xab, + 0xab,0xab,0xab,0xab,0xab,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05, + 0x00,0x1b,0x00,0xd5,0x07,0x1c +}; + +#define CROSS_WIDTH 16 +#define CROSS_HEIGHT 16 +#define CROSS_HOT_X 7 +#define CROSS_HOT_Y 7 + +static unsigned char cross_bitmap[] = { + 0xc0, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, + 0x40, 0x02, 0x40, 0x02, 0x7f, 0xfe, 0x01, 0x80, + 0x01, 0x80, 0x7f, 0xfe, 0x40, 0x02, 0x40, 0x02, + 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xc0, 0x03 +}; + +static unsigned char cross_mask_bitmap[] = { + 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, + 0xc0, 0x03, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xc0, 0x03, + 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03 +}; +#endif +// Set cursor graphics according to mode. +void View3DInventorViewer::setCursorRepresentation(int modearg) +{ + // There is a synchronization problem between Qt and SoQt which + // happens when popping up a context-menu. In this case the + // Qt::WA_UnderMouse attribute is resetted and never set again + // even if the mouse is still in the canvas. Thus, the cursor + // won't be changed as long as the user doesn't leave and enter + // the canvas. To fix this we explicitly set Qt::WA_UnderMouse + // if the mouse is inside the canvas. + QWidget* w = this->getGLWidget(); + + if (w && w->rect().contains(QCursor::pos())) + w->setAttribute(Qt::WA_UnderMouse); + + switch(modearg) { + case NavigationStyle::IDLE: + case NavigationStyle::INTERACT: + if(isEditing()) + this->getWidget()->setCursor(this->editCursor); + else + this->getWidget()->setCursor(QCursor(Qt::ArrowCursor)); + + break; + + case NavigationStyle::DRAGGING: + case NavigationStyle::SPINNING: + this->getWidget()->setCursor(spinCursor); + break; + + case NavigationStyle::ZOOMING: + { + this->getWidget()->setCursor(zoomCursor); + } + break; + + case NavigationStyle::SEEK_MODE: + case NavigationStyle::SEEK_WAIT_MODE: + case NavigationStyle::BOXZOOM: + { + this->getWidget()->setCursor(Qt::CrossCursor); + } + break; + + case NavigationStyle::PANNING: + this->getWidget()->setCursor(panCursor); + break; + + case NavigationStyle::SELECTION: + { + this->getWidget()->setCursor(Qt::PointingHandCursor); + } + break; + + default: + assert(0); + break; + } +} + +void View3DInventorViewer::setEditing(SbBool edit) +{ + this->editing = edit; + this->getWidget()->setCursor(QCursor(Qt::ArrowCursor)); + this->editCursor = QCursor(); +} + +void View3DInventorViewer::setEditingCursor(const QCursor& cursor) +{ + this->getWidget()->setCursor(cursor); + this->editCursor = this->getWidget()->cursor(); +} + +void View3DInventorViewer::setComponentCursor(QCursor cursor) +{ + this->getWidget()->setCursor(cursor); +} + + +void View3DInventorViewer::selectCB(void* viewer, SoPath* path) +{ + ViewProvider* vp = static_cast(viewer)->getViewProviderByPath(path); + + if (vp && vp->useNewSelectionModel()) { + } +} + +void View3DInventorViewer::deselectCB(void* viewer, SoPath* path) +{ + ViewProvider* vp = static_cast(viewer)->getViewProviderByPath(path); + + if (vp && vp->useNewSelectionModel()) { + } +} + +SoPath* View3DInventorViewer::pickFilterCB(void* viewer, const SoPickedPoint* pp) +{ + ViewProvider* vp = static_cast(viewer)->getViewProviderByPath(pp->getPath()); + + if (vp && vp->useNewSelectionModel()) { + std::string e = vp->getElement(pp->getDetail()); + vp->getSelectionShape(e.c_str()); + static char buf[513]; + snprintf(buf,512,"Hovered: %s (%f,%f,%f)" + ,e.c_str() + ,pp->getPoint()[0] + ,pp->getPoint()[1] + ,pp->getPoint()[2]); + + getMainWindow()->showMessage(QString::fromLatin1(buf),3000); + } + + return pp->getPath(); +} + +void View3DInventorViewer::addEventCallback(SoType eventtype, SoEventCallbackCB* cb, void* userdata) +{ + pEventCallback->addEventCallback(eventtype, cb, userdata); +} + +void View3DInventorViewer::removeEventCallback(SoType eventtype, SoEventCallbackCB* cb, void* userdata) +{ + pEventCallback->removeEventCallback(eventtype, cb, userdata); +} + +ViewProvider* View3DInventorViewer::getViewProviderByPath(SoPath* path) const +{ + // FIXME Use the viewprovider map introduced for the selection + for(std::set::const_iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) { + for(int i = 0; igetLength(); i++) { + SoNode* node = path->getNode(i); + + if ((*it)->getRoot() == node) { + return (*it); + } + } + } + + return 0; +} + +ViewProvider* View3DInventorViewer::getViewProviderByPathFromTail(SoPath* path) const +{ + // Make sure I'm the lowest LocHL in the pick path! + for(int i = 0; i < path->getLength(); i++) { + SoNode* node = path->getNodeFromTail(i); + + if (node->isOfType(SoSeparator::getClassTypeId())) { + std::map::const_iterator it = _ViewProviderMap.find(static_cast(node)); + + if (it != _ViewProviderMap.end()) { + return it->second; + } + } + } + + return 0; +} + +std::vector View3DInventorViewer::getViewProvidersOfType(const Base::Type& typeId) const +{ + std::vector views; + + for(std::set::const_iterator it = _ViewProviderSet.begin(); it != _ViewProviderSet.end(); ++it) { + if((*it)->getTypeId().isDerivedFrom(typeId)) { + views.push_back(*it); + } + } + + return views; +} + +void View3DInventorViewer::turnAllDimensionsOn() +{ + dimensionRoot->whichChild = SO_SWITCH_ALL; +} + +void View3DInventorViewer::turnAllDimensionsOff() +{ + dimensionRoot->whichChild = SO_SWITCH_NONE; +} + +void View3DInventorViewer::eraseAllDimensions() +{ + static_cast(dimensionRoot->getChild(0))->removeAllChildren(); + static_cast(dimensionRoot->getChild(1))->removeAllChildren(); +} + +void View3DInventorViewer::turn3dDimensionsOn() +{ + static_cast(dimensionRoot->getChild(0))->whichChild = SO_SWITCH_ALL; +} + +void View3DInventorViewer::turn3dDimensionsOff() +{ + static_cast(dimensionRoot->getChild(0))->whichChild = SO_SWITCH_NONE; +} + +void View3DInventorViewer::addDimension3d(SoNode* node) +{ + static_cast(dimensionRoot->getChild(0))->addChild(node); +} + +void View3DInventorViewer::addDimensionDelta(SoNode* node) +{ + static_cast(dimensionRoot->getChild(1))->addChild(node); +} + +void View3DInventorViewer::turnDeltaDimensionsOn() +{ + static_cast(dimensionRoot->getChild(1))->whichChild = SO_SWITCH_ALL; +} + +void View3DInventorViewer::turnDeltaDimensionsOff() +{ + static_cast(dimensionRoot->getChild(1))->whichChild = SO_SWITCH_NONE; +} + +PyObject *View3DInventorViewer::getPyObject(void) +{ + if (!_viewerPy) + _viewerPy = new View3DInventorViewerPy(this); + + Py_INCREF(_viewerPy); + return _viewerPy; +} diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index 1c37d88bc604..b0fb28537c87 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -341,7 +341,7 @@ class GuiExport View3DInventorViewer : public Quarter::SoQTQuarterAdaptor, publi NavigationStyle* navigationStyle() const; void setDocument(Gui::Document *pcDocument); - + virtual PyObject *getPyObject(void); protected: From b825571562eb117c1f20dc6663ba01ed60ab58c9 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 5 May 2012 14:37:56 +0200 Subject: [PATCH 026/664] implement active body in PartDesign --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 51 +++++++++++- src/Mod/Assembly/App/AppAssemblyPy.cpp.orig | 86 +++++++++++++++++++++ src/Mod/Assembly/Gui/Command.cpp | 28 +++---- src/Mod/Assembly/Gui/Workbench.cpp | 2 + src/Mod/Part/App/AppPart.cpp | 4 +- src/Mod/Part/App/{Body.cpp => BodyBase.cpp} | 12 ++- src/Mod/Part/App/{Body.h => BodyBase.h} | 14 ++-- src/Mod/Part/App/BodyBasePy.xml | 17 ++++ src/Mod/Part/App/BodyBasePyImp.cpp | 29 +++++++ src/Mod/Part/App/CMakeLists.txt | 7 +- src/Mod/PartDesign/App/Body.cpp | 2 +- src/Mod/PartDesign/App/Body.h | 4 +- src/Mod/PartDesign/App/BodyPy.xml | 17 ++++ src/Mod/PartDesign/App/BodyPyImp.cpp | 30 +++++++ src/Mod/PartDesign/App/CMakeLists.txt | 14 ++++ 15 files changed, 281 insertions(+), 36 deletions(-) create mode 100644 src/Mod/Assembly/App/AppAssemblyPy.cpp.orig rename src/Mod/Part/App/{Body.cpp => BodyBase.cpp} (88%) rename src/Mod/Part/App/{Body.h => BodyBase.h} (88%) create mode 100644 src/Mod/Part/App/BodyBasePy.xml create mode 100644 src/Mod/Part/App/BodyBasePyImp.cpp create mode 100644 src/Mod/PartDesign/App/BodyPy.xml create mode 100644 src/Mod/PartDesign/App/BodyPyImp.cpp diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 5d2997e5e070..7be456d55b07 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -22,11 +22,58 @@ #include "PreCompiled.h" -#ifndef _PreComp_ -# include +#ifndef _PreComp_ +# include #endif +#include +#include + +#include +#include +#include +#include + +#include + +// pointer to the active assembly object +PartDesign::Body *ActivePartObject =0; +Gui::Document *ActiveGuiDoc =0; +Gui::ViewProviderDocumentObject *ActiveVp =0; + + + +static PyObject * setActivePart(PyObject *self, PyObject *args) +{ + PyObject *object=0; + if (PyArg_ParseTuple(args,"|O!",&(PartDesign::BodyPy::Type), &object)&& object) { + PartDesign::Body* Item = static_cast(object)->getBodyPtr(); + // Should be set! + assert(Item); + + // get the gui document of the Assembly Item + if(ActivePartObject){ + + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); + ActivePartObject = 0; + + } + ActivePartObject = Item; + ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); + ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); + + }else{ + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); + ActivePartObject = 0; + } + + Py_Return; +} /* registration table */ struct PyMethodDef Assembly_methods[] = { + {"setActivePart" ,setActivePart ,METH_VARARGS, + "setActivePart(BodyObject) -- Set the PartBody object in work."}, + {NULL, NULL} /* end of table marker */ }; diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig b/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig new file mode 100644 index 000000000000..fa76945b129e --- /dev/null +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig @@ -0,0 +1,86 @@ +/*************************************************************************** + * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * * + * 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 +#endif + +<<<<<<< 8ef3abc971814e64ef79a85812dd1a5827ba955f:src/Mod/Assembly/App/AppAssemblyPy.cpp +/* registration table */ +struct PyMethodDef Assembly_methods[] = { + {NULL, NULL} /* end of table marker */ +======= +#include +#include + +#include +#include +#include +#include + +#include + +// pointer to the active assembly object +PartDesign::Body *ActivePartObject =0; +Gui::Document *ActiveGuiDoc =0; +Gui::ViewProviderDocumentObject *ActiveVp =0; + + + +static PyObject * setActivePart(PyObject *self, PyObject *args) +{ + PyObject *object=0; + if (PyArg_ParseTuple(args,"|O!",&(PartDesign::BodyPy::Type), &object)&& object) { + PartDesign::Body* Item = static_cast(object)->getBodyPtr(); + // Should be set! + assert(Item); + + // get the gui document of the Assembly Item + if(ActivePartObject){ + + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); + ActivePartObject = 0; + + } + ActivePartObject = Item; + ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); + ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); + + }else{ + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); + ActivePartObject = 0; + } + + Py_Return; +} + +/* registration table */ +struct PyMethodDef PartDesignGui_Import_methods[] = { + {"setActivePart" ,setActivePart ,METH_VARARGS, + "setActivePart(BodyObject) -- Set the PartBody object in work."}, + + {NULL, NULL} /* end of table marker */ +>>>>>>> implement active body in PartDesign:src/Mod/PartDesign/Gui/AppPartDesignGuiPy.cpp +}; diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index b626b2e66b80..6397d6ae084b 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -82,27 +82,29 @@ void CmdAssemblyAddNewPart::activated(int iMsg) Command::addModule(App,"PartDesign"); Command::addModule(Gui,"PartDesignGui"); -#if 1 // test code for children nesting - Command::addModule(App,"Part"); - std::string BodyName = getUniqueObjectName("Box"); - doCommand(Doc,"App.activeDocument().addObject('Part::Box','%s')",BodyName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); -#else std::string BodyName = getUniqueObjectName("Body"); // add the standard planes std::string Plane1Name = BodyName + "_PlaneXY"; std::string Plane2Name = BodyName + "_PlaneYZ"; std::string Plane3Name = BodyName + "_PlaneXZ"; - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane1Name.c_str()); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane2Name.c_str()); - doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(-0.707107,0.000000,0.000000,-0.707107))",Plane2Name.c_str()); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane3Name.c_str()); - doCommand(Doc,"App.activeDocument().%s.Annotation = [App.activeDocument().%s,App.activeDocument().%s,App.activeDocument().%s] ",PartName.c_str(),Plane1Name.c_str(),Plane2Name.c_str(),Plane3Name.c_str()); + //doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane1Name.c_str()); + //doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane2Name.c_str()); + //doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(-0.707107,0.000000,0.000000,-0.707107))",Plane2Name.c_str()); + //doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane3Name.c_str()); + //doCommand(Doc,"App.activeDocument().%s.Annotation = [App.activeDocument().%s,App.activeDocument().%s,App.activeDocument().%s] ",PartName.c_str(),Plane1Name.c_str(),Plane2Name.c_str(),Plane3Name.c_str()); // add the main body doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); -#endif # + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str()); + +#if 0 // test code for children nesting + Command::addModule(App,"Part"); + std::string BoxName = getUniqueObjectName("Box"); + doCommand(Doc,"App.activeDocument().addObject('Part::Box','%s')",BoxName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",BodyName.c_str(),BoxName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s ",BodyName.c_str(),BoxName.c_str()); +#endif + this->updateActive(); } diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index 8b183a449845..2831e0a6c84f 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -128,6 +128,8 @@ void Workbench::activated() void Workbench::deactivated() { + Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.setActiveAssembly(None)"); + Gui::Workbench::deactivated(); removeTaskWatcher(); diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index ed1711256ebd..3b581f4aa5d7 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -49,7 +49,7 @@ #include "FeatureMirroring.h" #include "FeatureRevolution.h" #include "PartFeatures.h" -#include "Body.h" +#include "BodyBase.h" #include "PrimitiveFeature.h" #include "Part2DObject.h" #include "CustomFeature.h" @@ -219,7 +219,7 @@ PyMODINIT_FUNC initPart() Part::Feature ::init(); Part::FeatureExt ::init(); - Part::Body ::init(); + Part::BodyBase ::init(); Part::FeaturePython ::init(); Part::FeatureGeometrySet ::init(); Part::CustomFeature ::init(); diff --git a/src/Mod/Part/App/Body.cpp b/src/Mod/Part/App/BodyBase.cpp similarity index 88% rename from src/Mod/Part/App/Body.cpp rename to src/Mod/Part/App/BodyBase.cpp index 1596c49da73c..8a5510f2f318 100644 --- a/src/Mod/Part/App/Body.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -27,23 +27,21 @@ #include -#include "Body.h" +#include "BodyBase.h" -using namespace Part; - namespace Part { -PROPERTY_SOURCE(Part::Body, Part::Feature) +PROPERTY_SOURCE(Part::BodyBase, Part::Feature) -Body::Body() +BodyBase::BodyBase() { ADD_PROPERTY(Model,(0)); ADD_PROPERTY(Tip ,(0)); } -short Body::mustExecute() const +short BodyBase::mustExecute() const { //if (Sketch.isTouched() || // Length.isTouched()) @@ -51,7 +49,7 @@ short Body::mustExecute() const return 0; } -App::DocumentObjectExecReturn *Body::execute(void) +App::DocumentObjectExecReturn *BodyBase::execute(void) { return App::DocumentObject::StdReturn; diff --git a/src/Mod/Part/App/Body.h b/src/Mod/Part/App/BodyBase.h similarity index 88% rename from src/Mod/Part/App/Body.h rename to src/Mod/Part/App/BodyBase.h index d5e91d428c3e..e17bf9ad0d88 100644 --- a/src/Mod/Part/App/Body.h +++ b/src/Mod/Part/App/BodyBase.h @@ -21,8 +21,8 @@ ***************************************************************************/ -#ifndef PART_Body_H -#define PART_Body_H +#ifndef PART_BodyBase_H +#define PART_BodyBase_H #include #include @@ -36,12 +36,12 @@ namespace Part * in edit or active on a workbench, the body shows only the * resulting shape to the outside (Tip link). */ -class PartExport Body : public Part::Feature +class PartExport BodyBase : public Part::Feature { - PROPERTY_HEADER(PartDesign::Body); + PROPERTY_HEADER(PartDesign::BodyBase); public: - Body(); + BodyBase(); App::PropertyLinkList Model; App::PropertyLink Tip; @@ -53,7 +53,7 @@ class PartExport Body : public Part::Feature short mustExecute() const; /// returns the type name of the view provider //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderBody"; + // return "PartDesignGui::ViewProviderBodyBase"; //} //@} }; @@ -61,4 +61,4 @@ class PartExport Body : public Part::Feature } //namespace Part -#endif // PART_Body_H +#endif // PART_BodyBase_H diff --git a/src/Mod/Part/App/BodyBasePy.xml b/src/Mod/Part/App/BodyBasePy.xml new file mode 100644 index 000000000000..94b232fce966 --- /dev/null +++ b/src/Mod/Part/App/BodyBasePy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all Body objects + + + diff --git a/src/Mod/Part/App/BodyBasePyImp.cpp b/src/Mod/Part/App/BodyBasePyImp.cpp new file mode 100644 index 000000000000..4f20f75a69a6 --- /dev/null +++ b/src/Mod/Part/App/BodyBasePyImp.cpp @@ -0,0 +1,29 @@ + +#include "PreCompiled.h" + +#include "Mod/Part/App/BodyBase.h" + +// inclusion of the generated files (generated out of ItemPy.xml) +#include "BodyBasePy.h" +#include "BodyBasePy.cpp" + +using namespace Part; + +// returns a string which represents the object e.g. when printed in python +std::string BodyBasePy::representation(void) const +{ + return std::string(""); +} + + +PyObject *BodyBasePy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int BodyBasePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 4b6efbf1d817..1328cac34e49 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -40,6 +40,7 @@ endif(FREETYPE_FOUND) generate_from_xml(ArcPy) generate_from_xml(ArcOfCirclePy) generate_from_xml(ArcOfParabolaPy) +generate_from_xml(BodyBasePy) generate_from_xml(CirclePy) generate_from_xml(ArcOfEllipsePy) generate_from_xml(EllipsePy) @@ -134,8 +135,8 @@ SET(Features_SRCS FeatureGeometrySet.cpp CustomFeature.cpp CustomFeature.h - Body.h - Body.cpp + BodyBase.h + BodyBase.cpp ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) @@ -154,6 +155,8 @@ SET(Python_SRCS ArcOfCirclePyImp.cpp ArcOfParabolaPy.xml ArcOfParabolaPyImp.cpp + BodyBasePy.xml + BodyBasePyImp.cpp CirclePy.xml CirclePyImp.cpp ArcOfEllipsePy.xml diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index a5939fdf369d..f435afc0e138 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -35,7 +35,7 @@ using namespace PartDesign; namespace PartDesign { -PROPERTY_SOURCE(PartDesign::Body, Part::Body) +PROPERTY_SOURCE(PartDesign::Body, Part::BodyBase) Body::Body() { diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index b895425c3744..b66fc752d43a 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -25,13 +25,13 @@ #define PARTDESIGN_Body_H #include -#include +#include namespace PartDesign { -class Body : public Part::Body +class Body : public Part::BodyBase { PROPERTY_HEADER(PartDesign::Body); diff --git a/src/Mod/PartDesign/App/BodyPy.xml b/src/Mod/PartDesign/App/BodyPy.xml new file mode 100644 index 000000000000..ab251ac73e9e --- /dev/null +++ b/src/Mod/PartDesign/App/BodyPy.xml @@ -0,0 +1,17 @@ + + + + + + PartDesign body class + + + diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp new file mode 100644 index 000000000000..aa592537ae56 --- /dev/null +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -0,0 +1,30 @@ + +#include "PreCompiled.h" + +#include "Mod/PartDesign/App/Body.h" + +// inclusion of the generated files (generated out of ItemPy.xml) +#include "BodyPy.h" +#include "BodyPy.cpp" + +using namespace PartDesign; + +// returns a string which represents the object e.g. when printed in python +std::string BodyPy::representation(void) const +{ + return std::string(""); +} + + + +PyObject *BodyPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int BodyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 8340a38a156b..51500d14c4c6 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -7,6 +7,8 @@ endif(MSVC) include_directories( ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/src + ${CMAKE_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${OCC_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} @@ -16,6 +18,9 @@ include_directories( ) link_directories(${OCC_LIBRARY_DIR}) +generate_from_xml(BodyPy) + + set(PartDesign_LIBS ${OCC_LIBRARIES} ${OCC_DEBUG_LIBRARIES} @@ -88,12 +93,21 @@ SET(Module_SRCS ) SOURCE_GROUP("Module" FILES ${Module_SRCS}) + +SET(Python_SRCS + BodyPy.xml + BodyPyImp.cpp + +) +SOURCE_GROUP("Python" FILES ${Python_SRCS}) + SET(PartDesign_SRCS ${Features_SRCS} ${FeaturesTransformed_SRCS} ${FeaturesSketchBased_SRCS} ${FeaturesDressUp_SRCS} ${Module_SRCS} + ${Python_SRCS} ) SET(PartDesign_Scripts From 903855ad82fff7447c5e88280b525f2f4bc757ab Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 5 May 2012 17:10:52 +0200 Subject: [PATCH 027/664] Automatic WB switching and Active PartDesign body --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 4 ++-- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 1 + src/Mod/PartDesign/App/Body.cpp | 10 ++++++++++ src/Mod/PartDesign/App/Body.h | 9 ++++++--- src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 2 ++ src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 8 ++++---- src/Mod/PartDesign/Gui/Workbench.cpp | 3 +++ 7 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 7be456d55b07..30ff96e6184a 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -61,10 +61,10 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) ActivePartObject = Item; ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,true); }else{ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,false); ActivePartObject = 0; } diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 23af658abfdb..49fe6fa71c40 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -47,6 +47,7 @@ ViewProviderItemAssembly::~ViewProviderItemAssembly() bool ViewProviderItemAssembly::doubleClicked(void) { + Gui::Command::assureWorkbench("AssemblyWorkbench"); Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.setActiveAssembly(App.activeDocument().%s)",this->getObject()->getNameInDocument()); return true; } diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index f435afc0e138..7110e04a08b1 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -28,6 +28,7 @@ #include #include "Body.h" +#include "BodyPy.h" using namespace PartDesign; @@ -56,4 +57,13 @@ App::DocumentObjectExecReturn *Body::execute(void) return App::DocumentObject::StdReturn; } +PyObject *Body::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new BodyPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + } \ No newline at end of file diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index b66fc752d43a..ecf001f84b73 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -44,10 +44,13 @@ class Body : public Part::BodyBase App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderBody"; - //} + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderBody"; + } //@} + + PyObject *getPyObject(void); + }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index af202d08c216..af942d95f491 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -36,6 +36,7 @@ #include "Workbench.h" #include "ViewProviderPocket.h" +#include "ViewProviderBody.h" #include "ViewProviderPad.h" #include "ViewProviderChamfer.h" #include "ViewProviderFillet.h" @@ -105,6 +106,7 @@ PyMODINIT_FUNC initPartDesignGui() PartDesignGui::Workbench ::init(); PartDesignGui::ViewProvider ::init(); + PartDesignGui::ViewProviderBody ::init(); PartDesignGui::ViewProviderPocket ::init(); PartDesignGui::ViewProviderPad ::init(); PartDesignGui::ViewProviderRevolution ::init(); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 08472d0ca823..7d4b19c1ffc6 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -44,10 +44,10 @@ ViewProviderBody::~ViewProviderBody() bool ViewProviderBody::doubleClicked(void) { - std::string Msg("Change "); - Msg += this->pcObject->getNameInDocument(); - Gui::Command::openCommand(Msg.c_str()); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); + // assure the PartDesign workbench + Gui::Command::assureWorkbench("PartDesignWorkbench"); + Gui::Command::addModule(Gui::Command::Gui,"PartDesignGui"); + Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(App.activeDocument().%s)",this->getObject()->getNameInDocument()); return true; } diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 07eb72ebbe8f..e327a071e0fa 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -34,6 +34,7 @@ #include #include #include +#include using namespace PartDesignGui; @@ -155,6 +156,8 @@ void Workbench::activated() void Workbench::deactivated() { + Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(None)"); + Gui::Workbench::deactivated(); removeTaskWatcher(); From bf26a422cb22f215b4fb31bcf127caab54c873dc Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 16 May 2012 15:19:40 +0200 Subject: [PATCH 028/664] clean up in- and out-list code --- src/Mod/PartDesign/App/FeatureRevolution.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index c7270016261a..76bb61366a40 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -241,8 +241,8 @@ void Revolution::updateAxis(void) axis *= SketchPlm; Base::Vector3d base=axis.getBase(); Base::Vector3d dir=axis.getDirection(); - Base.setValue(base.x,base.y,base.z); - Axis.setValue(dir.x,dir.y,dir.z); + Base.setValue(float(base.x),float(base.y),float(base.z)); + Axis.setValue(float(dir.x),float(dir.y),float(dir.z)); } } } From fbd763a8f4d80cced38fdad08c2f9499a6fc90f2 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 16 May 2012 21:45:03 +0200 Subject: [PATCH 029/664] switch PartDesign to Bodies --- src/Base/Uuid.h | 7 - src/Mod/PartDesign/Gui/CMakeLists.txt | 1 + src/Mod/PartDesign/Gui/Command.cpp | 1381 ++++++----- src/Mod/PartDesign/Gui/Command.cpp.orig | 2050 +++++++++++++++++ src/Mod/PartDesign/Gui/PreCompiled.h | 2 +- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 25 +- src/Mod/PartDesign/Gui/ViewProviderBody.h | 2 + src/Mod/PartDesign/Gui/Workbench.cpp | 80 +- src/Mod/Sketcher/Gui/PreCompiled.h | 6 +- .../Sketcher/Gui/SketchOrientationDialog.h | 4 +- 10 files changed, 2875 insertions(+), 683 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/Command.cpp.orig diff --git a/src/Base/Uuid.h b/src/Base/Uuid.h index 362d6b7b2618..3ec4e9af97d4 100644 --- a/src/Base/Uuid.h +++ b/src/Base/Uuid.h @@ -47,15 +47,8 @@ class BaseExport Uuid const std::string& getValue(void) const; static std::string createUuid(void); - /// raw data - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[ 8 ]; - private: std::string _uuid; - }; } //namespace Base diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 27a94d9e5276..bb951f6cc523 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -21,6 +21,7 @@ link_directories(${OCC_LIBRARY_DIR}) set(PartDesignGui_LIBS PartDesign + SketcherGui PartGui SketcherGui FreeCADGui diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 216867a9ba79..94c6c83c3c83 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -47,14 +47,20 @@ #include #include #include +#include #include +#include +#include +#include #include #include +#include "FeaturePickDialog.h" + using namespace std; -#include "FeaturePickDialog.h" +extern PartDesign::Body *ActivePartObject; namespace Gui { //=========================================================================== @@ -122,50 +128,150 @@ void validateSketches(std::vector& sketches, const bool su } } // namespace Gui +//=========================================================================== +// Helper for Body +//=========================================================================== + +PartDesign::Body *getBody(void) +{ + if(!ActivePartObject){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), + QObject::tr("To do PartDesign you need a active Body object in the documnt. Please make one active or create one. If you have a document with PartDesign objects without Body, use the transfer methode in PartDesign to put it into a Body.")); + } + return ActivePartObject; + +} + + //=========================================================================== // Part_Pad //=========================================================================== /* Sketch commands =======================================================*/ -//DEF_STD_CMD_A(CmdPartDesignNewSketch); -// -//CmdPartDesignNewSketch::CmdPartDesignNewSketch() -// :Command("PartDesign_NewSketch") -//{ -// sAppModule = "PartDesign"; -// sGroup = QT_TR_NOOP("PartDesign"); -// sMenuText = QT_TR_NOOP("Create sketch"); -// sToolTipText = QT_TR_NOOP("Create a new sketch"); -// sWhatsThis = sToolTipText; -// sStatusTip = sToolTipText; -// sPixmap = "Sketcher_NewSketch"; -//} -// -// -//void CmdPartDesignNewSketch::activated(int iMsg) -//{ -// const char camstring[] = "#Inventor V2.1 ascii \\n OrthographicCamera { \\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance 37 \\n farDistance 137 \\n aspectRatio 1 \\n focalDistance 87 \\n height 119 }"; -// -// std::string FeatName = getUniqueObjectName("Sketch"); -// -// std::string cam(camstring); -// -// openCommand("Create a new Sketch"); -// doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); -// doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// //getDocument()->recompute(); -//} -// -//bool CmdPartDesignNewSketch::isActive(void) -//{ -// if (getActiveGuiDocument()) -// return true; -// else -// return false; -//} -// +DEF_STD_CMD_A(CmdPartDesignNewSketch); + +CmdPartDesignNewSketch::CmdPartDesignNewSketch() + :Command("PartDesign_NewSketch") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create sketch"); + sToolTipText = QT_TR_NOOP("Create a new sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_NewSketch"; +} + + +void CmdPartDesignNewSketch::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + // No PartDesign feature without Body past FreeCAD 0.13 + if(!pcActiveBody) return; + + Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); + Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + + if (SketchFilter.match()) { + Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); + openCommand("Edit Sketch"); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); + } + else if (FaceFilter.match()) { + // get the selected object + Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + Base::Placement ObjectPos = part->Placement.getValue(); + const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); + if (sub.size() > 1){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), + QObject::tr("You have to select a single face as support for a sketch!")); + return; + } + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); + const TopoDS_Face& face = TopoDS::Face(sh); + if (face.IsNull()){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), + QObject::tr("You have to select a face as support for a sketch!")); + return; + } + + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), + QObject::tr("You need a planar face as support for a sketch!")); + return; + } + + std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + + // create Sketch on Face + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a Sketch on Face"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + else { + // ask user for orientation + SketcherGui::SketchOrientationDialog Dlg; + + if (Dlg.exec() != QDialog::Accepted) + return; // canceled + Base::Vector3d p = Dlg.Pos.getPosition(); + Base::Rotation r = Dlg.Pos.getRotation(); + + // do the right view direction + std::string camstring; + switch(Dlg.DirType){ + case 0: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 1: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 2: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 3: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 4: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 5: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + } + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a new Sketch"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + +} + +bool CmdPartDesignNewSketch::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} //=========================================================================== // PartDesign_Pad @@ -186,6 +292,8 @@ CmdPartDesignPad::CmdPartDesignPad() void CmdPartDesignPad::activated(int iMsg) { + PartDesign::Body *pcActiveBody = getBody(); + bool bNoSketchWasSelected = false; // Get a valid sketch from the user // First check selections @@ -219,6 +327,8 @@ void CmdPartDesignPad::activated(int iMsg) openCommand("Make Pad"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pad\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); App::DocumentObjectGroup* grp = sketch->getGroup(); @@ -272,6 +382,8 @@ CmdPartDesignPocket::CmdPartDesignPocket() void CmdPartDesignPocket::activated(int iMsg) { + PartDesign::Body *pcActiveBody = getBody(); + // Get a valid sketch from the user // First check selections std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); @@ -299,6 +411,8 @@ void CmdPartDesignPocket::activated(int iMsg) openCommand("Make Pocket"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pocket\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); App::DocumentObjectGroup* grp = sketch->getGroup(); @@ -344,6 +458,8 @@ CmdPartDesignRevolution::CmdPartDesignRevolution() void CmdPartDesignRevolution::activated(int iMsg) { + PartDesign::Body *pcActiveBody = getBody(); + bool bNoSketchWasSelected = false; // Get a valid sketch from the user // First check selections @@ -377,6 +493,8 @@ void CmdPartDesignRevolution::activated(int iMsg) openCommand("Make Revolution"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Revolution\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", FeatName.c_str(), sketch->getNameInDocument()); @@ -430,60 +548,60 @@ CmdPartDesignGroove::CmdPartDesignGroove() void CmdPartDesignGroove::activated(int iMsg) { - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - // Next let the user choose from a list of all eligible objects - if (sketches.size() == 0) { - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - if (sketches.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); - return; - } - } - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Groove"); - - openCommand("Make Groove"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); - PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); - if (pcGroove && pcGroove->suggestReversed()) - doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - if (support) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - if (support) { - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); - } +// // Get a valid sketch from the user +// // First check selections +// std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); +// Gui::validateSketches(sketches, true); +// // Next let the user choose from a list of all eligible objects +// if (sketches.size() == 0) { +// sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); +// Gui::validateSketches(sketches, true); +// if (sketches.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), +// QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); +// return; +// } +// } +// // If there is more than one selection/possibility, show dialog and let user pick sketch +// if (sketches.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(sketches); +// if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } +// +// Part::Part2DObject* sketch = static_cast(sketches.front()); +// App::DocumentObject* support = sketch->Support.getValue(); +// std::string FeatName = getUniqueObjectName("Groove"); +// +// openCommand("Make Groove"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", +// FeatName.c_str(), sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); +// PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); +// if (pcGroove && pcGroove->suggestReversed()) +// doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); +// App::DocumentObjectGroup* grp = sketch->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),sketch->getNameInDocument()); +// } +// updateActive(); +// if (isActiveObjectValid()) { +// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); +// if (support) +// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); +// } +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// if (support) { +// copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); +// copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); +// copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); +// } } bool CmdPartDesignGroove::isActive(void) @@ -523,102 +641,102 @@ void CmdPartDesignFillet::activated(int iMsg) QObject::tr("Fillet works only on parts.")); return; } - + std::string SelString = selection[0].getAsPropertyLinkSubString(); Part::Feature *base = static_cast(selection[0].getObject()); - - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// +// const Part::TopoShape& TopShape = base->Shape.getShape(); +// if (TopShape._Shape.IsNull()){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - - std::vector SubNames = std::vector(selection[0].getSubNames()); - - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { - TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); - const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); - - if(los.Extent() != 2) - { - SubNames.erase(SubNames.begin()+i); - continue; - } - - const TopoDS_Shape& face1 = los.First(); - const TopoDS_Shape& face2 = los.Last(); - GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), - TopoDS::Face(face1), - TopoDS::Face(face2)); - if (cont != GeomAbs_C0) { - SubNames.erase(SubNames.begin()+i); - continue; - } - - i++; - } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - - TopTools_IndexedMapOfShape mapOfFaces; - TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); - - for(int j = 1; j <= mapOfFaces.Extent(); ++j) { - TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); - - int id = mapOfEdges.FindIndex(edge); - - std::stringstream buf; - buf << "Edge"; - buf << id; - - if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) - { - SubNames.push_back(buf.str()); - } - - } - - SubNames.erase(SubNames.begin()+i); - } - // empty name or any other sub-element - else { - SubNames.erase(SubNames.begin()+i); - } - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// return; +// } +// +// TopTools_IndexedMapOfShape mapOfEdges; +// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; +// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); +// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); +// +// std::vector SubNames = std::vector(selection[0].getSubNames()); +// +// unsigned int i = 0; +// +// while(i < SubNames.size()) +// { +// std::string aSubName = static_cast(SubNames.at(i)); +// +// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { +// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); +// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); +// +// if(los.Extent() != 2) +// { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// const TopoDS_Shape& face1 = los.First(); +// const TopoDS_Shape& face2 = los.Last(); +// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), +// TopoDS::Face(face1), +// TopoDS::Face(face2)); +// if (cont != GeomAbs_C0) { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// i++; +// } +// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { +// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); +// +// TopTools_IndexedMapOfShape mapOfFaces; +// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); +// +// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { +// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); +// +// int id = mapOfEdges.FindIndex(edge); +// +// std::stringstream buf; +// buf << "Edge"; +// buf << id; +// +// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) +// { +// SubNames.push_back(buf.str()); +// } +// +// } +// +// SubNames.erase(SubNames.begin()+i); +// } +// // empty name or any other sub-element +// else { +// SubNames.erase(SubNames.begin()+i); +// } +// } +// +// if (SubNames.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("No fillet possible on selected faces/edges.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - +// return; +// } +// +// std::string SelString; +// SelString += "(App."; +// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); +// SelString += "."; +// SelString += selection[0].getFeatName(); +// SelString += ",["; +// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ +// SelString += "\""; +// SelString += *it; +// SelString += "\""; +// if(it != --SubNames.end()) +// SelString += ","; +// } +// SelString += "])"; +// std::string FeatName = getUniqueObjectName("Fillet"); openCommand("Make Fillet"); @@ -675,103 +793,104 @@ void CmdPartDesignChamfer::activated(int iMsg) QObject::tr("Chamfer works only on parts.")); return; } + std::string SelString = selection[0].getAsPropertyLinkSubString(); Part::Feature *base = static_cast(selection[0].getObject()); - - const Part::TopoShape& TopShape = base->Shape.getShape(); - - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// +// const Part::TopoShape& TopShape = base->Shape.getShape(); +// +// if (TopShape._Shape.IsNull()){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - - std::vector SubNames = std::vector(selection[0].getSubNames()); - - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { - TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); - const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); - - if(los.Extent() != 2) - { - SubNames.erase(SubNames.begin()+i); - continue; - } - - const TopoDS_Shape& face1 = los.First(); - const TopoDS_Shape& face2 = los.Last(); - GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), - TopoDS::Face(face1), - TopoDS::Face(face2)); - if (cont != GeomAbs_C0) { - SubNames.erase(SubNames.begin()+i); - continue; - } - - i++; - } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - - TopTools_IndexedMapOfShape mapOfFaces; - TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); - - for(int j = 1; j <= mapOfFaces.Extent(); ++j) { - TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); - - int id = mapOfEdges.FindIndex(edge); - - std::stringstream buf; - buf << "Edge"; - buf << id; - - if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) - { - SubNames.push_back(buf.str()); - } - - } - - SubNames.erase(SubNames.begin()+i); - } - // empty name or any other sub-element - else { - SubNames.erase(SubNames.begin()+i); - } - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No chamfer possible on selected faces/edges.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - +// return; +// } +// +// TopTools_IndexedMapOfShape mapOfEdges; +// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; +// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); +// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); +// +// std::vector SubNames = std::vector(selection[0].getSubNames()); +// +// unsigned int i = 0; +// +// while(i < SubNames.size()) +// { +// std::string aSubName = static_cast(SubNames.at(i)); +// +// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { +// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); +// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); +// +// if(los.Extent() != 2) +// { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// const TopoDS_Shape& face1 = los.First(); +// const TopoDS_Shape& face2 = los.Last(); +// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), +// TopoDS::Face(face1), +// TopoDS::Face(face2)); +// if (cont != GeomAbs_C0) { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// i++; +// } +// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { +// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); +// +// TopTools_IndexedMapOfShape mapOfFaces; +// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); +// +// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { +// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); +// +// int id = mapOfEdges.FindIndex(edge); +// +// std::stringstream buf; +// buf << "Edge"; +// buf << id; +// +// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) +// { +// SubNames.push_back(buf.str()); +// } +// +// } +// +// SubNames.erase(SubNames.begin()+i); +// } +// // empty name or any other sub-element +// else { +// SubNames.erase(SubNames.begin()+i); +// } +// } +// +// if (SubNames.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("No chamfer possible on selected faces/edges.")); +// return; +// } +// +// std::string SelString; +// SelString += "(App."; +// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); +// SelString += "."; +// SelString += selection[0].getFeatName(); +// SelString += ",["; +// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ +// SelString += "\""; +// SelString += *it; +// SelString += "\""; +// if(it != --SubNames.end()) +// SelString += ","; +// } +// SelString += "])"; +// std::string FeatName = getUniqueObjectName("Chamfer"); openCommand("Make Chamfer"); @@ -815,96 +934,96 @@ CmdPartDesignDraft::CmdPartDesignDraft() void CmdPartDesignDraft::activated(int iMsg) { - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() < 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select one or more faces.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Draft works only on parts.")); - return; - } - - Part::Feature *base = static_cast(selection[0].getObject()); - - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected Part is empty.")); - return; - } - - std::vector SubNames = std::vector(selection[0].getSubNames()); - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - // Check for valid face types - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - BRepAdaptor_Surface sf(face); - if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) - SubNames.erase(SubNames.begin()+i); - } else { - // empty name or any other sub-element - SubNames.erase(SubNames.begin()+i); - } - - i++; - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No draft possible on selected faces.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument"; - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - - std::string FeatName = getUniqueObjectName("Draft"); - - // We don't create any defaults for neutral plane and pull direction, but Draft::execute() - // will choose them. - // Note: When the body feature is there, the best thing would be to get pull direction and - // neutral plane from the preceding feature in the tree. Or even store them as default in - // the Body feature itself - openCommand("Make Draft"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +// std::vector selection = getSelection().getSelectionEx(); +// +// if (selection.size() < 1) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Select one or more faces.")); +// return; +// } +// +// if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), +// QObject::tr("Draft works only on parts.")); +// return; +// } +// +// Part::Feature *base = static_cast(selection[0].getObject()); +// +// const Part::TopoShape& TopShape = base->Shape.getShape(); +// if (TopShape._Shape.IsNull()){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Shape of selected Part is empty.")); +// return; +// } +// +// std::vector SubNames = std::vector(selection[0].getSubNames()); +// unsigned int i = 0; +// +// while(i < SubNames.size()) +// { +// std::string aSubName = static_cast(SubNames.at(i)); +// +// if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { +// // Check for valid face types +// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); +// BRepAdaptor_Surface sf(face); +// if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) +// SubNames.erase(SubNames.begin()+i); +// } else { +// // empty name or any other sub-element +// SubNames.erase(SubNames.begin()+i); +// } +// +// i++; +// } +// +// if (SubNames.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("No draft possible on selected faces.")); +// return; +// } +// +// std::string SelString; +// SelString += "(App."; +// SelString += "ActiveDocument"; +// SelString += "."; +// SelString += selection[0].getFeatName(); +// SelString += ",["; +// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ +// SelString += "\""; +// SelString += *it; +// SelString += "\""; +// if(it != --SubNames.end()) +// SelString += ","; +// } +// SelString += "])"; +// +// std::string FeatName = getUniqueObjectName("Draft"); +// +// // We don't create any defaults for neutral plane and pull direction, but Draft::execute() +// // will choose them. +// // Note: When the body feature is there, the best thing would be to get pull direction and +// // neutral plane from the preceding feature in the tree. Or even store them as default in +// // the Body feature itself +// openCommand("Make Draft"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); +// updateActive(); +// if (isActiveObjectValid()) { +// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); +// } +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// App::DocumentObjectGroup* grp = base->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// } +// +// copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); +// copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); +// copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); } bool CmdPartDesignDraft::isActive(void) @@ -931,56 +1050,56 @@ CmdPartDesignMirrored::CmdPartDesignMirrored() void CmdPartDesignMirrored::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("Mirrored"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("Mirrored"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); - // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like - // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' - updateActive(); // Helps to ensure that the object already exists when the next command comes up - doCommand(Doc,str.str().c_str()); - Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); - if (sketch) - doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first.")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("Mirrored"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("Mirrored"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); +// // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like +// // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' +// updateActive(); // Helps to ensure that the object already exists when the next command comes up +// doCommand(Doc,str.str().c_str()); +// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); +// if (sketch) +// doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", +// FeatName.c_str(), sketch->getNameInDocument()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); } bool CmdPartDesignMirrored::isActive(void) @@ -1007,63 +1126,63 @@ CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() void CmdPartDesignLinearPattern::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("LinearPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("LinearPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); - if (sketch) - doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please.")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("LinearPattern"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("LinearPattern"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); +// if (sketch) +// doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", +// FeatName.c_str(), sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// App::DocumentObjectGroup* grp = sketch->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),sketch->getNameInDocument()); +// } +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); } bool CmdPartDesignLinearPattern::isActive(void) @@ -1090,63 +1209,63 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() void CmdPartDesignPolarPattern::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("PolarPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("PolarPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); - if (sketch) - doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please.")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("PolarPattern"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("PolarPattern"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); +// if (sketch) +// doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", +// FeatName.c_str(), sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// App::DocumentObjectGroup* grp = sketch->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),sketch->getNameInDocument()); +// } +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); } bool CmdPartDesignPolarPattern::isActive(void) @@ -1173,52 +1292,52 @@ CmdPartDesignScaled::CmdPartDesignScaled() void CmdPartDesignScaled::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("Scaled"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("Scaled"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please.")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("Scaled"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("Scaled"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); } bool CmdPartDesignScaled::isActive(void) @@ -1245,48 +1364,48 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("MultiTransform"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("MultiTransform"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please.")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("MultiTransform"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("MultiTransform"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); } bool CmdPartDesignMultiTransform::isActive(void) @@ -1306,14 +1425,14 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); - rcCmdMgr.addCommand(new CmdPartDesignGroove()); +// rcCmdMgr.addCommand(new CmdPartDesignGroove()); rcCmdMgr.addCommand(new CmdPartDesignFillet()); - rcCmdMgr.addCommand(new CmdPartDesignDraft()); - //rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); +// rcCmdMgr.addCommand(new CmdPartDesignDraft()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); - rcCmdMgr.addCommand(new CmdPartDesignMirrored()); - rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); - rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); - //rcCmdMgr.addCommand(new CmdPartDesignScaled()); - rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); +// rcCmdMgr.addCommand(new CmdPartDesignMirrored()); +// rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); +// rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); +// //rcCmdMgr.addCommand(new CmdPartDesignScaled()); +// rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); } diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig new file mode 100644 index 000000000000..d5e5fa667582 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -0,0 +1,2050 @@ +/*************************************************************************** + * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "FeaturePickDialog.h" + +using namespace std; + +extern PartDesign::Body *ActivePartObject; + +namespace Gui { +//=========================================================================== +// Common utility functions +//=========================================================================== + +// Take a list of Part2DObjects and erase those which are not eligible for creating a +// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define +// a Subtractive feature +void validateSketches(std::vector& sketches, const bool supportRequired) +{ + std::vector::iterator s = sketches.begin(); + + while (s != sketches.end()) { + // Check whether this sketch is already being used by another feature + std::vector ref = (*s)->getInList(); + std::vector::iterator r = ref.begin(); + while (r != ref.end()) { + if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { + r = ref.erase(r); + continue; + } + ++r; + } + if (!ref.empty()) { + // TODO: Display some information message that this sketch was removed? + s = sketches.erase(s); + continue; + } + + // Check whether the sketch shape is valid + Part::Part2DObject* sketch = static_cast(*s); + const TopoDS_Shape& shape = sketch->Shape.getValue(); + if (shape.IsNull()) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + + // count free wires + int ctWires=0; + TopExp_Explorer ex; + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { + ctWires++; + } + if (ctWires == 0) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + + // Check for support + if (supportRequired) { + App::DocumentObject* support = sketch->Support.getValue(); + if (support == NULL) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + } + + // All checks passed - go on to next candidate + s++; + } +} +} // namespace Gui + +//=========================================================================== +// Helper for Body +//=========================================================================== + +PartDesign::Body *getBody(void) +{ + if(!ActivePartObject){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), + QObject::tr("To do PartDesign you need a active Body object in the documnt. Please make one active or create one. If you have a document with PartDesign objects without Body, use the transfer methode in PartDesign to put it into a Body.")); + } + return ActivePartObject; + +} + + +//=========================================================================== +// Part_Pad +//=========================================================================== + +/* Sketch commands =======================================================*/ +DEF_STD_CMD_A(CmdPartDesignNewSketch); + +CmdPartDesignNewSketch::CmdPartDesignNewSketch() + :Command("PartDesign_NewSketch") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create sketch"); + sToolTipText = QT_TR_NOOP("Create a new sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_NewSketch"; +} + + +void CmdPartDesignNewSketch::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + // No PartDesign feature without Body past FreeCAD 0.13 + if(!pcActiveBody) return; + + Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); + Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + + if (SketchFilter.match()) { + Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); + openCommand("Edit Sketch"); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); + } + else if (FaceFilter.match()) { + // get the selected object + Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + Base::Placement ObjectPos = part->Placement.getValue(); + const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); + if (sub.size() > 1){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), + QObject::tr("You have to select a single face as support for a sketch!")); + return; + } + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); + const TopoDS_Face& face = TopoDS::Face(sh); + if (face.IsNull()){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), + QObject::tr("You have to select a face as support for a sketch!")); + return; + } + + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), + QObject::tr("You need a planar face as support for a sketch!")); + return; + } + + std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + + // create Sketch on Face + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a Sketch on Face"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + else { + // ask user for orientation + SketcherGui::SketchOrientationDialog Dlg; + + if (Dlg.exec() != QDialog::Accepted) + return; // canceled + Base::Vector3d p = Dlg.Pos.getPosition(); + Base::Rotation r = Dlg.Pos.getRotation(); + + // do the right view direction + std::string camstring; + switch(Dlg.DirType){ + case 0: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 1: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 2: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 3: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 4: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 5: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + } + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a new Sketch"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + +} + +bool CmdPartDesignNewSketch::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +//=========================================================================== +// PartDesign_Pad +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPad); + +CmdPartDesignPad::CmdPartDesignPad() + : Command("PartDesign_Pad") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Pad"); + sToolTipText = QT_TR_NOOP("Pad a selected sketch"); + sWhatsThis = "PartDesign_Pad"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Pad"; +} + +void CmdPartDesignPad::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + bool bNoSketchWasSelected = false; + // Get a valid sketch from the user + // First check selections + std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document + sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + bNoSketchWasSelected = true; + } + Gui::validateSketches(sketches, false); + if (sketches.size() == 0) { + if (bNoSketchWasSelected) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), + QObject::tr("Please create a sketch or 2D object first.")); + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), + QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); + } + return; + } + + // If there is more than one selection/possibility, show dialog and let user pick sketch + if (sketches.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches); + if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } + + Part::Part2DObject* sketch = static_cast(sketches.front()); + App::DocumentObject* support = sketch->Support.getValue(); + std::string FeatName = getUniqueObjectName("Pad"); + + openCommand("Make Pad"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pad\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); + if (support) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); + } + // #0001721: use '0' as edit value to avoid switching off selection in + // ViewProviderGeometryObject::setEditViewer + doCommand(Gui,"Gui.activeDocument().setEdit('%s',0)",FeatName.c_str()); + + //commitCommand(); + adjustCameraPosition(); + + if (support) { + copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); + } +} + +bool CmdPartDesignPad::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Pocket +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPocket); + +CmdPartDesignPocket::CmdPartDesignPocket() + : Command("PartDesign_Pocket") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Pocket"); + sToolTipText = QT_TR_NOOP("Create a pocket with the selected sketch"); + sWhatsThis = "PartDesign_Pocket"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Pocket"; +} + +void CmdPartDesignPocket::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + // Get a valid sketch from the user + // First check selections + std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + Gui::validateSketches(sketches, true); + // Next let the user choose from a list of all eligible objects + if (sketches.size() == 0) { + sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + Gui::validateSketches(sketches, true); + if (sketches.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), + QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); + return; + } + } + // If there is more than one selection/possibility, show dialog and let user pick sketch + if (sketches.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches); + if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } + + Part::Part2DObject* sketch = static_cast(sketches.front()); + App::DocumentObject* support = sketch->Support.getValue(); + std::string FeatName = getUniqueObjectName("Pocket"); + + openCommand("Make Pocket"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pocket\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); + } + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); +} + +bool CmdPartDesignPocket::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Revolution +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignRevolution); + +CmdPartDesignRevolution::CmdPartDesignRevolution() + : Command("PartDesign_Revolution") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Revolution"); + sToolTipText = QT_TR_NOOP("Revolve a selected sketch"); + sWhatsThis = "PartDesign_Revolution"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Revolution"; +} + +void CmdPartDesignRevolution::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + bool bNoSketchWasSelected = false; + // Get a valid sketch from the user + // First check selections + std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document + sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + bNoSketchWasSelected = true; + } + Gui::validateSketches(sketches, false); + if (sketches.size() == 0) { + if (bNoSketchWasSelected) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), + QObject::tr("Please create a sketch or 2D object first.")); + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), + QObject::tr("None of selected sketches/2D objects is valid for revolving. Please select a valid sketch or 2D object that is not used by any other feature.")); + } + return; + } + + // If there is more than one selection/possibility, show dialog and let user pick sketch + if (sketches.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches); + if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } + + Part::Part2DObject* sketch = static_cast(sketches.front()); + App::DocumentObject* support = sketch->Support.getValue(); + std::string FeatName = getUniqueObjectName("Revolution"); + + openCommand("Make Revolution"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Revolution\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + PartDesign::Revolution* pcRevolution = static_cast(getDocument()->getObject(FeatName.c_str())); + if (pcRevolution && pcRevolution->suggestReversed()) + doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); + if (support) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); + } + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + if (support) { + copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); + } +} + +bool CmdPartDesignRevolution::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Groove +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignGroove); + +CmdPartDesignGroove::CmdPartDesignGroove() + : Command("PartDesign_Groove") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Groove"); + sToolTipText = QT_TR_NOOP("Groove a selected sketch"); + sWhatsThis = "PartDesign_Groove"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Groove"; +} + +void CmdPartDesignGroove::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + // Get a valid sketch from the user + // First check selections + std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + Gui::validateSketches(sketches, true); + // Next let the user choose from a list of all eligible objects + if (sketches.size() == 0) { + sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + Gui::validateSketches(sketches, true); + if (sketches.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), + QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); + return; + } + } + // If there is more than one selection/possibility, show dialog and let user pick sketch + if (sketches.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches); + if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } + + Part::Part2DObject* sketch = static_cast(sketches.front()); + App::DocumentObject* support = sketch->Support.getValue(); + std::string FeatName = getUniqueObjectName("Groove"); + + openCommand("Make Groove"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); + if (pcGroove && pcGroove->suggestReversed()) + doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); + if (support) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); + } + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + if (support) { + copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); + copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); + } +======= +// // Get a valid sketch from the user +// // First check selections +// std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); +// Gui::validateSketches(sketches, true); +// // Next let the user choose from a list of all eligible objects +// if (sketches.size() == 0) { +// sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); +// Gui::validateSketches(sketches, true); +// if (sketches.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), +// QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid")); +// return; +// } +// } +// // If there is more than one selection/possibility, show dialog and let user pick sketch +// if (sketches.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(sketches); +// if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } +// +// Part::Part2DObject* sketch = static_cast(sketches.front()); +// App::DocumentObject* support = sketch->Support.getValue(); +// std::string FeatName = getUniqueObjectName("Groove"); +// +// openCommand("Make Groove"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", +// FeatName.c_str(), sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); +// PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); +// if (pcGroove && pcGroove->suggestReversed()) +// doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); +// App::DocumentObjectGroup* grp = sketch->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),sketch->getNameInDocument()); +// } +// updateActive(); +// if (isActiveObjectValid()) { +// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); +// if (support) +// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); +// } +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// if (support) { +// copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); +// copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); +// copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); +// } +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignGroove::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Fillet +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignFillet); + +CmdPartDesignFillet::CmdPartDesignFillet() + :Command("PartDesign_Fillet") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Fillet"); + sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); + sWhatsThis = "PartDesign_Fillet"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Fillet"; +} + +void CmdPartDesignFillet::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge, face or body. Only one body is allowed.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Fillet works only on parts.")); + return; + } + std::string SelString = selection[0].getAsPropertyLinkSubString(); + Part::Feature *base = static_cast(selection[0].getObject()); +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected part is empty.")); + return; + } + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); + + std::vector SubNames = std::vector(selection[0].getSubNames()); + + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); + const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); + + if(los.Extent() != 2) + { + SubNames.erase(SubNames.begin()+i); + continue; + } + + const TopoDS_Shape& face1 = los.First(); + const TopoDS_Shape& face2 = los.Last(); + GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), + TopoDS::Face(face1), + TopoDS::Face(face2)); + if (cont != GeomAbs_C0) { + SubNames.erase(SubNames.begin()+i); + continue; + } + + i++; + } + else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); + + for(int j = 1; j <= mapOfFaces.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); + + int id = mapOfEdges.FindIndex(edge); + + std::stringstream buf; + buf << "Edge"; + buf << id; + + if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) + { + SubNames.push_back(buf.str()); + } + + } + + SubNames.erase(SubNames.begin()+i); + } + // empty name or any other sub-element + else { + SubNames.erase(SubNames.begin()+i); + } + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No fillet possible on selected faces/edges.")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + +======= +// +// const Part::TopoShape& TopShape = base->Shape.getShape(); +// if (TopShape._Shape.IsNull()){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Shape of selected part is empty")); +// return; +// } +// +// TopTools_IndexedMapOfShape mapOfEdges; +// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; +// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); +// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); +// +// std::vector SubNames = std::vector(selection[0].getSubNames()); +// +// unsigned int i = 0; +// +// while(i < SubNames.size()) +// { +// std::string aSubName = static_cast(SubNames.at(i)); +// +// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { +// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); +// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); +// +// if(los.Extent() != 2) +// { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// const TopoDS_Shape& face1 = los.First(); +// const TopoDS_Shape& face2 = los.Last(); +// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), +// TopoDS::Face(face1), +// TopoDS::Face(face2)); +// if (cont != GeomAbs_C0) { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// i++; +// } +// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { +// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); +// +// TopTools_IndexedMapOfShape mapOfFaces; +// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); +// +// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { +// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); +// +// int id = mapOfEdges.FindIndex(edge); +// +// std::stringstream buf; +// buf << "Edge"; +// buf << id; +// +// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) +// { +// SubNames.push_back(buf.str()); +// } +// +// } +// +// SubNames.erase(SubNames.begin()+i); +// } +// // empty name or any other sub-element +// else { +// SubNames.erase(SubNames.begin()+i); +// } +// } +// +// if (SubNames.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("No fillet possible on selected faces/edges")); +// return; +// } +// +// std::string SelString; +// SelString += "(App."; +// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); +// SelString += "."; +// SelString += selection[0].getFeatName(); +// SelString += ",["; +// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ +// SelString += "\""; +// SelString += *it; +// SelString += "\""; +// if(it != --SubNames.end()) +// SelString += ","; +// } +// SelString += "])"; +// +>>>>>>> switch PartDesign to Bodies + std::string FeatName = getUniqueObjectName("Fillet"); + + openCommand("Make Fillet"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.Selection.clearSelection()"); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignFillet::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Chamfer +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignChamfer); + +CmdPartDesignChamfer::CmdPartDesignChamfer() + :Command("PartDesign_Chamfer") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Chamfer"); + sToolTipText = QT_TR_NOOP("Chamfer the selected edges of a shape"); + sWhatsThis = "PartDesign_Chamfer"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Chamfer"; +} + +void CmdPartDesignChamfer::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge, face or body. Only one body is allowed.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Chamfer works only on parts.")); + return; + } + std::string SelString = selection[0].getAsPropertyLinkSubString(); + + Part::Feature *base = static_cast(selection[0].getObject()); +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + + const Part::TopoShape& TopShape = base->Shape.getShape(); + + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected part is empty.")); + return; + } + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); + + std::vector SubNames = std::vector(selection[0].getSubNames()); + + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); + const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); + + if(los.Extent() != 2) + { + SubNames.erase(SubNames.begin()+i); + continue; + } + + const TopoDS_Shape& face1 = los.First(); + const TopoDS_Shape& face2 = los.Last(); + GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), + TopoDS::Face(face1), + TopoDS::Face(face2)); + if (cont != GeomAbs_C0) { + SubNames.erase(SubNames.begin()+i); + continue; + } + + i++; + } + else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); + + for(int j = 1; j <= mapOfFaces.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); + + int id = mapOfEdges.FindIndex(edge); + + std::stringstream buf; + buf << "Edge"; + buf << id; + + if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) + { + SubNames.push_back(buf.str()); + } + + } + + SubNames.erase(SubNames.begin()+i); + } + // empty name or any other sub-element + else { + SubNames.erase(SubNames.begin()+i); + } + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No chamfer possible on selected faces/edges.")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + +======= +// +// const Part::TopoShape& TopShape = base->Shape.getShape(); +// +// if (TopShape._Shape.IsNull()){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Shape of selected part is empty")); +// return; +// } +// +// TopTools_IndexedMapOfShape mapOfEdges; +// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; +// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); +// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); +// +// std::vector SubNames = std::vector(selection[0].getSubNames()); +// +// unsigned int i = 0; +// +// while(i < SubNames.size()) +// { +// std::string aSubName = static_cast(SubNames.at(i)); +// +// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { +// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); +// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); +// +// if(los.Extent() != 2) +// { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// const TopoDS_Shape& face1 = los.First(); +// const TopoDS_Shape& face2 = los.Last(); +// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), +// TopoDS::Face(face1), +// TopoDS::Face(face2)); +// if (cont != GeomAbs_C0) { +// SubNames.erase(SubNames.begin()+i); +// continue; +// } +// +// i++; +// } +// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { +// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); +// +// TopTools_IndexedMapOfShape mapOfFaces; +// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); +// +// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { +// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); +// +// int id = mapOfEdges.FindIndex(edge); +// +// std::stringstream buf; +// buf << "Edge"; +// buf << id; +// +// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) +// { +// SubNames.push_back(buf.str()); +// } +// +// } +// +// SubNames.erase(SubNames.begin()+i); +// } +// // empty name or any other sub-element +// else { +// SubNames.erase(SubNames.begin()+i); +// } +// } +// +// if (SubNames.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("No chamfer possible on selected faces/edges")); +// return; +// } +// +// std::string SelString; +// SelString += "(App."; +// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); +// SelString += "."; +// SelString += selection[0].getFeatName(); +// SelString += ",["; +// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ +// SelString += "\""; +// SelString += *it; +// SelString += "\""; +// if(it != --SubNames.end()) +// SelString += ","; +// } +// SelString += "])"; +// +>>>>>>> switch PartDesign to Bodies + std::string FeatName = getUniqueObjectName("Chamfer"); + + openCommand("Make Chamfer"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.Selection.clearSelection()"); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignChamfer::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Draft +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignDraft); + +CmdPartDesignDraft::CmdPartDesignDraft() + :Command("PartDesign_Draft") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Draft"); + sToolTipText = QT_TR_NOOP("Make a draft on a face"); + sWhatsThis = "PartDesign_Draft"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Draft"; +} + +void CmdPartDesignDraft::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() < 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select one or more faces.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Draft works only on parts.")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected Part is empty.")); + return; + } + + std::vector SubNames = std::vector(selection[0].getSubNames()); + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + // Check for valid face types + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + BRepAdaptor_Surface sf(face); + if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) + SubNames.erase(SubNames.begin()+i); + } else { + // empty name or any other sub-element + SubNames.erase(SubNames.begin()+i); + } + + i++; + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No draft possible on selected faces.")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument"; + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Draft"); + + // We don't create any defaults for neutral plane and pull direction, but Draft::execute() + // will choose them. + // Note: When the body feature is there, the best thing would be to get pull direction and + // neutral plane from the preceding feature in the tree. Or even store them as default in + // the Body feature itself + openCommand("Make Draft"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + } + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +======= +// std::vector selection = getSelection().getSelectionEx(); +// +// if (selection.size() < 1) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Select one or more faces.")); +// return; +// } +// +// if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), +// QObject::tr("Draft works only on parts")); +// return; +// } +// +// Part::Feature *base = static_cast(selection[0].getObject()); +// +// const Part::TopoShape& TopShape = base->Shape.getShape(); +// if (TopShape._Shape.IsNull()){ +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("Shape of selected Part is empty")); +// return; +// } +// +// std::vector SubNames = std::vector(selection[0].getSubNames()); +// unsigned int i = 0; +// +// while(i < SubNames.size()) +// { +// std::string aSubName = static_cast(SubNames.at(i)); +// +// if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { +// // Check for valid face types +// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); +// BRepAdaptor_Surface sf(face); +// if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) +// SubNames.erase(SubNames.begin()+i); +// } else { +// // empty name or any other sub-element +// SubNames.erase(SubNames.begin()+i); +// } +// +// i++; +// } +// +// if (SubNames.size() == 0) { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +// QObject::tr("No draft possible on selected faces")); +// return; +// } +// +// std::string SelString; +// SelString += "(App."; +// SelString += "ActiveDocument"; +// SelString += "."; +// SelString += selection[0].getFeatName(); +// SelString += ",["; +// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ +// SelString += "\""; +// SelString += *it; +// SelString += "\""; +// if(it != --SubNames.end()) +// SelString += ","; +// } +// SelString += "])"; +// +// std::string FeatName = getUniqueObjectName("Draft"); +// +// // We don't create any defaults for neutral plane and pull direction, but Draft::execute() +// // will choose them. +// // Note: When the body feature is there, the best thing would be to get pull direction and +// // neutral plane from the preceding feature in the tree. Or even store them as default in +// // the Body feature itself +// openCommand("Make Draft"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); +// updateActive(); +// if (isActiveObjectValid()) { +// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); +// } +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// App::DocumentObjectGroup* grp = base->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// } +// +// copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); +// copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); +// copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignDraft::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Mirrored +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMirrored); + +CmdPartDesignMirrored::CmdPartDesignMirrored() + : Command("PartDesign_Mirrored") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Mirrored"); + sToolTipText = QT_TR_NOOP("Create a mirrored feature"); + sWhatsThis = "PartDesign_Mirrored"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Mirrored"; +} + +void CmdPartDesignMirrored::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("Mirrored"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("Mirrored"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); + // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like + // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' + updateActive(); // Helps to ensure that the object already exists when the next command comes up + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +======= +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("Mirrored"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("Mirrored"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); +// // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like +// // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' +// updateActive(); // Helps to ensure that the object already exists when the next command comes up +// doCommand(Doc,str.str().c_str()); +// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); +// if (sketch) +// doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", +// FeatName.c_str(), sketch->getNameInDocument()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignMirrored::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_LinearPattern +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignLinearPattern); + +CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() + : Command("PartDesign_LinearPattern") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("LinearPattern"); + sToolTipText = QT_TR_NOOP("Create a linear pattern feature"); + sWhatsThis = "PartDesign_LinearPattern"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_LinearPattern"; +} + +void CmdPartDesignLinearPattern::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("LinearPattern"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("LinearPattern"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +======= +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("LinearPattern"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("LinearPattern"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); +// if (sketch) +// doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", +// FeatName.c_str(), sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// App::DocumentObjectGroup* grp = sketch->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),sketch->getNameInDocument()); +// } +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignLinearPattern::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_PolarPattern +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPolarPattern); + +CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() + : Command("PartDesign_PolarPattern") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("PolarPattern"); + sToolTipText = QT_TR_NOOP("Create a polar pattern feature"); + sWhatsThis = "PartDesign_PolarPattern"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_PolarPattern"; +} + +void CmdPartDesignPolarPattern::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("PolarPattern"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("PolarPattern"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +======= +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("PolarPattern"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("PolarPattern"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); +// if (sketch) +// doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", +// FeatName.c_str(), sketch->getNameInDocument()); +// doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// App::DocumentObjectGroup* grp = sketch->getGroup(); +// if (grp) { +// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" +// ,grp->getNameInDocument(),sketch->getNameInDocument()); +// } +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignPolarPattern::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Scaled +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignScaled); + +CmdPartDesignScaled::CmdPartDesignScaled() + : Command("PartDesign_Scaled") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Scaled"); + sToolTipText = QT_TR_NOOP("Create a scaled feature"); + sWhatsThis = "PartDesign_Scaled"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Scaled"; +} + +void CmdPartDesignScaled::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("Scaled"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("Scaled"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +======= +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("Scaled"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("Scaled"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); +// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); +// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) +// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignScaled::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_MultiTransform +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMultiTransform); + +CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() + : Command("PartDesign_MultiTransform") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("MultiTransform"); + sToolTipText = QT_TR_NOOP("Create a multitransform feature"); + sWhatsThis = "PartDesign_MultiTransform"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_MultiTransform"; +} + +void CmdPartDesignMultiTransform::activated(int iMsg) +{ +<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("MultiTransform"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("MultiTransform"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +======= +// // Get a valid original from the user +// // First check selections +// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // Next create a list of all eligible objects +// if (features.size() == 0) { +// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); +// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); +// features.insert(features.end(), subtractive.begin(), subtractive.end()); +// // If there is more than one selected or eligible object, show dialog and let user pick one +// if (features.size() > 1) { +// PartDesignGui::FeaturePickDialog Dlg(features); +// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) +// return; // Cancelled or nothing selected +// } else { +// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), +// QObject::tr("Please create a subtractive or additive feature first, please")); +// return; +// } +// } +// +// std::string FeatName = getUniqueObjectName("MultiTransform"); +// +// std::stringstream str; +// std::vector tempSelNames; +// str << "App.activeDocument()." << FeatName << ".Originals = ["; +// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ +// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; +// tempSelNames.push_back((*it)->getNameInDocument()); +// } +// str << "]"; +// +// openCommand("MultiTransform"); +// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); +// updateActive(); +// doCommand(Doc,str.str().c_str()); +// +// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +// +// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); +// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +>>>>>>> switch PartDesign to Bodies +} + +bool CmdPartDesignMultiTransform::isActive(void) +{ + return hasActiveDocument(); +} + + +//=========================================================================== +// Initialization +//=========================================================================== + +void CreatePartDesignCommands(void) +{ + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + + rcCmdMgr.addCommand(new CmdPartDesignPad()); + rcCmdMgr.addCommand(new CmdPartDesignPocket()); + rcCmdMgr.addCommand(new CmdPartDesignRevolution()); +// rcCmdMgr.addCommand(new CmdPartDesignGroove()); + rcCmdMgr.addCommand(new CmdPartDesignFillet()); +// rcCmdMgr.addCommand(new CmdPartDesignDraft()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignChamfer()); +// rcCmdMgr.addCommand(new CmdPartDesignMirrored()); +// rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); +// rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); +// //rcCmdMgr.addCommand(new CmdPartDesignScaled()); +// rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + } diff --git a/src/Mod/PartDesign/Gui/PreCompiled.h b/src/Mod/PartDesign/Gui/PreCompiled.h index a473c289ae59..4fd34892adba 100644 --- a/src/Mod/PartDesign/Gui/PreCompiled.h +++ b/src/Mod/PartDesign/Gui/PreCompiled.h @@ -29,7 +29,7 @@ // Importing of App classes #ifdef FC_OS_WIN32 # define PartDesignExport __declspec(dllimport) -# define PartDesignGuiExport __declspec(dllexport) +# define PartDesignGuiExport __declspec(dllexport) # define PartExport __declspec(dllimport) # define PartGuiExport __declspec(dllimport) # define SketcherExport __declspec(dllimport) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 7d4b19c1ffc6..bf3b4e1cc992 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -28,7 +28,9 @@ #include "ViewProviderBody.h" #include -//#include +#include +#include +#include using namespace PartDesignGui; @@ -51,4 +53,25 @@ bool ViewProviderBody::doubleClicked(void) return true; } +std::vector ViewProviderBody::claimChildren(void)const +{ + std::vector Model = static_cast(getObject())->Model.getValues(); + std::set OutSet; + + // search for objects handled (claimed) by the features + for(std::vector::const_iterator it = Model.begin();it!=Model.end();++it){ + // sketches of SketchBased features get claimed under the feature so has to be removed from the Body + if ((*it)->isDerivedFrom(PartDesign::SketchBased::getClassTypeId())){ + OutSet.insert(static_cast(*it)->Sketch.getValue()); + } + } + + // remove the otherwise handled objects + std::vector Result(Model.size()); + sort (Model.begin(), Model.end()); + std::vector::iterator it = set_difference (Model.begin(), Model.end(), OutSet.begin(),OutSet.end(), Result.begin()); + + // return the rest as claim set of the Body + return std::vector(Result.begin(),it); +} diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index 18f7de1cd82a..516c7b360ad2 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -40,6 +40,8 @@ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart virtual ~ViewProviderBody(); virtual bool doubleClicked(void); + std::vector claimChildren(void)const; + }; diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index e327a071e0fa..0bc10990438c 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -34,7 +34,6 @@ #include #include #include -#include using namespace PartDesignGui; @@ -85,10 +84,10 @@ void Workbench::activated() )); const char* Face[] = { - "Sketcher_NewSketch", + "PartDesign_NewSketch", "PartDesign_Fillet", "PartDesign_Chamfer", - "PartDesign_Draft", +// "PartDesign_Draft", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 1", @@ -100,7 +99,7 @@ void Workbench::activated() const char* Faces[] = { "PartDesign_Fillet", "PartDesign_Chamfer", - "PartDesign_Draft", +// "PartDesign_Draft", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 2..", @@ -110,12 +109,10 @@ void Workbench::activated() )); const char* Sketch[] = { - "Sketcher_NewSketch", - "Sketcher_EditSketch", + "PartDesign_NewSketch", "PartDesign_Pad", "PartDesign_Pocket", "PartDesign_Revolution", - "PartDesign_Groove", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Sketcher::SketchObject COUNT 1", @@ -124,22 +121,22 @@ void Workbench::activated() "Part_Box" )); - const char* Transformed[] = { - "PartDesign_Mirrored", - "PartDesign_LinearPattern", - "PartDesign_PolarPattern", -// "PartDesign_Scaled", - "PartDesign_MultiTransform", - 0}; - Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( - "SELECT PartDesign::SketchBased", - Transformed, - "Transformation tools", - "PartDesign_MultiTransform" - )); +// const char* Transformed[] = { +// "PartDesign_Mirrored", +// "PartDesign_LinearPattern", +// "PartDesign_PolarPattern", +//// "PartDesign_Scaled", +// "PartDesign_MultiTransform", +// 0}; +// Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( +// "SELECT PartDesign::SketchBased", +// Transformed, +// "Transformation tools", +// "PartDesign_MultiTransform" +// )); const char* Empty[] = { - "Sketcher_NewSketch", + "PartDesign_NewSketch", "Part_Box", "Part_Cylinder", 0}; @@ -184,22 +181,26 @@ Gui::MenuItem* Workbench::setupMenuBar() const root->insertItem(item, part); part->setCommand("&Part Design"); SketcherGui::addSketcherWorkbenchSketchActions( *part ); - *part << geom + *part << "PartDesign_NewSketch" + << "Sketcher_LeaveSketch" + << "Sketcher_ViewSketch" + << "Sketcher_MapSketch" + << geom << cons << consaccel << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" - << "PartDesign_Groove" +// << "PartDesign_Groove" << "PartDesign_Fillet" - << "PartDesign_Chamfer" - << "PartDesign_Draft" - << "PartDesign_Mirrored" - << "PartDesign_LinearPattern" - << "PartDesign_PolarPattern" + << "PartDesign_Chamfer"; +// << "PartDesign_Draft" +// << "PartDesign_Mirrored" +// << "PartDesign_LinearPattern" +// << "PartDesign_PolarPattern" // << "PartDesign_Scaled" - << "PartDesign_MultiTransform"; +// << "PartDesign_MultiTransform"; // For 0.13 a couple of python packages like numpy, matplotlib and others // are not deployed with the installer on Windows. Thus, the WizardShaft is // not deployed either hence the check for the existence of the command. @@ -218,20 +219,23 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand("Part Design"); - SketcherGui::addSketcherWorkbenchSketchActions( *part ); - *part << "Separator" +// TODO: reenable features than rebasing +// SketcherGui::addSketcherWorkbenchSketchActions( *part ); + *part << "PartDesign_NewSketch" + << "Sketcher_LeaveSketch" + << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" - << "PartDesign_Groove" +// << "PartDesign_Groove" << "PartDesign_Fillet" - << "PartDesign_Chamfer" - << "PartDesign_Draft" - << "PartDesign_Mirrored" - << "PartDesign_LinearPattern" - << "PartDesign_PolarPattern" + << "PartDesign_Chamfer"; +// << "PartDesign_Draft" +// << "PartDesign_Mirrored" +// << "PartDesign_LinearPattern" +// << "PartDesign_PolarPattern" // << "PartDesign_Scaled" - << "PartDesign_MultiTransform"; +// << "PartDesign_MultiTransform"; Gui::ToolBarItem* geom = new Gui::ToolBarItem(root); geom->setCommand("Sketcher geometries"); diff --git a/src/Mod/Sketcher/Gui/PreCompiled.h b/src/Mod/Sketcher/Gui/PreCompiled.h index 501c7ac9e6cd..8e1a525484f3 100644 --- a/src/Mod/Sketcher/Gui/PreCompiled.h +++ b/src/Mod/Sketcher/Gui/PreCompiled.h @@ -28,9 +28,9 @@ // Importing of App classes #ifdef FC_OS_WIN32 -# define SketcherExport __declspec(dllimport) -# define PartExport __declspec(dllimport) -# define PartGuiExport __declspec(dllimport) +# define SketcherExport __declspec(dllimport) +# define PartExport __declspec(dllimport) +# define PartGuiExport __declspec(dllimport) # define SketcherGuiExport __declspec(dllexport) #else // for Linux # define SketcherExport diff --git a/src/Mod/Sketcher/Gui/SketchOrientationDialog.h b/src/Mod/Sketcher/Gui/SketchOrientationDialog.h index cf74dd4dd7ce..a2782c0e4e72 100644 --- a/src/Mod/Sketcher/Gui/SketchOrientationDialog.h +++ b/src/Mod/Sketcher/Gui/SketchOrientationDialog.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2011 Jürgen Riegel * + * Copyright (c) 2011 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * @@ -29,7 +29,7 @@ namespace SketcherGui { class Ui_SketchOrientationDialog; -class SketchOrientationDialog : public QDialog +class SketcherGuiExport SketchOrientationDialog : public QDialog { Q_OBJECT From f5cfa8d72ae98f0c4a425dfa39928e47f5aa0c11 Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 17 May 2012 17:20:44 +0200 Subject: [PATCH 030/664] change inheritance of Item (again) --- src/Mod/Assembly/App/Item.cpp | 2 +- src/Mod/Assembly/App/Item.h | 7 +++++-- src/Mod/Assembly/App/ItemAssembly.cpp | 24 ++++++++++++++---------- src/Mod/Assembly/App/ItemAssembly.h | 2 ++ src/Mod/Assembly/App/ItemPart.cpp | 11 +++++++++-- src/Mod/Assembly/App/ItemPart.h | 2 ++ src/Mod/Assembly/Gui/ViewProvider.cpp | 2 +- src/Mod/Assembly/Gui/ViewProvider.h | 4 ++-- 8 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index b41a0a3273c5..98d339352c92 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -36,7 +36,7 @@ using namespace Assembly; namespace Assembly { -PROPERTY_SOURCE(Assembly::Item, Part::Feature) +PROPERTY_SOURCE_ABSTRACT(Assembly::Item, App::GeoFeature) Item::Item() { diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index 8119b4b36e8c..c995f6057b3f 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -25,13 +25,14 @@ #define Assembly_Item_H #include -#include +#include +#include namespace Assembly { -class AssemblyExport Item : public Part::Feature +class AssemblyExport Item : public App::GeoFeature { PROPERTY_HEADER(Assembly::Item); @@ -72,6 +73,8 @@ class AssemblyExport Item : public Part::Feature } //@} + virtual TopoDS_Shape getShape(void)const =0 ; + PyObject *getPyObject(void); }; diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 159a11abb289..7ef0829553d8 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -53,6 +53,12 @@ short ItemAssembly::mustExecute() const } App::DocumentObjectExecReturn *ItemAssembly::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +TopoDS_Shape ItemAssembly::getShape(void) const { std::vector s; std::vector obj = Items.getValues(); @@ -60,7 +66,7 @@ App::DocumentObjectExecReturn *ItemAssembly::execute(void) std::vector::iterator it; for (it = obj.begin(); it != obj.end(); ++it) { if ((*it)->getTypeId().isDerivedFrom(Assembly::Item::getClassTypeId())) { - TopoDS_Shape aShape = static_cast(*it)->Shape.getValue(); + TopoDS_Shape aShape = static_cast(*it)->getShape(); if (!aShape.IsNull()) s.push_back(aShape); } @@ -75,15 +81,13 @@ App::DocumentObjectExecReturn *ItemAssembly::execute(void) aBuilder.Add(aRes, *it); } - if (aRes.IsNull()) - throw Base::Exception("Resulting shape is invalid"); - this->Shape.setValue(aRes); - } - else { - // set empty shape - this->Shape.setValue(TopoDS_Shape()); + //if (aRes.IsNull()) + // throw Base::Exception("Resulting shape is invalid"); + return aRes; } - return App::DocumentObject::StdReturn; + // set empty shape + return TopoDS_Compound(); + } -} +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 3011771220d2..5d7a882c8653 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -50,6 +50,8 @@ class AssemblyExport ItemAssembly : public Assembly::Item return "AssemblyGui::ViewProviderItemAssembly"; } //@} + + virtual TopoDS_Shape getShape(void) const; }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index a74d6c527633..f2911f676f69 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -28,6 +28,7 @@ #include #include "ItemPart.h" +#include using namespace Assembly; @@ -52,14 +53,20 @@ short ItemPart::mustExecute() const } App::DocumentObjectExecReturn *ItemPart::execute(void) +{ + return App::DocumentObject::StdReturn; +} + +TopoDS_Shape ItemPart::getShape(void) const { App::DocumentObject* obj = Model.getValue(); if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - this->Shape.setValue(static_cast(obj)->Shape.getValue()); + return static_cast(obj)->Shape.getValue(); } - return App::DocumentObject::StdReturn; + return TopoDS_Shape(); + } } \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h index f2854d9ed5c9..d1d77cc2923e 100644 --- a/src/Mod/Assembly/App/ItemPart.h +++ b/src/Mod/Assembly/App/ItemPart.h @@ -51,6 +51,8 @@ class AssemblyExport ItemPart : public Assembly::Item return "AssemblyGui::ViewProviderItemPart"; } //@} + + virtual TopoDS_Shape getShape(void) const; }; } //namespace Assembly diff --git a/src/Mod/Assembly/Gui/ViewProvider.cpp b/src/Mod/Assembly/Gui/ViewProvider.cpp index 5b0fd1474fb7..5807f0493821 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.cpp +++ b/src/Mod/Assembly/Gui/ViewProvider.cpp @@ -34,7 +34,7 @@ using namespace AssemblyGui; -PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,PartGui::ViewProviderPart) +PROPERTY_SOURCE(AssemblyGui::ViewProviderItem,Gui::ViewProviderGeometryObject) ViewProviderItem::ViewProviderItem() { diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h index e3462c28cce2..fd76f56ab2d2 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.h +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -24,13 +24,13 @@ #ifndef ASSEMBLYGUI_ViewProvider_H #define ASSEMBLYGUI_ViewProvider_H -#include +#include class SoGroup; namespace AssemblyGui { -class AssemblyGuiExport ViewProviderItem : public PartGui::ViewProviderPart +class AssemblyGuiExport ViewProviderItem : public Gui::ViewProviderGeometryObject { PROPERTY_HEADER(AssemblyGui::ViewProviderItem); From db460cff8a1a3ca98b2d3f541fc3c38b1c0a9667 Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 18 May 2012 14:43:35 +0200 Subject: [PATCH 031/664] auto WB switching for editing Sketches and new TaskWatcher --- src/Gui/TaskView/TaskWatcher.cpp | 1 + src/Mod/PartDesign/Gui/Workbench.cpp | 28 +++++++++++++-------- src/Mod/PartDesign/Gui/Workbench.h | 2 ++ src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 6 +++++ src/Mod/Sketcher/Gui/ViewProviderSketch.h | 1 + 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Gui/TaskView/TaskWatcher.cpp b/src/Gui/TaskView/TaskWatcher.cpp index 4c6f99d6345c..4a7d1434519d 100644 --- a/src/Gui/TaskView/TaskWatcher.cpp +++ b/src/Gui/TaskView/TaskWatcher.cpp @@ -169,4 +169,5 @@ bool TaskWatcherCommandsEmptySelection::shouldShow() return (App::GetApplication().getActiveDocument() && Gui::Selection().size() == 0); } + #include "moc_TaskWatcher.cpp" diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 0bc10990438c..ecc5a04d7b0b 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -35,6 +35,8 @@ #include #include +#include + using namespace PartDesignGui; #if 0 // needed for Qt's lupdate utility @@ -44,6 +46,9 @@ using namespace PartDesignGui; qApp->translate("Gui::TaskView::TaskWatcherCommands", "Create Geometry"); #endif +extern PartDesign::Body *ActivePartObject; + + /// @namespace PartDesignGui @class Workbench TYPESYSTEM_SOURCE(PartDesignGui::Workbench, Gui::StdWorkbench) @@ -62,16 +67,7 @@ void Workbench::activated() std::vector Watcher; - //Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( - // "FROM Robot SELECT TrajectoryObject COUNT 1" - // "FROM Robot SELECT RobotObject COUNT 1", - // RobotAndTrac, - // "Trajectory tools", - // "Robot_InsertWaypoint" - //)); - - //Watcher.push_back(new TaskWatcherRobot); - + const char* Edge[] = { "PartDesign_Fillet", "PartDesign_Chamfer", @@ -149,15 +145,27 @@ void Workbench::activated() addTaskWatcher(Watcher); Gui::Control().showTaskView(); + + // set the previous used active Body + if(oldActive != "") + Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(App.activeDocument().%s)",oldActive.c_str()); + } void Workbench::deactivated() { + // remember the body for later activation + if(ActivePartObject) + oldActive = ActivePartObject->getNameInDocument(); + else + oldActive = ""; + // reset the active Body Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(None)"); Gui::Workbench::deactivated(); removeTaskWatcher(); + } Gui::MenuItem* Workbench::setupMenuBar() const diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 1d92729707e9..02220f870ed3 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -48,6 +48,8 @@ class PartDesignGuiExport Workbench : public Gui::StdWorkbench Gui::MenuItem* setupMenuBar() const; Gui::ToolBarItem* setupToolBars() const; Gui::ToolBarItem* setupCommandBars() const; + + std::string oldActive; }; } // namespace PartDesignGui diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 850397670bf4..e6e6466f2220 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -4156,6 +4156,9 @@ void ViewProviderSketch::setupContextMenu(QMenu *menu, QObject *receiver, const bool ViewProviderSketch::setEdit(int ModNum) { + // always change to sketcher WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("SketcherWorkbench"); + // When double-clicking on the item for this sketch the // object unsets and sets its edit mode without closing // the task panel @@ -4580,6 +4583,9 @@ void ViewProviderSketch::unsetEdit(int ModNum) // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); + + // return to the WB before edeting the sketch + Gui::Command::assureWorkbench(oldWb.c_str()); } void ViewProviderSketch::setEditViewer(Gui::View3DInventorViewer* viewer, int ModNum) diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 5511f9407d3f..3a718277de23 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -382,6 +382,7 @@ class SketcherGuiExport ViewProviderSketch : public PartGui::ViewProvider2DObjec bool relative; Gui::Rubberband* rubberband; + std::string oldWb; }; } // namespace PartGui From 71b9ded9a195e4042349ea4b38f7214e0dfa5591 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 19 May 2012 17:59:24 +0200 Subject: [PATCH 032/664] some adjustments on WB auto-switch --- src/Mod/PartDesign/Gui/Workbench.cpp | 10 +++++----- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index ecc5a04d7b0b..380f227551df 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -142,18 +142,19 @@ void Workbench::activated() "Part_Box" )); + // set the previous used active Body + if(oldActive != "") + Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(App.activeDocument().%s)",oldActive.c_str()); addTaskWatcher(Watcher); Gui::Control().showTaskView(); - // set the previous used active Body - if(oldActive != "") - Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(App.activeDocument().%s)",oldActive.c_str()); - + } void Workbench::deactivated() { + removeTaskWatcher(); // remember the body for later activation if(ActivePartObject) oldActive = ActivePartObject->getNameInDocument(); @@ -163,7 +164,6 @@ void Workbench::deactivated() Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(None)"); Gui::Workbench::deactivated(); - removeTaskWatcher(); } diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index e6e6466f2220..a77323db2ecf 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -4584,6 +4584,8 @@ void ViewProviderSketch::unsetEdit(int ModNum) // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); + //Gui::Application::Instance-> + // return to the WB before edeting the sketch Gui::Command::assureWorkbench(oldWb.c_str()); } From 8f11dc549278c55511d85db14f4c731a521f530d Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 19 May 2012 19:39:38 +0200 Subject: [PATCH 033/664] start Constraints --- src/Mod/Assembly/App/ItemAssembly.h | 1 + src/Mod/Assembly/Gui/CMakeLists.txt | 2 + src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 7 +- .../Gui/ViewProviderConstraintGroup.cpp | 95 +++++++++++++++++++ .../Gui/ViewProviderConstraintGroup.h | 59 ++++++++++++ 5 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 5d7a882c8653..156f1f6d8d8b 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -39,6 +39,7 @@ class AssemblyExport ItemAssembly : public Assembly::Item ItemAssembly(); App::PropertyLinkList Items; + App::PropertyLinkList Annotations; /** @name methods override feature */ //@{ diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 21be6e185742..b28a58e02b06 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -35,6 +35,8 @@ SET(AssemblyGuiViewProvider_SRCS ViewProviderPart.h ViewProviderAssembly.cpp ViewProviderAssembly.h + ViewProviderConstraintGroup.cpp + ViewProviderConstraintGroup.h ) SOURCE_GROUP("ViewProvider" FILES ${AssemblyGuiViewProvider_SRCS}) diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 49fe6fa71c40..ca1d578d31ef 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -84,9 +84,12 @@ std::vector ViewProviderItemAssembly::getDisplayModes(void) const std::vector ViewProviderItemAssembly::claimChildren(void)const { + std::vector temp(static_cast(getObject())->Items.getValues()); + temp.insert(temp.end(), + static_cast(getObject())->Annotations.getValues().begin(), + static_cast(getObject())->Annotations.getValues().end()); - return static_cast(getObject())->Items.getValues(); - + return temp; } std::vector ViewProviderItemAssembly::claimChildren3D(void)const diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp new file mode 100644 index 000000000000..02bab39c48f2 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 +#endif + +#include "ViewProviderConstraintGroup.h" +#include +#include + +#include + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintGroup,Gui::ViewProviderDocumentObject) + +ViewProviderConstraintGroup::ViewProviderConstraintGroup() +{ +} + +ViewProviderConstraintGroup::~ViewProviderConstraintGroup() +{ +} + +bool ViewProviderConstraintGroup::doubleClicked(void) +{ + return false; +} + +void ViewProviderConstraintGroup::attach(App::DocumentObject *pcFeat) +{ + // call parent attach method + ViewProviderDocumentObject::attach(pcFeat); + + + // putting all together with the switch + addDisplayMaskMode(getChildRoot(), "Main"); +} + +void ViewProviderConstraintGroup::setDisplayMode(const char* ModeName) +{ + if ( strcmp("Main",ModeName)==0 ) + setDisplayMaskMode("Main"); + + ViewProviderDocumentObject::setDisplayMode( ModeName ); +} + +std::vector ViewProviderConstraintGroup::getDisplayModes(void) const +{ + // get the modes of the father + std::vector StrList = ViewProviderDocumentObject::getDisplayModes(); + + // add your own modes + StrList.push_back("Main"); + + return StrList; +} + + +std::vector ViewProviderConstraintGroup::claimChildren(void)const +{ + std::vector temp(static_cast(getObject())->Constraints.getValues()); + + return temp; +} + +std::vector ViewProviderConstraintGroup::claimChildren3D(void)const +{ + + //return static_cast(getObject())->Constraints.getValues(); + return std::vector (); +} diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h new file mode 100644 index 000000000000..dabcb2af9587 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 ASSEMBLYGUI_ViewProviderConstraintGroup_H +#define ASSEMBLYGUI_ViewProviderConstraintGroup_H + +#include + + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintGroup : public Gui::ViewProviderDocumentObject +{ + PROPERTY_HEADER(PartGui::ViewProviderConstraintGroup); + +public: + /// constructor + ViewProviderConstraintGroup(); + /// destructor + virtual ~ViewProviderConstraintGroup(); + + virtual bool doubleClicked(void); + virtual void attach(App::DocumentObject *); + virtual void setDisplayMode(const char* ModeName); + /// returns a list of all possible modes + virtual std::vector getDisplayModes(void) const; + + virtual std::vector claimChildren(void)const; + + virtual std::vector claimChildren3D(void)const; + +}; + + + +} // namespace AssemblyGui + + +#endif // ASSEMBLYGUI_ViewProviderAssembly_H From f29c33c7dc1066518295b1d322fac2382e32634a Mon Sep 17 00:00:00 2001 From: jriegel Date: Sat, 19 May 2012 19:45:26 +0200 Subject: [PATCH 034/664] add .gitignore for *.pyc files --- src/Tools/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/Tools/.gitignore diff --git a/src/Tools/.gitignore b/src/Tools/.gitignore new file mode 100644 index 000000000000..f52f64fbf925 --- /dev/null +++ b/src/Tools/.gitignore @@ -0,0 +1,4 @@ +# ignore the pyc files created while compile +*.pyc +generateBase/*.pyc +generateTemplates/*.pyc From b08b2f6140da1fcba7212b58653f124398461a24 Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 24 May 2012 15:04:34 +0200 Subject: [PATCH 035/664] addition of constraints --- src/Mod/Assembly/App/AppAssembly.cpp | 18 ++++++ src/Mod/Assembly/App/ConstraintGroup.h | 6 +- src/Mod/Assembly/App/ItemAssembly.cpp | 1 + src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 3 + src/Mod/Assembly/Gui/CommandConstraints.cpp | 61 ++++++++++++++++++- .../Gui/ViewProviderConstraintGroup.cpp | 6 +- 6 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index d46f1d4d946c..773af74c3cfb 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -34,6 +34,14 @@ #include "ItemAssembly.h" #include "ItemPart.h" +#include "ConstraintAngle.h" +#include "ConstraintAxis.h" +#include "ConstraintContact.h" +#include "ConstraintFix.h" +#include "ConstraintGroup.h" +#include "ConstraintOffset.h" + + extern struct PyMethodDef Assembly_methods[]; PyDoc_STRVAR(module_Assembly_doc, @@ -64,9 +72,19 @@ void AssemblyExport initAssembly() // call PyType_Ready, otherwise we run into a segmentation fault, later on. // This function is responsible for adding inherited slots from a type's base class. + // Item hirachy Assembly::Item ::init(); Assembly::ItemAssembly ::init(); Assembly::ItemPart ::init(); + + // constraint hirachy + Assembly::Constraint ::init(); + Assembly::ConstraintAngle ::init(); + Assembly::ConstraintAxis ::init(); + Assembly::ConstraintContact ::init(); + Assembly::ConstraintFix ::init(); + Assembly::ConstraintOffset ::init(); + Assembly::ConstraintGroup ::init(); } } // extern "C" diff --git a/src/Mod/Assembly/App/ConstraintGroup.h b/src/Mod/Assembly/App/ConstraintGroup.h index 15406dacd2f1..2d4157666b38 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.h +++ b/src/Mod/Assembly/App/ConstraintGroup.h @@ -46,9 +46,9 @@ class AssemblyExport ConstraintGroup : public App::DocumentObject App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraintGroup"; - //} + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintGroup"; + } //@} }; diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 7ef0829553d8..e6e6563a84c7 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -42,6 +42,7 @@ PROPERTY_SOURCE(Assembly::ItemAssembly, Assembly::Item) ItemAssembly::ItemAssembly() { ADD_PROPERTY(Items,(0)); + ADD_PROPERTY(Annotations,(0)); } short ItemAssembly::mustExecute() const diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index 97e128262aec..c0acd9477309 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -35,6 +35,7 @@ #include "ViewProvider.h" #include "ViewProviderPart.h" #include "ViewProviderAssembly.h" +#include "ViewProviderConstraintGroup.h" #include @@ -82,6 +83,8 @@ void AssemblyGuiExport initAssemblyGui() AssemblyGui::ViewProviderItemPart ::init(); AssemblyGui::ViewProviderItemAssembly::init(); + AssemblyGui::ViewProviderConstraintGroup::init(); + // add resources and reloads the translators loadAssemblyResource(); } diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index 083a9c1dd962..6ef91bffc26a 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include @@ -30,11 +31,58 @@ #include #include +#include +#include + using namespace std; +extern Assembly::Item *ActiveAsmObject; + +// Helper methods =========================================================== + +Assembly::ConstraintGroup * getConstraintGroup(Assembly::ItemAssembly *Asm) +{ + Assembly::ConstraintGroup *ConstGrp = 0; + std::vector Ano = Asm->Annotations.getValues(); + for(std::vector::const_iterator it = Ano.begin();it!=Ano.end();++it){ + if((*it)->getTypeId().isDerivedFrom(Assembly::ConstraintGroup::getClassTypeId() )){ + ConstGrp = static_cast(*it); + break; + } + } + return ConstGrp; +} + +bool getConstraintPrerequisits(Assembly::ItemAssembly **Asm,Assembly::ConstraintGroup **ConstGrp) +{ + if(!ActiveAsmObject || !ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Assembly"), + QObject::tr("You need a active (blue) Assembly to insert a Constraint. Please create a new one or make one active (double click).")); + return true; + } + *Asm = static_cast(ActiveAsmObject); + + // find the Constraint group of the active Assembly + *ConstGrp = getConstraintGroup(*Asm); + // if it hasen't aleardy one, create one: + if(!*ConstGrp){ + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ConstraintGroup','ConstraintGroup')"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = 'ConstraintGroup'"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Annotations = App.activeDocument().%s.Annotations + [App.activeDocument().ActiveObject]",(*Asm)->getNameInDocument(),(*Asm)->getNameInDocument()); + + } + // find now + *ConstGrp = getConstraintGroup(*Asm); + if(!*ConstGrp) + throw Base::Exception("Could not create Assembly::ConstraintGroup in active Assembly"); + + // return with no error + return false; + +} //=========================================================================== DEF_STD_CMD(CmdAssemblyConstraintAxle); @@ -54,8 +102,17 @@ CmdAssemblyConstraintAxle::CmdAssemblyConstraintAxle() void CmdAssemblyConstraintAxle::activated(int iMsg) { - // load the file with the module - //Command::doCommand(Command::Gui, "import Assembly, AssemblyGui"); + Assembly::ItemAssembly *Asm=0; + Assembly::ConstraintGroup *ConstGrp=0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm,&ConstGrp)) + return; + + openCommand("Insert Constraint Axle"); + std::string ConstrName = getUniqueObjectName("Axle"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); } diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp index 02bab39c48f2..1a10eda3f894 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp @@ -57,7 +57,7 @@ void ViewProviderConstraintGroup::attach(App::DocumentObject *pcFeat) // putting all together with the switch - addDisplayMaskMode(getChildRoot(), "Main"); +// addDisplayMaskMode(getChildRoot(), "Main"); } void ViewProviderConstraintGroup::setDisplayMode(const char* ModeName) @@ -65,7 +65,7 @@ void ViewProviderConstraintGroup::setDisplayMode(const char* ModeName) if ( strcmp("Main",ModeName)==0 ) setDisplayMaskMode("Main"); - ViewProviderDocumentObject::setDisplayMode( ModeName ); +// ViewProviderDocumentObject::setDisplayMode( ModeName ); } std::vector ViewProviderConstraintGroup::getDisplayModes(void) const @@ -74,7 +74,7 @@ std::vector ViewProviderConstraintGroup::getDisplayModes(void) cons std::vector StrList = ViewProviderDocumentObject::getDisplayModes(); // add your own modes - StrList.push_back("Main"); +// StrList.push_back("Main"); return StrList; } From 2403af2e6c6331a4908fa7d7d9a6174e0759cbd4 Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 23 Aug 2012 17:14:56 +0200 Subject: [PATCH 036/664] Fix bug in switching active Part/Assembly object when document with active one was closed --- src/Gui/TaskView/TaskWatcher.cpp | 7 +---- src/Gui/TaskView/TaskWatcher.h | 4 +-- src/Mod/Assembly/App/AppAssemblyPy.cpp | 33 ++++++++++++++--------- src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 31 ++++++++++++--------- 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/Gui/TaskView/TaskWatcher.cpp b/src/Gui/TaskView/TaskWatcher.cpp index 4a7d1434519d..5e08c71d1485 100644 --- a/src/Gui/TaskView/TaskWatcher.cpp +++ b/src/Gui/TaskView/TaskWatcher.cpp @@ -102,9 +102,6 @@ TaskWatcherCommands::TaskWatcherCommands(const char* Filter,const char* commands Content.push_back(tb); } -TaskWatcherCommands::~TaskWatcherCommands() -{ -} //==== implementer =========================================================================== @@ -128,9 +125,7 @@ TaskWatcherCommandsEmptyDoc::TaskWatcherCommandsEmptyDoc(const char* commands[], { } -TaskWatcherCommandsEmptyDoc::~TaskWatcherCommandsEmptyDoc() -{ -} + //==== implementer =========================================================================== diff --git a/src/Gui/TaskView/TaskWatcher.h b/src/Gui/TaskView/TaskWatcher.h index 613bec7ecbbb..cd6e26df2e11 100644 --- a/src/Gui/TaskView/TaskWatcher.h +++ b/src/Gui/TaskView/TaskWatcher.h @@ -48,7 +48,7 @@ class GuiExport TaskWatcher : public QObject, public Gui::SelectionFilter public: TaskWatcher(const char* Filter); - ~TaskWatcher(); + virtual ~TaskWatcher(); std::vector &getWatcherContent(void); @@ -71,7 +71,6 @@ class GuiExport TaskWatcherCommands : public TaskWatcher public: TaskWatcherCommands(const char* Filter,const char* commands[], const char* name, const char* pixmap); - ~TaskWatcherCommands(); public: /// is called wenn the document or the Selection changes. @@ -88,7 +87,6 @@ class GuiExport TaskWatcherCommandsEmptyDoc : public TaskWatcherCommands public: TaskWatcherCommandsEmptyDoc(const char* commands[], const char* name, const char* pixmap); - ~TaskWatcherCommandsEmptyDoc(); public: /// is called wenn the document or the Selection changes. diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 30ff96e6184a..133c8fdd5d8a 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -38,34 +38,41 @@ // pointer to the active assembly object PartDesign::Body *ActivePartObject =0; -Gui::Document *ActiveGuiDoc =0; -Gui::ViewProviderDocumentObject *ActiveVp =0; +Gui::Document *ActiveGuiDoc =0; +App::Document *ActiveAppDoc =0; +Gui::ViewProviderDocumentObject *ActiveVp =0; static PyObject * setActivePart(PyObject *self, PyObject *args) { + if(ActivePartObject){ + // check if the document not already closed + std::vector docs = App::GetApplication().getDocuments(); + for(std::vector::const_iterator it=docs.begin();it!=docs.end();++it) + if(*it == ActiveAppDoc){ + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,false); + break; + } + + ActivePartObject = 0; + ActiveGuiDoc =0; + ActiveAppDoc =0; + ActiveVp =0; + } + PyObject *object=0; if (PyArg_ParseTuple(args,"|O!",&(PartDesign::BodyPy::Type), &object)&& object) { PartDesign::Body* Item = static_cast(object)->getBodyPtr(); // Should be set! assert(Item); - // get the gui document of the Assembly Item - if(ActivePartObject){ - - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); - ActivePartObject = 0; - - } ActivePartObject = Item; - ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); + ActiveAppDoc = Item->getDocument(); + ActiveGuiDoc = Gui::Application::Instance->getDocument(ActiveAppDoc); ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,true); - }else{ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,false); - ActivePartObject = 0; } Py_Return; diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index 0409d69ae205..22efa4eca6c3 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -39,13 +39,29 @@ // pointer to the active assembly object Assembly::Item *ActiveAsmObject =0; Gui::Document *ActiveGuiDoc =0; +App::Document *ActiveAppDoc =0; Gui::ViewProviderDocumentObject *ActiveVp =0; /* module functions */ static PyObject * setActiveAssembly(PyObject *self, PyObject *args) -{ +{ + if(ActiveAsmObject){ + // check if the document not already closed + std::vector docs = App::GetApplication().getDocuments(); + for(std::vector::const_iterator it=docs.begin();it!=docs.end();++it) + if(*it == ActiveAppDoc){ + ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); + break; + } + + ActiveAsmObject = 0; + ActiveGuiDoc =0; + ActiveAppDoc =0; + ActiveVp =0; + } + PyObject *object=0; if (PyArg_ParseTuple(args,"|O!",&(Assembly::ItemPy::Type), &object)&& object) { Assembly::Item* Item = static_cast(object)->getItemPtr(); @@ -53,20 +69,11 @@ static PyObject * setActiveAssembly(PyObject *self, PyObject *args) assert(Item); // get the gui document of the Assembly Item - if(ActiveAsmObject){ - - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); - ActiveAsmObject = 0; - - } ActiveAsmObject = Item; - ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); + ActiveAppDoc = Item->getDocument(); + ActiveGuiDoc = Gui::Application::Instance->getDocument(ActiveAppDoc); ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); - - }else{ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); - ActiveAsmObject = 0; } Py_Return; From 50652895d42bb8034995860b6f6711f388fb8d06 Mon Sep 17 00:00:00 2001 From: jriegel Date: Fri, 24 Aug 2012 18:27:53 +0200 Subject: [PATCH 037/664] 3D subgrouping for Body --- src/Mod/PartDesign/App/Body.cpp | 5 ++--- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 13 +++++++++++++ src/Mod/PartDesign/Gui/ViewProviderBody.h | 6 ++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 7110e04a08b1..0b5bbb8308ff 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -45,9 +45,8 @@ Body::Body() short Body::mustExecute() const { - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; + if (Tip.isTouched() ) + return 1; return 0; } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index bf3b4e1cc992..0d2eb1412f76 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include #endif #include "ViewProviderBody.h" @@ -38,10 +39,15 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderBody,PartGui::ViewProviderPart) ViewProviderBody::ViewProviderBody() { + pcBodyChildren = new SoGroup(); + pcBodyChildren->ref(); + } ViewProviderBody::~ViewProviderBody() { + pcBodyChildren->unref(); + pcBodyChildren = 0; } bool ViewProviderBody::doubleClicked(void) @@ -75,3 +81,10 @@ std::vector ViewProviderBody::claimChildren(void)const return std::vector(Result.begin(),it); } + +std::vector ViewProviderBody::claimChildren3D(void)const +{ + + return static_cast(getObject())->Model.getValues(); + +} diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index 516c7b360ad2..d416d01298ec 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -42,6 +42,12 @@ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart virtual bool doubleClicked(void); std::vector claimChildren(void)const; + // returns the root node where the children gets collected(3D) + virtual SoGroup* getChildRoot(void) const {return pcBodyChildren;} + std::vector claimChildren3D(void)const; + +private: + SoGroup *pcBodyChildren; }; From aa216ee69d077763b064b60daa44359af6b223ac Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 2 Jan 2013 12:31:04 +0100 Subject: [PATCH 038/664] Some fixes in Body visualls (ongoing) --- src/Mod/Assembly/Gui/ViewProvider.h | 1 + src/Mod/PartDesign/App/Body.cpp | 19 ++++++++- src/Mod/PartDesign/Gui/Command.cpp | 31 ++++++++------- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 43 ++++++++++++++++++++- src/Mod/PartDesign/Gui/ViewProviderBody.h | 14 +++++++ 5 files changed, 91 insertions(+), 17 deletions(-) diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h index fd76f56ab2d2..7cc1a3a7f9b7 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.h +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -48,6 +48,7 @@ class AssemblyGuiExport ViewProviderItem : public Gui::ViewProviderGeometryObjec virtual bool doubleClicked(void); private: + /// group node for all children collected through claimChildren3D(), reused by all Assembly ViewProviders SoGroup *pcChildren; }; diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 0b5bbb8308ff..0af02620ef07 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -27,6 +27,7 @@ #include +#include "Feature.h" #include "Body.h" #include "BodyPy.h" @@ -52,7 +53,23 @@ short Body::mustExecute() const App::DocumentObjectExecReturn *Body::execute(void) { - + // TODO right selection for Body + App::DocumentObject* link = Tip.getValue(); + if (!link) + //return new App::DocumentObjectExecReturn("No object!"); + return App::DocumentObject::StdReturn; + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Linked object is not a PartDesign object"); + //return App::DocumentObject::StdReturn; + // get the shape of the tip + const Part::TopoShape& TipShape = static_cast(link)->Shape.getShape(); + if (TipShape._Shape.IsNull()) + //return new App::DocumentObjectExecReturn("empty shape"); + return App::DocumentObject::StdReturn; + + Shape.setValue(TipShape); + + return App::DocumentObject::StdReturn; } diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 94c6c83c3c83..868229ea5b16 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -75,21 +75,22 @@ void validateSketches(std::vector& sketches, const bool su std::vector::iterator s = sketches.begin(); while (s != sketches.end()) { - // Check whether this sketch is already being used by another feature - std::vector ref = (*s)->getInList(); - std::vector::iterator r = ref.begin(); - while (r != ref.end()) { - if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { - r = ref.erase(r); - continue; - } - ++r; - } - if (!ref.empty()) { - // TODO: Display some information message that this sketch was removed? - s = sketches.erase(s); - continue; - } + // sketch is allways part of the body first. + //// Check whether this sketch is already being used by another feature + //std::vector ref = (*s)->getInList(); + //std::vector::iterator r = ref.begin(); + //while (r != ref.end()) { + // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { + // r = ref.erase(r); + // continue; + // } + // ++r; + //} + //if (!ref.empty()) { + // // TODO: Display some information message that this sketch was removed? + // s = sketches.erase(s); + // continue; + //} // Check whether the sketch shape is valid Part::Part2DObject* sketch = static_cast(*s); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 0d2eb1412f76..1374d2639772 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -41,15 +41,56 @@ ViewProviderBody::ViewProviderBody() { pcBodyChildren = new SoGroup(); pcBodyChildren->ref(); - + pcBodyTip = new SoGroup(); + pcBodyTip->ref(); } ViewProviderBody::~ViewProviderBody() { pcBodyChildren->unref(); pcBodyChildren = 0; + pcBodyTip->unref(); + pcBodyTip = 0; } + +void ViewProviderBody::attach(App::DocumentObject *pcFeat) +{ + // call parent attach method + ViewProviderPart::attach(pcFeat); + + + // putting all together with the switch + addDisplayMaskMode(pcBodyTip, "Body"); + addDisplayMaskMode(pcBodyChildren, "Through"); +} + +void ViewProviderBody::setDisplayMode(const char* ModeName) +{ + if ( strcmp("Body",ModeName)==0 ) + setDisplayMaskMode("Body"); + if ( strcmp("Main",ModeName)==0 ) + setDisplayMaskMode("Main"); + if ( strcmp("Through",ModeName)==0 ) + setDisplayMaskMode("Through"); + + ViewProviderGeometryObject::setDisplayMode( ModeName ); +} + +std::vector ViewProviderBody::getDisplayModes(void) const +{ + // get the modes of the father + std::vector StrList = ViewProviderGeometryObject::getDisplayModes(); + + // add your own modes + StrList.push_back("Through"); + StrList.push_back("Body"); + + return StrList; +} + + + bool ViewProviderBody::doubleClicked(void) { // assure the PartDesign workbench diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index d416d01298ec..667baf7522a9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -29,6 +29,12 @@ namespace PartDesignGui { +/** ViewProvider of the Body feature + * This class manage the visual apperance of the features in the + * Body feature. That mean while editing only the tip feature is + * visible. If the Body is not active it shows only the result shape (tip). + * \author jriegel + */ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart { PROPERTY_HEADER(PartGui::ViewProviderBody); @@ -38,6 +44,11 @@ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart ViewProviderBody(); /// destructor virtual ~ViewProviderBody(); + + virtual void attach(App::DocumentObject *); + virtual void setDisplayMode(const char* ModeName); + /// returns a list of all possible modes + virtual std::vector getDisplayModes(void) const; virtual bool doubleClicked(void); std::vector claimChildren(void)const; @@ -47,7 +58,10 @@ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart std::vector claimChildren3D(void)const; private: + /// group used to store children collected by claimChildren3D() SoGroup *pcBodyChildren; + /// group used to show the tip element in "edit" mode + SoGroup *pcBodyTip; }; From fca3b9dffb5d9a21a3acdaa0bd968f0d913e8c32 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 2 Jan 2013 17:27:14 +0100 Subject: [PATCH 039/664] Added Base planes with the Body --- src/Mod/Assembly/Gui/Command.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 6397d6ae084b..c1ac9f199a12 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -88,23 +88,20 @@ void CmdAssemblyAddNewPart::activated(int iMsg) std::string Plane1Name = BodyName + "_PlaneXY"; std::string Plane2Name = BodyName + "_PlaneYZ"; std::string Plane3Name = BodyName + "_PlaneXZ"; - //doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane1Name.c_str()); - //doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane2Name.c_str()); - //doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(-0.707107,0.000000,0.000000,-0.707107))",Plane2Name.c_str()); - //doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane3Name.c_str()); - //doCommand(Doc,"App.activeDocument().%s.Annotation = [App.activeDocument().%s,App.activeDocument().%s,App.activeDocument().%s] ",PartName.c_str(),Plane1Name.c_str(),Plane2Name.c_str(),Plane3Name.c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane1Name.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane2Name.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')",Plane3Name.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'"); + // add to anotation set of the Part object + doCommand(Doc,"App.activeDocument().%s.Annotation = [App.activeDocument().%s,App.activeDocument().%s,App.activeDocument().%s] ",PartName.c_str(),Plane1Name.c_str(),Plane2Name.c_str(),Plane3Name.c_str()); // add the main body doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str()); -#if 0 // test code for children nesting - Command::addModule(App,"Part"); - std::string BoxName = getUniqueObjectName("Box"); - doCommand(Doc,"App.activeDocument().addObject('Part::Box','%s')",BoxName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",BodyName.c_str(),BoxName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s ",BodyName.c_str(),BoxName.c_str()); -#endif - this->updateActive(); } From fc7db6369cd8c2ad4388be2ff00e261bef2a3097 Mon Sep 17 00:00:00 2001 From: jriegel Date: Wed, 2 Jan 2013 20:44:09 +0100 Subject: [PATCH 040/664] Assembly import script & PartDesign Solid object --- src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 14 ++++++ src/Mod/Assembly/Gui/Command.cpp | 53 ++++++++++++++++------ src/Mod/PartDesign/App/AppPartDesign.cpp | 2 + src/Mod/PartDesign/App/CMakeLists.txt | 2 + src/Mod/PartDesign/App/FeatureSolid.cpp | 44 ++++++++++++++++++ src/Mod/PartDesign/App/FeatureSolid.h | 55 +++++++++++++++++++++++ 6 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 src/Mod/PartDesign/App/FeatureSolid.cpp create mode 100644 src/Mod/PartDesign/App/FeatureSolid.h diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index 22efa4eca6c3..9f75430d330d 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -79,11 +79,25 @@ static PyObject * setActiveAssembly(PyObject *self, PyObject *args) Py_Return; } +/* module functions */ +static PyObject * getActiveAssembly(PyObject *self, PyObject *args) +{ + if(ActiveAsmObject){ + + return ActiveAsmObject->getPyObject(); + } + + + Py_Return; +} + /* registration table */ struct PyMethodDef AssemblyGui_Import_methods[] = { {"setActiveAssembly" ,setActiveAssembly ,METH_VARARGS, "setActiveAssembly(AssemblyObject) -- Set the Assembly object in work."}, + {"getActiveAssembly" ,getActiveAssembly ,METH_VARARGS, + "getActiveAssembly() -- Returns the Assembly object in work."}, {NULL, NULL} /* end of table marker */ }; diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index c1ac9f199a12..bfb3d65db66d 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -175,19 +175,46 @@ void CmdAssemblyAddExistingComponent::activated(int iMsg) return; } - openCommand("Insert TestPart"); - std::string PartName = getUniqueObjectName("Part"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",PartName.c_str()); - if(dest){ - std::string fatherName = dest->getNameInDocument(); - doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),PartName.c_str()); - } - Command::addModule(App,"PartDesign"); - Command::addModule(Gui,"PartDesignGui"); - std::string BodyName = getUniqueObjectName("Body"); - doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",BodyName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s ",PartName.c_str(),BodyName.c_str(),BodyName.c_str()); - + // asking for file name (only step at the moment) + QStringList filter; + filter << QString::fromAscii("STEP (*.stp *.step)"); + filter << QString::fromAscii("STEP with colors (*.stp *.step)"); + filter << QString::fromAscii("IGES (*.igs *.iges)"); + filter << QString::fromAscii("IGES with colors (*.igs *.iges)"); + filter << QString::fromAscii("BREP (*.brp *.brep)"); + + QString select; + QString fn = Gui::FileDialog::getOpenFileName(Gui::getMainWindow(), QString(), QString(), filter.join(QLatin1String(";;")), &select); + if (!fn.isEmpty()) { + + + openCommand("Import ExtPart"); + addModule(Doc,"Part"); + addModule(Doc,"PartDesign"); + addModule(Gui,"PartDesignGui"); + + std::string fName( (const char*)fn.toUtf8()); + + doCommand(Gui, + +"father = AssemblyGui.getActiveAssembly()\n" +"\n" +"for i in Part.read('%s').Solids:\n" +" po = App.activeDocument().addObject('Assembly::ItemPart','STP-Part_1')\n" +" father.Items = father.Items + [po]\n" +" bo = App.activeDocument().addObject('PartDesign::Body','STP-Body_1')\n" +" po.Model = bo\n" +" so = App.activeDocument().addObject('PartDesign::Solid','STP-Solid_1')\n" +" bo.Model = so\n" +" bo.Tip = so\n" +" so.Shape = i\n" +"\n" +"del so,bo,father,po\n" + + ,fName.c_str()); + + this->updateActive(); + } } void CreateAssemblyCommands(void) diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 18f96394c4b5..dbd6b0dbdfcf 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -30,6 +30,7 @@ #include #include "FeaturePad.h" +#include "FeatureSolid.h" #include "FeaturePocket.h" #include "FeatureFillet.h" #include "FeatureSketchBased.h" @@ -75,6 +76,7 @@ PyMODINIT_FUNC init_PartDesign() // This function is responsible for adding inherited slots from a type's base class. PartDesign::Feature ::init(); + PartDesign::Solid ::init(); PartDesign::DressUp ::init(); PartDesign::SketchBased ::init(); PartDesign::Subtractive ::init(); diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 51500d14c4c6..fce91a4760c5 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -31,6 +31,8 @@ set(PartDesign_LIBS SET(Features_SRCS Feature.cpp Feature.h + FeatureSolid.cpp + FeatureSolid.h Body.cpp Body.h ) diff --git a/src/Mod/PartDesign/App/FeatureSolid.cpp b/src/Mod/PartDesign/App/FeatureSolid.cpp new file mode 100644 index 000000000000..9f745e7ddb0d --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureSolid.cpp @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 "FeatureSolid.h" + + + +namespace PartDesign { + + +PROPERTY_SOURCE(PartDesign::Solid,PartDesign::Feature) + +Solid::Solid() +{ +} + + + +} diff --git a/src/Mod/PartDesign/App/FeatureSolid.h b/src/Mod/PartDesign/App/FeatureSolid.h new file mode 100644 index 000000000000..fd441c54fd45 --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureSolid.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 PARTDESIGN_FeatureSolid_H +#define PARTDESIGN_FeatureSolid_H + +#include +#include "Feature.h" + +class gp_Pnt; + + +/// Base class of all additive features in PartDesign +namespace PartDesign +{ + + /** PartDesign feature + * Base class of all PartDesign features. + * This kind of features only produce solids or fail. + */ +class PartDesignExport Solid : public Feature +{ + PROPERTY_HEADER(PartDesign::FeatureSolid); + +public: + Solid(); + +protected: + +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_Feature_H From cdd16de8e61cdc803d370f0ae5cf1573bfd40e1e Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 3 Jan 2013 20:46:17 +0100 Subject: [PATCH 041/664] Fix some build and runtime failures --- src/Mod/Assembly/App/ItemAssembly.cpp | 1 + src/Mod/PartDesign/Gui/Workbench.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index e6e6563a84c7..6ae738e6bf6b 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include #endif #include diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 380f227551df..c380e135449d 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -161,6 +161,7 @@ void Workbench::deactivated() else oldActive = ""; // reset the active Body + Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(None)"); Gui::Workbench::deactivated(); From e6387c6acf15e2652a75527cc8211928e2ac9588 Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 3 Jan 2013 22:27:56 +0100 Subject: [PATCH 042/664] Connect task box labels with commands as queued connection --- src/Gui/TaskView/TaskView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Gui/TaskView/TaskView.cpp b/src/Gui/TaskView/TaskView.cpp index 38640f2a123f..c93961318b9e 100644 --- a/src/Gui/TaskView/TaskView.cpp +++ b/src/Gui/TaskView/TaskView.cpp @@ -116,7 +116,7 @@ void TaskGroup::actionEvent (QActionEvent* e) TaskIconLabel *label = new TaskIconLabel( action->icon(), action->text(), this); this->addIconLabel(label); - connect(label,SIGNAL(clicked()),action,SIGNAL(triggered())); + connect(label,SIGNAL(clicked()),action,SIGNAL(triggered()),Qt::QueuedConnection); break; } case QEvent::ActionChanged: From 4d49b0b0594866400baaac165df5d9bee0f02651 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 6 Jan 2013 20:39:52 +0100 Subject: [PATCH 043/664] PropertyMap and new Attributes for the Assembly object and the Document --- src/App/Document.cpp | 4 ++++ src/Mod/Assembly/App/Item.cpp | 21 +++++++++++++++++---- src/Mod/Assembly/App/Item.h | 30 ++++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 4312724bd05a..f1cf43b00d9e 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -927,6 +927,10 @@ Document::Document(void) ADD_PROPERTY_TYPE(Id,(""),0,Prop_None,"ID of the document"); ADD_PROPERTY_TYPE(Uid,(id),0,Prop_ReadOnly,"UUID of the document"); + // license stuff + ADD_PROPERTY_TYPE(License,("CC-BY 3.0"),0,Prop_None,"License string of the Item"); + ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,Prop_None,"URL to the license text/contract"); + // license stuff int licenseId = App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/Document")->GetInt("prefLicenseType",0); diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index 98d339352c92..548db35752f9 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -26,6 +26,7 @@ #endif #include +#include #include "Item.h" #include "ItemPy.h" @@ -40,11 +41,23 @@ PROPERTY_SOURCE_ABSTRACT(Assembly::Item, App::GeoFeature) Item::Item() { - ADD_PROPERTY(Id,(0)); - ADD_PROPERTY(Uid,(0)); - ADD_PROPERTY(Name,(0)); - ADD_PROPERTY(Description,(0)); + ADD_PROPERTY_TYPE(CreatedBy,(""),0,App::Prop_None,"The creator of the Item"); + ADD_PROPERTY_TYPE(CreationDate,(Base::TimeInfo::currentDateTimeString()),0,App::Prop_ReadOnly,"Date of creation"); + ADD_PROPERTY_TYPE(LastModifiedBy,(""),0,App::Prop_None,0); + ADD_PROPERTY_TYPE(LastModifiedDate,("Unknown"),0,App::Prop_ReadOnly,"Date of last modification"); + ADD_PROPERTY_TYPE(Company,(""),0,App::Prop_None,"Additional tag to save the the name of the company"); + ADD_PROPERTY_TYPE(Comment,(""),0,App::Prop_None,"Additional tag to save a comment"); + ADD_PROPERTY_TYPE(Meta,(),0,App::Prop_None,"Map with additional meta information"); + ADD_PROPERTY_TYPE(Material,(),0,App::Prop_None,"Map with material properties"); + // create the uuid for the document + Base::Uuid id; + ADD_PROPERTY_TYPE(Id,(""),0,App::Prop_None,"ID (Part-Number) of the Item"); + ADD_PROPERTY_TYPE(Uid,(id.UuidStr),0,App::Prop_None,"UUID of the Item"); + // license stuff + ADD_PROPERTY_TYPE(License,("CC BY 3.0"),0,App::Prop_None,"License string of the Item"); + ADD_PROPERTY_TYPE(LicenseURL,("http://creativecommons.org/licenses/by/3.0/"),0,App::Prop_None,"URL to the license text/contract"); + // color and apperance ADD_PROPERTY(Color,(1.0,1.0,1.0,1.0)); // set transparent -> not used ADD_PROPERTY(Visibility,(true)); } diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index c995f6057b3f..a4393a88565b 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -39,19 +39,41 @@ class AssemblyExport Item : public App::GeoFeature public: Item(); - /** @name base properties of all Assembly Items */ + /** @name base properties of all Assembly Items + * This properties corospond mostly to the meta information + * in the App::Document class + */ //@{ /// Id e.g. Part number App::PropertyString Id; /// unique identifier of the Item App::PropertyUUID Uid; - /// Name of the Item (human readable) - App::PropertyString Name ; /// long description of the Item App::PropertyString Description ; + /// creators name (utf-8) + App::PropertyString CreatedBy; + App::PropertyString CreationDate; + /// user last modified the document + App::PropertyString LastModifiedBy; + App::PropertyString LastModifiedDate; + /// company name UTF8(optional) + App::PropertyString Company; + /// long comment or description (UTF8 with line breaks) + App::PropertyString Comment; + /** License string + * Holds the short license string for the Item, e.g. CC-BY + * for the Creative Commons license suit. + */ + App::PropertyString License; + /// License descripton/contract URL + App::PropertyString LicenseURL; + /// Meta descriptons + App::PropertyMap Meta; + /// Meta descriptons + App::PropertyMap Material; //@} - /** @name base properties of all Assembly Items */ + /** @name Visual properties */ //@{ /** Base color of the Item If the transparency value is 1.0 From b81bc0c27f1ffe804cabed9f5dd5e3737e6d5c37 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 6 Jan 2013 21:03:52 +0100 Subject: [PATCH 044/664] Update Item with new UUID tool --- src/Mod/Assembly/App/Item.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index 548db35752f9..9cf152f9cdee 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -52,7 +52,7 @@ Item::Item() // create the uuid for the document Base::Uuid id; ADD_PROPERTY_TYPE(Id,(""),0,App::Prop_None,"ID (Part-Number) of the Item"); - ADD_PROPERTY_TYPE(Uid,(id.UuidStr),0,App::Prop_None,"UUID of the Item"); + ADD_PROPERTY_TYPE(Uid,(id),0,App::Prop_None,"UUID of the Item"); // license stuff ADD_PROPERTY_TYPE(License,("CC BY 3.0"),0,App::Prop_None,"License string of the Item"); From 638cfcc2cf2a531c06b93ff5f4b186d2cb301679 Mon Sep 17 00:00:00 2001 From: jriegel Date: Sun, 13 Jan 2013 16:30:00 +0100 Subject: [PATCH 045/664] Start AssemblyLib.py --- src/Mod/Assembly/App/CMakeLists.txt | 3 +- src/Mod/Assembly/AssemblyLib.py | 77 +++++++++++++++++++++++++++++ src/Mod/Assembly/FCDocTool.py | 39 ++++++++++++++- src/Mod/Assembly/Gui/Command.cpp | 20 ++------ 4 files changed, 120 insertions(+), 19 deletions(-) create mode 100644 src/Mod/Assembly/AssemblyLib.py diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 6eaebbfdcc97..ca11c4ec1594 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -103,7 +103,8 @@ target_link_libraries(Assembly ${Assembly_LIBS}) fc_target_copy_resource(Assembly ${CMAKE_SOURCE_DIR}/src/Mod/Assembly ${CMAKE_BINARY_DIR}/Mod/Assembly - Init.py) + Init.py + AssemblyLib.py) SET_BIN_DIR(Assembly Assembly /Mod/Assembly) SET_PYTHON_PREFIX_SUFFIX(Assembly) diff --git a/src/Mod/Assembly/AssemblyLib.py b/src/Mod/Assembly/AssemblyLib.py new file mode 100644 index 000000000000..b08eeb257f7d --- /dev/null +++ b/src/Mod/Assembly/AssemblyLib.py @@ -0,0 +1,77 @@ +#! python +# -*- coding: utf-8 -*- +#*************************************************************************** +#* * +#* Copyright (c) 2012 * +#* Juergen Riegel * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program 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 program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** + + + +__title__="FreeCAD Assembly Lib" +__author__ = "Juergen Riegel " +__url__ = "http://free-cad.sourceforge.net" + +''' +General description: + + This set of classes is aimed for general methods used in the FreeCAD Assembly module + +User manual: + + TODO + +How it works / how to extend: + TODO +''' + +# import FreeCAD modules +import FreeCAD, Part, Assembly +from FreeCAD import Vector + +if FreeCAD.GuiUp: + import FreeCADGui, AssemblyGui + gui = True +else: + gui = False + +#--------------------------------------------------------------------------- +# General functions +#--------------------------------------------------------------------------- + + + + +#--------------------------------------------------------------------------- +# Import methods +#--------------------------------------------------------------------------- + + +def importAssembly(FileName,DestItem): + for i in Part.read(FileName).Solids: + po = FreeCAD.activeDocument().addObject('Assembly::ItemPart','STP-Part_1') + DestItem.Items = DestItem.Items + [po] + bo = FreeCAD.activeDocument().addObject('PartDesign::Body','STP-Body_1') + po.Model = bo + so = FreeCAD.activeDocument().addObject('PartDesign::Solid','STP-Solid_1') + bo.Model = so + bo.Tip = so + so.Shape = i + diff --git a/src/Mod/Assembly/FCDocTool.py b/src/Mod/Assembly/FCDocTool.py index 92c10eed4780..d1bc824f386f 100644 --- a/src/Mod/Assembly/FCDocTool.py +++ b/src/Mod/Assembly/FCDocTool.py @@ -1,7 +1,44 @@ #! python # -*- coding: utf-8 -*- -# (c) 2007 Juergen Riegel LGPL +#*************************************************************************** +#* * +#* Copyright (c) 2012 * +#* Juergen Riegel * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* This program 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 program; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#*************************************************************************** +__title__="FreeCAD document tool" +__author__ = "Juergen Riegel " +__url__ = "http://free-cad.sourceforge.net" + +''' +General description: + + Command line tool and lib for exploring FreeCAD documents + +User manual: + + TODO + +How it works / how to extend: + TODO +''' import zipfile from xml.dom.minidom import parse, parseString diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index bfb3d65db66d..4af10a38c584 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -192,26 +192,12 @@ void CmdAssemblyAddExistingComponent::activated(int iMsg) addModule(Doc,"Part"); addModule(Doc,"PartDesign"); addModule(Gui,"PartDesignGui"); + addModule(Gui,"AssemblyGui"); + addModule(Gui,"AssemblyLib"); std::string fName( (const char*)fn.toUtf8()); - doCommand(Gui, - -"father = AssemblyGui.getActiveAssembly()\n" -"\n" -"for i in Part.read('%s').Solids:\n" -" po = App.activeDocument().addObject('Assembly::ItemPart','STP-Part_1')\n" -" father.Items = father.Items + [po]\n" -" bo = App.activeDocument().addObject('PartDesign::Body','STP-Body_1')\n" -" po.Model = bo\n" -" so = App.activeDocument().addObject('PartDesign::Solid','STP-Solid_1')\n" -" bo.Model = so\n" -" bo.Tip = so\n" -" so.Shape = i\n" -"\n" -"del so,bo,father,po\n" - - ,fName.c_str()); + doCommand(Gui,"AssemblyLib.importAssembly('%s',AssemblyGui.getActiveAssembly())",fName.c_str()); this->updateActive(); } From 474fbbcb3eb1093ecfa64e98e038aa1768b1c4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 25 Apr 2013 11:58:21 +0200 Subject: [PATCH 046/664] basic infrastructure --- src/Base/Exception.h | 1 + src/Mod/Assembly/App/CMakeLists.txt | 31 +- src/Mod/Assembly/App/Constraint.cpp | 55 +- src/Mod/Assembly/App/Constraint.h | 20 +- src/Mod/Assembly/App/ConstraintAxis.cpp | 29 +- src/Mod/Assembly/App/ConstraintAxis.h | 3 + src/Mod/Assembly/App/ConstraintGroup.cpp | 57 +- src/Mod/Assembly/App/ConstraintGroup.h | 10 + src/Mod/Assembly/App/ConstraintGroupPy.xml | 7 + src/Mod/Assembly/App/ConstraintGroupPyImp.cpp | 19 +- src/Mod/Assembly/App/Item.cpp | 5 +- src/Mod/Assembly/App/Item.h | 5 +- src/Mod/Assembly/App/ItemAssembly.cpp | 73 +- src/Mod/Assembly/App/ItemAssembly.h | 14 +- src/Mod/Assembly/App/ItemAssemblyPy.xml | 10 + src/Mod/Assembly/App/ItemAssemblyPyImp.cpp | 31 + src/Mod/Assembly/App/ItemPart.cpp | 115 ++ src/Mod/Assembly/App/ItemPart.h | 10 +- src/Mod/Assembly/App/gcs3d/CMakeLists.txt | 24 - src/Mod/Assembly/App/gcs3d/Constraints.cpp | 416 ------ src/Mod/Assembly/App/gcs3d/Constraints.h | 133 -- src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx | 28 - src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx | 61 - src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx | 55 - src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx | 64 - src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx | 61 - src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx | 64 - src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx | 64 - src/Mod/Assembly/App/gcs3d/GCS.cpp | 1140 ----------------- src/Mod/Assembly/App/gcs3d/GCS.h | 122 -- src/Mod/Assembly/App/gcs3d/Geo.h | 67 - src/Mod/Assembly/App/gcs3d/InputParser.cpp | 359 ------ src/Mod/Assembly/App/gcs3d/InputParser.h | 60 - src/Mod/Assembly/App/gcs3d/SubSystem.cpp | 351 ----- src/Mod/Assembly/App/gcs3d/SubSystem.h | 89 -- src/Mod/Assembly/App/gcs3d/Util.h | 47 - src/Mod/Assembly/App/gcs3d/main.cpp | 122 -- src/Mod/Assembly/App/gcs3d/qp_eq.cpp | 65 - src/Mod/Assembly/App/gcs3d/qp_eq.h | 25 - src/Mod/Assembly/Gui/CMakeLists.txt | 3 +- src/Mod/Assembly/Gui/Command.cpp | 4 +- src/Mod/Assembly/Gui/CommandConstraints.cpp | 31 +- 42 files changed, 489 insertions(+), 3461 deletions(-) delete mode 100644 src/Mod/Assembly/App/gcs3d/CMakeLists.txt delete mode 100644 src/Mod/Assembly/App/gcs3d/Constraints.cpp delete mode 100644 src/Mod/Assembly/App/gcs3d/Constraints.h delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx delete mode 100644 src/Mod/Assembly/App/gcs3d/GCS.cpp delete mode 100644 src/Mod/Assembly/App/gcs3d/GCS.h delete mode 100644 src/Mod/Assembly/App/gcs3d/Geo.h delete mode 100644 src/Mod/Assembly/App/gcs3d/InputParser.cpp delete mode 100644 src/Mod/Assembly/App/gcs3d/InputParser.h delete mode 100644 src/Mod/Assembly/App/gcs3d/SubSystem.cpp delete mode 100644 src/Mod/Assembly/App/gcs3d/SubSystem.h delete mode 100644 src/Mod/Assembly/App/gcs3d/Util.h delete mode 100644 src/Mod/Assembly/App/gcs3d/main.cpp delete mode 100644 src/Mod/Assembly/App/gcs3d/qp_eq.cpp delete mode 100644 src/Mod/Assembly/App/gcs3d/qp_eq.h diff --git a/src/Base/Exception.h b/src/Base/Exception.h index f17fa71cb935..a4995b082c31 100644 --- a/src/Base/Exception.h +++ b/src/Base/Exception.h @@ -27,6 +27,7 @@ #define BASE_EXCEPTION_H #include +#include #include #include #include "FileInfo.h" diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index ca11c4ec1594..2c44c9c2f5f1 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -4,9 +4,14 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + add_definitions( -DUSE_LOGGING ) +endif (CMAKE_BUILD_TYPE STREQUAL "Debug") + include_directories( ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src + ${CMAKE_SOURCE_DIR}/src/Mod/Assembly/App ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${OCC_INCLUDE_DIR} @@ -23,27 +28,20 @@ set(Assembly_LIBS ${OCC_LIBRARIES} Part FreeCADApp + boost_log + rt + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} ) generate_from_xml(ItemPy) generate_from_xml(ItemAssemblyPy) generate_from_xml(ItemPartPy) +generate_from_xml(ConstraintPy) +generate_from_xml(ConstraintAxisPy) generate_from_xml(ConstraintGroupPy) -SET(FreeGCS3D_SRCS - gcs3d/GCS.cpp - gcs3d/GCS.h - gcs3d/Util.h - gcs3d/Geo.h - gcs3d/Constraints.cpp - gcs3d/Constraints.h - gcs3d/SubSystem.cpp - gcs3d/SubSystem.h - gcs3d/qp_eq.cpp - gcs3d/qp_eq.h -) -SOURCE_GROUP("FreeGCS3D" FILES ${FreeGCS3D_SRCS}) - SET(Features_SRCS Item.cpp Item.h @@ -83,6 +81,10 @@ SET(Python_SRCS ItemAssemblyPyImp.cpp ItemPartPy.xml ItemPartPyImp.cpp + ConstraintPy.xml + ConstraintPyImp.cpp + ConstraintAxisPy.xml + ConstraintAxisPyImp.cpp ConstraintGroupPy.xml ConstraintGroupPyImp.cpp ) @@ -92,7 +94,6 @@ SET(Assembly_SRCS ${Features_SRCS} ${Python_SRCS} ${Module_SRCS} - ${FreeGCS3D_SRCS} ) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp index 01aa71c5a0a7..62f1265cb05a 100644 --- a/src/Mod/Assembly/App/Constraint.cpp +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -1,7 +1,8 @@ /*************************************************************************** * Copyright (c) 2012 Juergen Riegel * + * Copyright (c) 2013 Stefan Tröger * * * - * This file is part of the FreeCAD CAx development system. * + * This file is part of the FreeCAD CAx development m_solvertem. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * @@ -25,9 +26,28 @@ #ifndef _PreComp_ #endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include +#include #include "Constraint.h" +#include "Item.h" +#include "ItemPart.h" using namespace Assembly; @@ -57,4 +77,37 @@ App::DocumentObjectExecReturn *Constraint::execute(void) return App::DocumentObject::StdReturn; } +void Constraint::init(boost::shared_ptr< Solver > solver) { + + //check if we have Assembly::ItemPart's + if( First.getValue()->getTypeId() != ItemPart::getClassTypeId() || + Second.getValue()->getTypeId() != ItemPart::getClassTypeId() ) { + Base::Console().Message("Links are not ItemPart's, the constraint is invalid\n"); + return; + }; + + //see if the parts are already initialized for the solver + Assembly::ItemPart* part1 = static_cast(First.getValue()); + if(!part1->m_part) { + part1->m_part = solver->createPart(part1->Placement.getValue(), part1->Uid.getValueStr()); + part1->m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, part1, _1)); + } + + Assembly::ItemPart* part2 = static_cast(Second.getValue()); + if(!part2->m_part) { + part2->m_part = solver->createPart(part2->Placement.getValue(), part2->Uid.getValueStr()); + part2->m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, part2, _1)); + } + + //let's get the geometrys + m_first_geom = part1->getGeometry3D(First.getSubValues()[0].c_str()); + m_second_geom = part2->getGeometry3D(Second.getSubValues()[0].c_str()); + + if(!m_first_geom || !m_second_geom) { + Base::Console().Message("Unable to initialize geometry\n"); + return; + }; +} + + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h index fd3562ce540b..00562fb51f6f 100644 --- a/src/Mod/Assembly/App/Constraint.h +++ b/src/Mod/Assembly/App/Constraint.h @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2012 Juergen Riegel * + * Copyright (c) 2013 Stefan Tröger * * * * This file is part of the FreeCAD CAx development system. * * * @@ -27,6 +28,10 @@ #include #include +#include + +#include "Solver.h" + namespace Assembly { @@ -34,6 +39,10 @@ namespace Assembly class AssemblyExport Constraint : public App::DocumentObject { PROPERTY_HEADER(Assembly::Constraint); + +protected: + boost::shared_ptr m_constraint; + boost::shared_ptr m_first_geom, m_second_geom; public: Constraint(); @@ -47,10 +56,13 @@ class AssemblyExport Constraint : public App::DocumentObject App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "AssemblyGui::ViewProviderConstraint"; - //} - //@} + const char* getViewProviderName(void) const { + return "Gui::ViewProviderDocumentObject"; + } + + /** @brief initialize the constraint in the assembly solver + */ + virtual void init(boost::shared_ptr solver); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintAxis.cpp b/src/Mod/Assembly/App/ConstraintAxis.cpp index b2ed9ab40553..1361e88c0782 100644 --- a/src/Mod/Assembly/App/ConstraintAxis.cpp +++ b/src/Mod/Assembly/App/ConstraintAxis.cpp @@ -1,5 +1,6 @@ /*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * + * Copyright (c) 2012 Juergen Riegel + * 2013 Stefan Tröger * * * This file is part of the FreeCAD CAx development system. * * * @@ -26,9 +27,12 @@ #endif #include +#include #include "ConstraintAxis.h" +#include "ConstraintAxisPy.h" +#include "ItemPart.h" using namespace Assembly; @@ -42,6 +46,15 @@ ConstraintAxis::ConstraintAxis() } +PyObject *ConstraintAxis::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ConstraintAxisPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + short ConstraintAxis::mustExecute() const { //if (Sketch.isTouched() || @@ -52,8 +65,20 @@ short ConstraintAxis::mustExecute() const App::DocumentObjectExecReturn *ConstraintAxis::execute(void) { - + Base::Console().Message("Recalculate axis constraint\n"); return App::DocumentObject::StdReturn; } +void ConstraintAxis::init(boost::shared_ptr< Solver > solver) +{ + Base::Console().Message("Init constraint axis\n"); + + //init the parts and geometries + Constraint::init(solver); + + //init the constraint + m_constraint = solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::distance = 0); +} + + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAxis.h b/src/Mod/Assembly/App/ConstraintAxis.h index c776ce8925a8..f0e8bc1085a7 100644 --- a/src/Mod/Assembly/App/ConstraintAxis.h +++ b/src/Mod/Assembly/App/ConstraintAxis.h @@ -38,6 +38,7 @@ class AssemblyExport ConstraintAxis : public Assembly::Constraint public: ConstraintAxis(); + PyObject *getPyObject(void); /** @name methods override feature */ //@{ @@ -49,6 +50,8 @@ class AssemblyExport ConstraintAxis : public Assembly::Constraint // return "PartDesignGui::ViewProviderConstraintAxis"; //} //@} + + virtual void init(boost::shared_ptr solver); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp index b27746f7e1bd..71fe93f0abf1 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.cpp +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2010 Juergen Riegel * + * Copyright (c) 2013 Stefan Tröger * * * * This file is part of the FreeCAD CAx development system. * * * @@ -26,8 +27,12 @@ #endif #include +#include +#include "ConstraintGroupPy.h" #include "ConstraintGroup.h" +#include "ItemPart.h" +#include "ItemAssembly.h" using namespace Assembly; @@ -42,6 +47,55 @@ ConstraintGroup::ConstraintGroup() ADD_PROPERTY(Constraints,(0)); } +PyObject *ConstraintGroup::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ConstraintGroupPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +void ConstraintGroup::addConstraint(Constraint* c) +{ + //add the constraint to our list + const std::vector< App::DocumentObject * > &vals = this->Constraints.getValues(); + std::vector< App::DocumentObject * > newVals(vals); + newVals.push_back(c); + this->Constraints.setValues(newVals); + + //let's retrieve the solver if not already done + ItemAssembly* assembly = NULL; + if(!m_solver) { + + typedef std::vector::iterator iter; + std::vector vec = getInList(); + + for(iter it = vec.begin(); it!=vec.end(); it++) { + + if( (*it)->getTypeId() == ItemAssembly::getClassTypeId() ) { + assembly = static_cast(*it); + m_solver = assembly->m_solver; + break; + }; + } + }; + + //check if we have been successfull + if(!m_solver) { + Base::Console().Message("ConstraintGroup: Unable to retrieve assembly solver\n"); + return; + }; + + //init the constraint + c->init(m_solver); + + //solve the system and propagate the change upstream + m_solver->solve(); + assembly->touch(); +} + + short ConstraintGroup::mustExecute() const { //if (Sketch.isTouched() || @@ -53,7 +107,8 @@ short ConstraintGroup::mustExecute() const App::DocumentObjectExecReturn *ConstraintGroup::execute(void) { + Base::Console().Message("Recalculate constraint group\n"); return App::DocumentObject::StdReturn; } -} \ No newline at end of file +} diff --git a/src/Mod/Assembly/App/ConstraintGroup.h b/src/Mod/Assembly/App/ConstraintGroup.h index 2d4157666b38..167cd3451ad4 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.h +++ b/src/Mod/Assembly/App/ConstraintGroup.h @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2010 Juergen Riegel * + * Copyright (c) 2013 Stefan Tröger * * * * This file is part of the FreeCAD CAx development system. * * * @@ -26,7 +27,10 @@ #include #include +#include +#include "Constraint.h" +#include "Solver.h" namespace Assembly { @@ -35,8 +39,14 @@ class AssemblyExport ConstraintGroup : public App::DocumentObject { PROPERTY_HEADER(Assembly::ConstraintGroup); +protected: + boost::shared_ptr m_solver; + public: ConstraintGroup(); + void addConstraint(Constraint* c); + + PyObject *getPyObject(void); App::PropertyLinkList Constraints; diff --git a/src/Mod/Assembly/App/ConstraintGroupPy.xml b/src/Mod/Assembly/App/ConstraintGroupPy.xml index 6ff8732e5423..9691e96682f9 100644 --- a/src/Mod/Assembly/App/ConstraintGroupPy.xml +++ b/src/Mod/Assembly/App/ConstraintGroupPy.xml @@ -13,5 +13,12 @@ Base class of all objects in Assembly + + + Adds a constraint object to the constraint group + + + + diff --git a/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp b/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp index 0fbcfaff1575..19bd9fd63141 100644 --- a/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp +++ b/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp @@ -2,6 +2,7 @@ #include "PreCompiled.h" #include "Mod/Assembly/App/ConstraintGroup.h" +#include "Mod/Assembly/App/ConstraintPy.h" // inclusion of the generated files (generated out of ConstraintGroupPy.xml) #include "ConstraintGroupPy.h" @@ -15,11 +16,19 @@ std::string ConstraintGroupPy::representation(void) const return std::string(""); } - - - - - +PyObject* ConstraintGroupPy::addConstraint(PyObject * args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O", &pcObj)) + return 0; + + if (PyObject_TypeCheck(pcObj, &(Assembly::ConstraintPy::Type))) { + Base::Console().Message("Add constraint\n"); + Assembly::Constraint *c = static_cast(pcObj)->getConstraintPtr(); + this->getConstraintGroupPtr()->addConstraint(c); + } + Py_Return; +} PyObject *ConstraintGroupPy::getCustomAttributes(const char* /*attr*/) const { diff --git a/src/Mod/Assembly/App/Item.cpp b/src/Mod/Assembly/App/Item.cpp index 9cf152f9cdee..897f357ff96c 100644 --- a/src/Mod/Assembly/App/Item.cpp +++ b/src/Mod/Assembly/App/Item.cpp @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2010 Juergen Riegel * + * Copyright (c) 2013 Stefan Tröger * * * * This file is part of the FreeCAD CAx development system. * * * @@ -27,10 +28,11 @@ #include #include +#include #include "Item.h" #include "ItemPy.h" - +#include using namespace Assembly; @@ -73,6 +75,7 @@ short Item::mustExecute() const App::DocumentObjectExecReturn *Item::execute(void) { + Base::Console().Message("Recalculate Assembly::Item\n"); return App::DocumentObject::StdReturn; } diff --git a/src/Mod/Assembly/App/Item.h b/src/Mod/Assembly/App/Item.h index a4393a88565b..9424fdd3325a 100644 --- a/src/Mod/Assembly/App/Item.h +++ b/src/Mod/Assembly/App/Item.h @@ -1,5 +1,6 @@ /*************************************************************************** * Copyright (c) 2010 Juergen Riegel * + * Copyright (c) 2013 Stefan Tröger * * * * This file is part of the FreeCAD CAx development system. * * * @@ -28,7 +29,6 @@ #include #include - namespace Assembly { @@ -83,7 +83,7 @@ class AssemblyExport Item : public App::GeoFeature /// Visibility App::PropertyBool Visibility; //@} - + /** @name methods override feature */ //@{ /// recalculate the feature @@ -98,6 +98,7 @@ class AssemblyExport Item : public App::GeoFeature virtual TopoDS_Shape getShape(void)const =0 ; PyObject *getPyObject(void); + }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 6ae738e6bf6b..0e86369d0f56 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -28,9 +28,11 @@ #endif #include +#include #include #include "ItemAssembly.h" +#include using namespace Assembly; @@ -40,7 +42,7 @@ namespace Assembly { PROPERTY_SOURCE(Assembly::ItemAssembly, Assembly::Item) -ItemAssembly::ItemAssembly() +ItemAssembly::ItemAssembly() : m_solver(new Solver) { ADD_PROPERTY(Items,(0)); ADD_PROPERTY(Annotations,(0)); @@ -48,15 +50,13 @@ ItemAssembly::ItemAssembly() short ItemAssembly::mustExecute() const { - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; return 0; } App::DocumentObjectExecReturn *ItemAssembly::execute(void) { - + Base::Console().Message("Execute ItemAssembly\n"); + this->touch(); return App::DocumentObject::StdReturn; } @@ -92,4 +92,67 @@ TopoDS_Shape ItemAssembly::getShape(void) const } +PyObject *ItemAssembly::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ItemAssemblyPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +void ItemAssembly::addPart(ItemPart* part) { + + if(part->m_part) { + //TODO: destroy old part + } + + //add the part to our list + const std::vector< App::DocumentObject * > &vals = this->Items.getValues(); + std::vector< App::DocumentObject * > newVals(vals); + newVals.push_back(part); + this->Items.setValues(newVals); + + part->m_part = m_solver->createPart(part->Placement.getValue(), part->Uid.getValueStr()); +} + +void ItemAssembly::addComponent(ItemAssembly* assembly) { + + if(assembly->m_solver) { + //TODO: destroy old solver system + } + + //add the component to our list + const std::vector< App::DocumentObject * > &vals = this->Items.getValues(); + std::vector< App::DocumentObject * > newVals(vals); + newVals.push_back(assembly); + this->Items.setValues(newVals); + + assembly->m_solver = boost::shared_ptr(m_solver->createSubsystem()); + assembly->m_solver->setTransformation(assembly->Placement.getValue()); +} + +ItemPart* ItemAssembly::getContainingPart(App::DocumentObject* obj) { + + typedef std::vector::const_iterator iter; + + const std::vector& vector = Items.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if( (*it)->getTypeId() == Assembly::ItemPart::getClassTypeId() ) { + if(static_cast(*it)->holdsObject(obj)) + return static_cast(*it); + } + else if ( (*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId() ) { + + Assembly::ItemPart* part = static_cast(*it)->getContainingPart(obj); + if(part) + return part; + } + }; + + return NULL; +} + + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 156f1f6d8d8b..58036bbff6c4 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -25,15 +25,17 @@ #define ItemAssembly_ItemAssembly_H #include -#include "Item.h" +#include "Item.h" +#include "Solver.h" +#include "ItemPart.h" namespace Assembly { class AssemblyExport ItemAssembly : public Assembly::Item { - PROPERTY_HEADER(Assembly::ItemAssembly); + PROPERTY_HEADER(Assembly::ItemAssembly); public: ItemAssembly(); @@ -50,9 +52,17 @@ class AssemblyExport ItemAssembly : public Assembly::Item const char* getViewProviderName(void) const { return "AssemblyGui::ViewProviderItemAssembly"; } + PyObject *getPyObject(void); //@} virtual TopoDS_Shape getShape(void) const; + + void addPart(Assembly::ItemPart* part); + void addComponent(Assembly::ItemAssembly* assembly); + + Assembly::ItemPart* getContainingPart(App::DocumentObject* obj); + + boost::shared_ptr m_solver; }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ItemAssemblyPy.xml b/src/Mod/Assembly/App/ItemAssemblyPy.xml index e2f560946eae..7e9ba5727546 100644 --- a/src/Mod/Assembly/App/ItemAssemblyPy.xml +++ b/src/Mod/Assembly/App/ItemAssemblyPy.xml @@ -13,5 +13,15 @@ Base class of all objects in Assembly + + + Adds a Assembly::ItemPart object to the assembly + + + + + Adds a Assembly::ItemAssembly object to the assembly + + diff --git a/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp b/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp index 7542d312f75a..5d7ff419c06e 100644 --- a/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp +++ b/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp @@ -6,6 +6,7 @@ // inclusion of the generated files (generated out of ItemAssemblyPy.xml) #include "ItemAssemblyPy.h" #include "ItemAssemblyPy.cpp" +#include using namespace Assembly; @@ -16,9 +17,39 @@ std::string ItemAssemblyPy::representation(void) const } +PyObject* ItemAssemblyPy::addPart(PyObject * args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O", &pcObj)) { + Base::Console().Message("Test 1 fails\n"); + return 0; + } + if (PyObject_TypeCheck(pcObj, &(Assembly::ItemPartPy::Type))) { + Assembly::ItemPart *c = static_cast(pcObj)->getItemPartPtr(); + getItemAssemblyPtr()->addPart(c); + Base::Console().Message("Add Part\n"); + } + else Base::Console().Message("Test 2 fails\n"); + Py_Return; +} +PyObject* ItemAssemblyPy::addComponent(PyObject * args) +{ + PyObject *pcObj; + if (!PyArg_ParseTuple(args, "O", &pcObj)) { + Base::Console().Message("Test 1 fails\n"); + return 0; + } + if (PyObject_TypeCheck(pcObj, &(Assembly::ItemAssemblyPy::Type))) { + Assembly::ItemAssembly *c = static_cast(pcObj)->getItemAssemblyPtr(); + getItemAssemblyPtr()->addComponent(c); + Base::Console().Message("Add Component\n"); + } + else Base::Console().Message("Test 2 fails\n"); + Py_Return; +} PyObject *ItemAssemblyPy::getCustomAttributes(const char* /*attr*/) const diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index f2911f676f69..61a5b9fc0def 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -26,9 +26,20 @@ #endif #include +#include #include "ItemPart.h" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace Assembly; @@ -54,6 +65,8 @@ short ItemPart::mustExecute() const App::DocumentObjectExecReturn *ItemPart::execute(void) { + Base::Console().Message("Recalculate ItemPart\n"); + this->touch(); return App::DocumentObject::StdReturn; } @@ -66,7 +79,109 @@ TopoDS_Shape ItemPart::getShape(void) const } return TopoDS_Shape(); +} +PyObject *ItemPart::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ItemPartPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +bool ItemPart::holdsObject(App::DocumentObject* obj) const { + + //get the body object and the relevant model list + Part::BodyBase* base = static_cast(Model.getValue()); + const std::vector& vector = base->Model.getValues(); + + //check if it holds the relevant document object + return std::find(vector.begin(), vector.end(), obj)!=vector.end(); +} + +void ItemPart::setCalculatedPlacement(boost::shared_ptr< Part3D > part) { + + //part is the same as m_part, so it doasn't matter which one we use + Base::Console().Message("Set new calculated part placement\n"); + + Base::Placement p = dcm::get(part); + Placement.setValue(p); +} + + +boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) +{ + + //check if the item is initialized + if(!m_part) + return boost::shared_ptr< Geometry3D >(); + + boost::shared_ptr geometry; + if(m_part->hasGeometry3D(Type)) { + return m_part->getGeometry3D(Type); + //Base::Console().Message("Already has geometry, nothing added\n"); + } else { + Part::TopoShape ts; + App::DocumentObject* obj = Model.getValue(); + + if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + ts = static_cast(obj)->Shape.getShape(); + } + else return boost::shared_ptr< Geometry3D >(); + + TopoDS_Shape s = ts.getSubShape(Type); + if(s.ShapeType() == TopAbs_FACE) { + TopoDS_Face face = TopoDS::Face(s); + BRepAdaptor_Surface surface(face); + //Base::Console().Message("Fase selected\n"); + switch(surface.GetType()) { + case GeomAbs_Plane: { + //Base::Console().Message("plane selected\n"); + gp_Pln plane = surface.Plane(); + if(face.Orientation()==TopAbs_REVERSED) { + gp_Dir dir = plane.Axis().Direction(); + plane = gp_Pln(plane.Location(), dir.Reversed()); + } + geometry = m_part->addGeometry3D(plane, Type, dcm::Global); + break; + } + case GeomAbs_Cylinder: { + //Base::Console().Message("cylinder selected\n"); + gp_Cylinder cyl = surface.Cylinder(); + geometry = m_part->addGeometry3D(cyl, Type, dcm::Global); + break; + } + default: + Base::Console().Message("Unsuported Surface Geometrie Type at selection 1\n"); + return boost::shared_ptr< Geometry3D >(); + } + + } else if(s.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge edge = TopoDS::Edge(s); + BRepAdaptor_Curve curve(edge); + switch(curve.GetType()) { + case GeomAbs_Line: { + gp_Lin line = curve.Line(); + geometry = m_part->addGeometry3D(line, Type, dcm::Global); + break; + } + default: + //Base::Console().Message("Unsuported Curve Geometrie Type at selection 1\n"); + return boost::shared_ptr< Geometry3D >(); + } + + } else if(s.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v1 = TopoDS::Vertex(s); + gp_Pnt point = BRep_Tool::Pnt(v1); + geometry = m_part->addGeometry3D(point, Type, dcm::Global); + + } else { + Base::Console().Message("Unsuported Topologie Type at selection 1\n"); + return boost::shared_ptr< Geometry3D >(); + } + }; + return geometry; } } \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h index d1d77cc2923e..c19e82740319 100644 --- a/src/Mod/Assembly/App/ItemPart.h +++ b/src/Mod/Assembly/App/ItemPart.h @@ -26,6 +26,7 @@ #include #include "Item.h" +#include "Solver.h" namespace Assembly @@ -34,7 +35,7 @@ namespace Assembly class AssemblyExport ItemPart : public Assembly::Item { PROPERTY_HEADER(Assembly::ItemPart); - + public: ItemPart(); @@ -50,9 +51,16 @@ class AssemblyExport ItemPart : public Assembly::Item const char* getViewProviderName(void) const { return "AssemblyGui::ViewProviderItemPart"; } + PyObject *getPyObject(void); //@} virtual TopoDS_Shape getShape(void) const; + + bool holdsObject(App::DocumentObject* obj) const; + + boost::shared_ptr m_part; + virtual boost::shared_ptr getGeometry3D(const char* Type ); + void setCalculatedPlacement( boost::shared_ptr part ); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/gcs3d/CMakeLists.txt b/src/Mod/Assembly/App/gcs3d/CMakeLists.txt deleted file mode 100644 index 518b8553efc6..000000000000 --- a/src/Mod/Assembly/App/gcs3d/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -project(solver) - -cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) -set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -find_package(XercesC REQUIRED) -find_package(Eigen3) - -include_directories(${EIGEN3_INCLUDE_DIR}) - -#add_subdirectory(NewSolver) - -set(solver_SRC main.cpp - Constraints.cpp - GCS.cpp - InputParser.cpp - qp_eq.cpp - SubSystem.cpp) - -add_executable(solver ${solver_SRC}) - -target_link_libraries(solver ${XERCESC_LIBRARIES}) - - diff --git a/src/Mod/Assembly/App/gcs3d/Constraints.cpp b/src/Mod/Assembly/App/gcs3d/Constraints.cpp deleted file mode 100644 index 8dbe679358af..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Constraints.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 -#include "Constraints.h" - -using namespace Eigen; - -namespace GCS -{ - -/////////////////////////////////////// -// Constraints -/////////////////////////////////////// - -Constraint::Constraint() -: origpvec(0), pvec(0), scale(1.), tag(0) -{ -} - -void Constraint::redirectParams(MAP_pD_pD redirectionmap) -{ - int i=0; - for (VEC_pD::iterator param=origpvec.begin(); - param != origpvec.end(); ++param, i++) { - MAP_pD_pD::const_iterator it = redirectionmap.find(*param); - if (it != redirectionmap.end()) - pvec[i] = it->second; - } -} - -void Constraint::revertParams() -{ - pvec = origpvec; -} - -ConstraintType Constraint::getTypeId() -{ - return None; -} - -void Constraint::rescale(double coef) -{ - scale = coef * 1.; -} - -double Constraint::error() -{ - return 0.; -} - -double Constraint::grad(double *param) -{ - return 0.; -} - -double Constraint::maxStep(MAP_pD_D &dir, double lim) -{ - return lim; -} - - -//quattorot and derivatives - -Matrix3d rotation(double a, double b, double c, double d) { - - double norm = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); - double x=a/norm, y=b/norm, z=c/norm, w=d/norm; - - Matrix3d rot; - rot(0,0) = 1-2*(pow(y,2)+pow(z,2)); - rot(0,1) = -2.0*w*z + 2.0*x*y; - rot(0,2) = 2.0*w*y + 2.0*x*z; - rot(1,0) = 2.0*w*z + 2.0*x*y; - rot(1,1) = 1-2*(pow(x,2)+pow(z,2)); - rot(1,2) = -2.0*w*x + 2.0*y*z; - rot(2,0) = -2.0*w*y + 2.0*x*z; - rot(2,1) = 2.0*w*x + 2.0*y*z; - rot(2,2) = 1-2*(pow(x,2)+pow(y,2)); - - return rot; -} - -Matrix3d rotation_da(double a, double b, double c, double d) { - - double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); - double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); - double x=a/no, y=b/no, z=c/no, w=d/no; - - double dxa = 1.0/no - pow(a,2)/pow(no,3); - double dya = (-1.0*b*a)/div; - double dza = (-1.0*c*a)/div; - double dwa = (-1.0*d*a)/div; - - Matrix3d rot; - rot << -4.0*(y*dya+z*dza), -2.0*(w*dza+dwa*z)+2.0*(x*dya+dxa*y), 2.0*(dwa*y+w*dya)+2.0*(dxa*z+x*dza), - 2.0*(w*dza+dwa*z)+2.0*(x*dya+dxa*y), -4.0*(x*dxa+z*dza), -2.0*(dwa*x+w*dxa)+2.0*(dya*z+y*dza), - -2.0*(dwa*y+w*dya)+2.0*(dxa*z+x*dza), 2.0*(dwa*x+w*dxa)+2.0*(dya*z+y*dza), -4.0*(x*dxa+y*dya); - - return rot; -} - -Matrix3d rotation_db(double a, double b, double c, double d) { - - double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); - double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); - double x=a/no, y=b/no, z=c/no, w=d/no; - - double dxb = (-1.0*a*b)/div; - double dyb = 1.0/no - pow(b,2)/pow(no,3); - double dzb = (-1.0*c*b)/div; - double dwb = (-1.0*d*b)/div; - - Matrix3d rot; - rot << -4.0*(y*dyb+z*dzb), -2.0*(w*dzb+dwb*z)+2.0*(x*dyb+dxb*y), 2.0*(dwb*y+w*dyb)+2.0*(dxb*z+x*dzb), - 2.0*(w*dzb+dwb*z)+2.0*(x*dyb+dxb*y), -4.0*(x*dxb+z*dzb), -2.0*(dwb*x+w*dxb)+2.0*(dyb*z+y*dzb), - -2.0*(dwb*y+w*dyb)+2.0*(dxb*z+x*dzb), 2.0*(dwb*x+w*dxb)+2.0*(dyb*z+y*dzb), -4.0*(x*dxb+y*dyb); - - return rot; -} - -Matrix3d rotation_dc(double a, double b, double c, double d) { - - double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); - double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); - double x=a/no, y=b/no, z=c/no, w=d/no; - - double dxc = (-1.0*a*c)/div; - double dyc = (-1.0*b*c)/div; - double dzc = 1.0/no - pow(c,2)/pow(no,3); - double dwc = (-1.0*d*c)/div; - - Matrix3d rot; - rot << -4.0*(y*dyc+z*dzc), -2.0*(w*dzc+dwc*z)+2.0*(x*dyc+dxc*y), 2.0*(dwc*y+w*dyc)+2.0*(dxc*z+x*dzc), - 2.0*(w*dzc+dwc*z)+2.0*(x*dyc+dxc*y), -4.0*(x*dxc+z*dzc), -2.0*(dwc*x+w*dxc)+2.0*(dyc*z+y*dzc), - -2.0*(dwc*y+w*dyc)+2.0*(dxc*z+x*dzc), 2.0*(dwc*x+w*dxc)+2.0*(dyc*z+y*dzc), -4.0*(x*dxc+y*dyc); - - return rot; -} - -Matrix3d rotation_dd(double a, double b, double c, double d) { - - double no = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); - double div = pow(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2), 3.0/2.0); - double x=a/no, y=b/no, z=c/no, w=d/no; - - double dxd = (-1.0*a*d)/div; - double dyd = (-1.0*b*d)/div; - double dzd = (-1.0*c*d)/div; - double dwd = 1.0/no - pow(d,2)/pow(no,3); - - Matrix3d rot; - rot << -4.0*(y*dyd+z*dzd), -2.0*(w*dzd+dwd*z)+2.0*(x*dyd+dxd*y), 2.0*(dwd*y+w*dyd)+2.0*(dxd*z+x*dzd), - 2.0*(w*dzd+dwd*z)+2.0*(x*dyd+dxd*y), -4.0*(x*dxd+z*dzd), -2.0*(dwd*x+w*dxd)+2.0*(dyd*z+y*dzd), - -2.0*(dwd*y+w*dyd)+2.0*(dxd*z+x*dzd), 2.0*(dwd*x+w*dxd)+2.0*(dyd*z+y*dzd), -4.0*(x*dxd+y*dyd); - - return rot; -} - - -//Plane parallel (need to be treated special as angle=0° or angle=180° dos not work with angle constraint -ConstraintParralelFaceAS::ConstraintParralelFaceAS( GCS::Solid& s0, GCS::Solid& s1, ParallelType *t) -{ - type = t; - - //get the face placements in the objects coordinate system and calculate the normals - Vector3d a,b; - a << s0.n.x, s0.n.y, s0.n.z; - b << s1.n.x, s1.n.y, s1.n.z; - - //get the normal vector - n0 = (a).normalized(); - n1 = (b).normalized(); - - - pvec.push_back(s0.q.a); - pvec.push_back(s0.q.b); - pvec.push_back(s0.q.c); - pvec.push_back(s0.q.d); - pvec.push_back(s1.q.a); - pvec.push_back(s1.q.b); - pvec.push_back(s1.q.c); - pvec.push_back(s1.q.d); - origpvec = pvec; - rescale(); - -} - -ConstraintType ConstraintParralelFaceAS::getTypeId() -{ - return ASParallel; -} - -void ConstraintParralelFaceAS::rescale(double coef) -{ - scale = coef; -} - -double ConstraintParralelFaceAS::error() -{ - - Matrix3d rot0, rot1; - - rot0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); - rot1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); - - Vector3d n0_g = (rot0*n0); - Vector3d n1_g = (rot1*n1); - - double error = 0; - if (*type == GCS::NormalSame) - error = pow((n0_g-n1_g).norm(),2); - else - error = pow((n0_g+n1_g).norm(),2); - - return error; -} - -double ConstraintParralelFaceAS::grad(double* param) -{ - - Vector3d dn; - Matrix3d r0, r1; - r0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); - r1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); - - if (param == q0a()) { - Matrix3d rot = rotation_da(*q0a(), *q0b(), *q0c(), *q0d()); - dn = rot*n0; - } - else if (param == q0b()) { - Matrix3d rot = rotation_db(*q0a(), *q0b(), *q0c(), *q0d()); - dn = rot*n0; - } - else if (param == q0c()) { - Matrix3d rot = rotation_dc(*q0a(), *q0b(), *q0c(), *q0d()); - dn = rot*n0; - } - else if (param == q0d()) { - Matrix3d rot = rotation_dd(*q0a(), *q0b(), *q0c(), *q0d()); - dn = rot*n0; - } - else if (param == q1a()) { - Matrix3d rot = rotation_da(*q1a(), *q1b(), *q1c(), *q1d()); - dn = rot*n1*-1; - } - else if (param == q1b()) { - Matrix3d rot = rotation_db(*q1a(), *q1b(), *q1c(), *q1d()); - dn = rot*n1*-1; - } - else if (param == q1c()) { - Matrix3d rot = rotation_dc(*q1a(), *q1b(), *q1c(), *q1d()); - dn = rot*n1*-1; - } - else if (param == q1d()) { - Matrix3d rot = rotation_dd(*q1a(), *q1b(), *q1c(), *q1d()); - dn = rot*n1*-1; - } - else return 0; - - - Vector3d n0n = r0*n0; - Vector3d n1n = r1*n1; - - double div = 0; - if (*type == NormalSame) - div = (n0n-n1n).dot(dn)*2; - else - div = (n0n+n1n).dot(dn)*2; - - return div; -} - - -//dDistance constraint - -ConstraintFaceDistanceAS::ConstraintFaceDistanceAS(GCS::Solid& s0, GCS::Solid& s1, double *d) -{ - - n0 << s0.n.x, s0.n.y, s0.n.z; - n0.normalize(); - p0 << s0.p.x, s0.p.y, s0.p.z; - p1 << s1.p.x, s1.p.y, s1.p.z; - - //and positions - pvec.push_back(s0.d.x); - pvec.push_back(s0.d.y); - pvec.push_back(s0.d.z); - pvec.push_back(s1.d.x); - pvec.push_back(s1.d.y); - pvec.push_back(s1.d.z); - - //quaternions - pvec.push_back(s0.q.a); - pvec.push_back(s0.q.b); - pvec.push_back(s0.q.c); - pvec.push_back(s0.q.d); - pvec.push_back(s1.q.a); - pvec.push_back(s1.q.b); - pvec.push_back(s1.q.c); - pvec.push_back(s1.q.d); - - //distance - dist = d; - - origpvec = pvec; - rescale(); - -} - -ConstraintType ConstraintFaceDistanceAS::getTypeId() -{ - return ASDistance; -} - -void ConstraintFaceDistanceAS::rescale(double coef) -{ - scale = coef; -} - -double ConstraintFaceDistanceAS::error() -{ - - Matrix3d rot0, rot1; - Vector3d v0, v1; - - rot0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); - rot1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); - v0 << *p0x(), *p0y(), *p0z(); - v1 << *p1x(), *p1y(), *p1z(); - - double error = std::pow(((rot0*n0).dot(rot1*p1+v1) - (rot0*n0).dot(rot0*p0+v0))/(rot0*n0).norm() - *dist,2); - - return error; -} - -double ConstraintFaceDistanceAS::grad(double* param) -{ - - Matrix3d r0, r1; - Vector3d v0, v1; - - v0 << *p0x(), *p0y(), *p0z(); - v1 << *p1x(), *p1y(), *p1z(); - r0 = rotation(*q0a(), *q0b(), *q0c(), *q0d()); - r1 = rotation(*q1a(), *q1b(), *q1c(), *q1d()); - - Matrix3d dr0, dr1; - double div = 0; - double error=((r0*n0).dot(r1*p1+v1) - (r0*n0).dot(r0*p0+v0))/(r0*n0).norm() - *dist; - if (param == q0a() || param == q0b() || param == q0c() || param == q0d()) { - - if (param == q0a()) dr0 = rotation_da(*q0a(), *q0b(), *q0c(), *q0d()); - else if (param == q0b()) dr0 = rotation_db(*q0a(), *q0b(), *q0c(), *q0d()); - else if (param == q0c()) dr0 = rotation_dc(*q0a(), *q0b(), *q0c(), *q0d()); - else if (param == q0d()) dr0 = rotation_dd(*q0a(), *q0b(), *q0c(), *q0d()); - - VectorXd r0n = r0*n0; - div = ( (dr0*n0).dot(r1*p1+v1)*r0n.norm() - r0n.dot(r1*p1+v1)*r0n.dot(dr0*n0)/r0n.norm() ); - div -= ( ((dr0*n0).dot(r0*p0+v0)+r0n.dot(dr0*p0))*r0n.norm() ); - div -= ( r0n.dot(r0*p0+v0)*r0n.dot(dr0*n0)/r0n.norm() ); - div /= pow(r0n.norm(),2); - } - else if (param == q1a() || param == q1b() || param == q1c() || param == q1d()) { - - if (param == q1a()) dr1 = rotation_da(*q1a(), *q1b(), *q1c(), *q1d()); - else if (param == q1b()) dr1 = rotation_db(*q1a(), *q1b(), *q1c(), *q1d()); - else if (param == q1c()) dr1 = rotation_dc(*q1a(), *q1b(), *q1c(), *q1d()); - else if (param == q1d()) dr1 = rotation_dd(*q1a(), *q1b(), *q1c(), *q1d()); - - div = (r0*n0).dot(dr1*p1)/(r0*n0).norm(); - } - else if (param == p0x() || param == p0y() || param == p0z()) { - - Vector3d dp_g; - if (param == p0x()) dp_g << 1,0,0; - else if (param == p0y()) dp_g << 0,1,0; - else if (param == p0z()) dp_g << 0,0,1; - - div = -1*(r0*n0).dot(dp_g)/(r0*n0).norm(); - } - else if (param == p1x() || param == p1y() || param == p1z()) { - - Vector3d dp_g; - if (param == p1x()) dp_g << 1,0,0; - else if (param == p1y()) dp_g << 0,1,0; - else if (param == p1z()) dp_g << 0,0,1; - - div = (r0*n0).dot(dp_g)/(r0*n0).norm(); - } - else return 0; - - div *= 2*error; - return div; -} - -} //namespace GCS diff --git a/src/Mod/Assembly/App/gcs3d/Constraints.h b/src/Mod/Assembly/App/gcs3d/Constraints.h deleted file mode 100644 index f8b2b38c95d6..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Constraints.h +++ /dev/null @@ -1,133 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 FREEGCS_CONSTRAINTS_H -#define FREEGCS_CONSTRAINTS_H - -#include "Geo.h" -#include "Util.h" -#include - -namespace GCS -{ - - /////////////////////////////////////// - // Constraints - /////////////////////////////////////// - - enum ConstraintType { - None = 0, - ASParallel, - ASDistance - }; - - enum ParallelType { - - NormalWhatever = 0, - NormalSame, - NormalOpposite - }; - - class Constraint - { - protected: - VEC_pD origpvec; // is used only as a reference for redirecting and reverting pvec - VEC_pD pvec; - double scale; - int tag; - public: - Constraint(); - - inline VEC_pD params() { return pvec; } - - void redirectParams(MAP_pD_pD redirectionmap); - void revertParams(); - void setTag(int tagId) { tag = tagId; } - int getTag() { return tag; } - - virtual ConstraintType getTypeId(); - virtual void rescale(double coef=1.); - virtual double error(); - virtual double grad(double *); - // virtual void grad(MAP_pD_D &deriv); --> TODO: vectorized grad version - virtual double maxStep(MAP_pD_D &dir, double lim=1.); - }; - - // AS_plane_parallel - class ConstraintParralelFaceAS : public Constraint - { - private: - inline double* q0a() { return pvec[0]; } - inline double* q0b() { return pvec[1]; } - inline double* q0c() { return pvec[2]; } - inline double* q0d() { return pvec[3]; } - inline double* q1a() { return pvec[4]; } - inline double* q1b() { return pvec[5]; } - inline double* q1c() { return pvec[6]; } - inline double* q1d() { return pvec[7]; } - - Eigen::Vector3d n0, n1; - ParallelType *type; - - public: - ConstraintParralelFaceAS(GCS::Solid& s0, GCS::Solid& s1, ParallelType *t); - - virtual ConstraintType getTypeId(); - virtual void rescale(double coef=1.); - virtual double error(); - virtual double grad(double *); - }; - - class ConstraintFaceDistanceAS : public Constraint - { - private: - inline double* p0x() { return pvec[0]; } - inline double* p0y() { return pvec[1]; } - inline double* p0z() { return pvec[2]; } - inline double* p1x() { return pvec[3]; } - inline double* p1y() { return pvec[4]; } - inline double* p1z() { return pvec[5]; } - inline double* q0a() { return pvec[6]; } - inline double* q0b() { return pvec[7]; } - inline double* q0c() { return pvec[8]; } - inline double* q0d() { return pvec[9]; } - inline double* q1a() { return pvec[10]; } - inline double* q1b() { return pvec[11]; } - inline double* q1c() { return pvec[12]; } - inline double* q1d() { return pvec[13]; } - - Eigen::Vector3d p0, p1; - Eigen::Vector3d n0; - - double *dist; - public: - ConstraintFaceDistanceAS(GCS::Solid& s0, GCS::Solid& s1, double *d); - virtual ConstraintType getTypeId(); - virtual void rescale(double coef=1.); - virtual double error(); - virtual double grad(double *); - }; - - -} //namespace GCS - -#endif // FREEGCS_CONSTRAINTS_H diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx deleted file mode 100644 index 8216a86e5ef7..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex1.gcx +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx deleted file mode 100644 index 68e3d8c5dbde..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex2.gcx +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx deleted file mode 100644 index 207e000674d2..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex3.gcx +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx deleted file mode 100644 index 5164d326eb9f..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex4.gcx +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx deleted file mode 100644 index d505e772ce6f..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex5.gcx +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx deleted file mode 100644 index c4ccdfa2c781..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex6.gcx +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx b/src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx deleted file mode 100644 index ab4cd68738dd..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Example/AS_ex7.gcx +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Mod/Assembly/App/gcs3d/GCS.cpp b/src/Mod/Assembly/App/gcs3d/GCS.cpp deleted file mode 100644 index 8f8592883a76..000000000000 --- a/src/Mod/Assembly/App/gcs3d/GCS.cpp +++ /dev/null @@ -1,1140 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 -#include -#include - -#include "GCS.h" -#include "qp_eq.h" -#include - -#include -#include -#include - -namespace GCS -{ - - -/////////////////////////////////////// -// Solver -/////////////////////////////////////// - -// System -System::System() - : clist(0), - c2p(), p2c(), - subsys0(0), - subsys1(0), - subsys2(0), - reference(), - init(false) -{ -} - -System::System(std::vector clist_) - : c2p(), p2c(), - subsys0(0), - subsys1(0), - subsys2(0), - reference(), - init(false) -{ - // create own (shallow) copy of constraints - for (std::vector::iterator constr=clist_.begin(); - constr != clist_.end(); ++constr) { - Constraint *newconstr; - switch ((*constr)->getTypeId()) { - - case GCS::ASParallel: { - ConstraintParralelFaceAS *oldconstr = static_cast(*constr); - newconstr = new ConstraintParralelFaceAS(*oldconstr); - break; - } - case GCS::ASDistance: { - ConstraintFaceDistanceAS *oldconstr = static_cast(*constr); - newconstr = new ConstraintFaceDistanceAS(*oldconstr); - break; - } - case None: - break; - } - if (newconstr) - addConstraint(newconstr); - } -} - -System::~System() -{ - clear(); -} - -void System::clear() -{ - clearReference(); - clearSubSystems(); - free(clist); - c2p.clear(); - p2c.clear(); -} - -void System::clearByTag(int tagId) -{ - std::vector constrvec; - for (std::vector::const_iterator - constr=clist.begin(); constr != clist.end(); ++constr) { - if ((*constr)->getTag() == tagId) - constrvec.push_back(*constr); - } - for (std::vector::const_iterator - constr=constrvec.begin(); constr != constrvec.end(); ++constr) { - removeConstraint(*constr); - } -} - -int System::addConstraint(Constraint *constr) -{ - clearReference(); - - clist.push_back(constr); - VEC_pD constr_params = constr->params(); - for (VEC_pD::const_iterator param=constr_params.begin(); - param != constr_params.end(); ++param) { -// jacobi.set(constr, *param, 0.); - c2p[constr].push_back(*param); - p2c[*param].push_back(constr); - } - return clist.size()-1; -} - -void System::removeConstraint(Constraint *constr) -{ - clearReference(); - clearSubSystems(); - - std::vector::iterator it; - it = std::find(clist.begin(), clist.end(), constr); - clist.erase(it); - - VEC_pD constr_params = c2p[constr]; - for (VEC_pD::const_iterator param=constr_params.begin(); - param != constr_params.end(); ++param) { - std::vector &constraints = p2c[*param]; - it = std::find(constraints.begin(), constraints.end(), constr); - constraints.erase(it); - } - c2p.erase(constr); - - std::vector constrvec; - constrvec.push_back(constr); - free(constrvec); -} - - - -void System::initSolution(VEC_pD ¶ms) -{ - // - Stores the current parameters in the vector "reference" - // - Identifies the equality constraints tagged with ids >= 0 - // and prepares a corresponding system reduction - // - Organizes the rest of constraints into two subsystems for - // tag ids >=0 and < 0 respectively and applies the - // system reduction specified in the previous step - - clearReference(); - for (VEC_pD::const_iterator param=params.begin(); - param != params.end(); ++param) - reference[*param] = **param; - - // identification of equality constraints and parameter reduction - std::set eliminated; // constraints that will be eliminated through reduction - reductionmap.clear(); - { - VEC_pD reduced_params=params; - MAP_pD_I params_index; - for (int i=0; i < int(params.size()); ++i) - params_index[params[i]] = i; - - /* for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr) { - if ((*constr)->getTag() >= 0 && (*constr)->getTypeId() == Equal) { - MAP_pD_I::const_iterator it1,it2; - it1 = params_index.find((*constr)->params()[0]); - it2 = params_index.find((*constr)->params()[1]); - if (it1 != params_index.end() && it2 != params_index.end()) { - eliminated.insert(*constr); - double *p_kept = reduced_params[it1->second]; - double *p_replaced = reduced_params[it2->second]; - for (int i=0; i < int(params.size()); ++i) - if (reduced_params[i] == p_replaced) - reduced_params[i] = p_kept; - } - } - }*/ - for (int i=0; i < int(params.size()); ++i) - if (params[i] != reduced_params[i]) - reductionmap[params[i]] = reduced_params[i]; - } - - int i=0; - std::vector clist0, clist1, clist2; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr, i++) { - if (eliminated.count(*constr) == 0) { - if ((*constr)->getTag() >= 0) - clist0.push_back(*constr); - else if ((*constr)->getTag() == -1) // move constraints - clist1.push_back(*constr); - else // distance from reference constraints - clist2.push_back(*constr); - } - } - - clearSubSystems(); - if (clist0.size() > 0) - subsys0 = new SubSystem(clist0, params, reductionmap); - if (clist1.size() > 0) - subsys1 = new SubSystem(clist1, params, reductionmap); - if (clist2.size() > 0) - subsys2 = new SubSystem(clist2, params, reductionmap); - init = true; -} - -void System::clearReference() -{ - init = false; - reference.clear(); -} - -void System::resetToReference() -{ - for (MAP_pD_D::const_iterator it=reference.begin(); - it != reference.end(); ++it) - *(it->first) = it->second; -} - -int System::solve(VEC_pD ¶ms, bool isFine, Algorithm alg) -{ - initSolution(params); - return solve(isFine, alg); -} - -int System::solve(bool isFine, Algorithm alg) -{ - if (subsys0) { - resetToReference(); - if (subsys2) { - int ret = solve(subsys0, subsys2, isFine); - if (subsys1) // give subsys1 higher priority than subsys2 - // in this case subsys2 acts like a preconditioner - return solve(subsys0, subsys1, isFine); - else - return ret; - } - else if (subsys1) - return solve(subsys0, subsys1, isFine); - else - return solve(subsys0, isFine, alg); - } - else if (subsys1) { - resetToReference(); - if (subsys2) - return solve(subsys1, subsys2, isFine); - else - return solve(subsys1, isFine, alg); - } - else - // return success in order to permit coincidence constraints to be applied - return Success; -} - -int System::solve(SubSystem *subsys, bool isFine, Algorithm alg) -{ - - std::cout << std::endl << "Initial Error: " << subsys->error() << std::endl; - clock_t begin = clock(); - int ret; - if (alg == BFGS) - ret= solve_BFGS(subsys, isFine); - else if (alg == LevenbergMarquardt) - ret= solve_LM(subsys); - else if (alg == DogLeg) - ret= solve_DL(subsys); - else if (alg == HOPS) - ret= solve_EX(subsys); - - clock_t end = clock(); - std::cout << "Time elapsed: " << double( ((end-begin)*1000)/CLOCKS_PER_SEC ) << " ms"<< std::endl; - - return ret; -} - -int System::solve_EX(SubSystem* subsys) { - - - return 0; - -} - - -int System::solve_BFGS(SubSystem *subsys, bool isFine) -{ - int xsize = subsys->pSize(); - if (xsize == 0) - return Success; - - subsys->redirectParams(); - - Eigen::MatrixXd D = Eigen::MatrixXd::Identity(xsize, xsize); - Eigen::VectorXd x(xsize); - Eigen::VectorXd xdir(xsize); - Eigen::VectorXd grad(xsize); - Eigen::VectorXd h(xsize); - Eigen::VectorXd y(xsize); - Eigen::VectorXd Dy(xsize); - - // Initial unknowns vector and initial gradient vector - subsys->getParams(x); - subsys->calcGrad(grad); - - // Initial search direction oposed to gradient (steepest-descent) - xdir = grad; - lineSearch(subsys, xdir); - double err = subsys->error(); - - h = x; - subsys->getParams(x); - h = x - h; // = x xold - - double convergence = isFine ? XconvergenceFine : XconvergenceRough; - int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*err + 1e12; - - for (int iter=1; iter < maxIterNumber; iter++) { - - if (h.norm() <= convergence || err <= smallF) - break; - if (err > diverging_lim || err != err) // check for diverging and NaN - break; - - y = grad; - subsys->calcGrad(grad); - y = grad - y; // = grad gradold - - double hty = h.dot(y); - //make sure that hty is never 0 - if (hty == 0) - hty = .0000000001; - - Dy = D * y; - - double ytDy = y.dot(Dy); - - //Now calculate the BFGS update on D - D += (1.+ytDy/hty)/hty * h * h.transpose(); - D -= 1./hty * (h * Dy.transpose() + Dy * h.transpose()); - - xdir = D * grad; - lineSearch(subsys, xdir); - err = subsys->error(); - - h = x; - subsys->getParams(x); - h = x - h; // = x xold - } - - subsys->revertParams(); - - std::cout << "Error after BFGS solving: " << err << std::endl; - - if (err <= smallF) - return Success; - if (h.norm() <= convergence) - return Converged; - return Failed; -} - -int System::solve_LM(SubSystem* subsys) -{ - int xsize = subsys->pSize(); - int csize = subsys->cSize(); - - if (xsize == 0) - return Success; - - Eigen::VectorXd e(csize), e_new(csize); // vector of all function errors (every constraint is one function) - Eigen::MatrixXd J(csize, xsize); // Jacobi of the subsystem - Eigen::MatrixXd A(xsize, xsize); - Eigen::VectorXd x(xsize), h(xsize), x_new(xsize), g(xsize), diag_A(xsize); - - subsys->redirectParams(); - - subsys->getParams(x); - subsys->calcResidual(e); - e*=-1; - - int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*e.squaredNorm() + 1e12; - - double eps=1e-10, eps1=1e-80; - double tau=1e-3; - double nu=2, mu=0; - int iter=0, stop=0; - for (iter=0; iter < maxIterNumber && !stop; ++iter) { - - // check error - double err=e.squaredNorm(); - if (err <= eps) { // error is small, Success - stop = 1; - break; - } - else if (err > diverging_lim || err != err) { // check for diverging and NaN - stop = 6; - break; - } - - // J^T J, J^T e - subsys->calcJacobi(J);; - - A = J.transpose()*J; - g = J.transpose()*e; - - // Compute ||J^T e||_inf - double g_inf = g.lpNorm(); - diag_A = A.diagonal(); // save diagonal entries so that augmentation can be later canceled - - // check for convergence - if (g_inf <= eps1) { - stop = 2; - break; - } - - // compute initial damping factor - if (iter == 0) - mu = tau * A.diagonal().lpNorm(); - - // determine increment using adaptive damping - while (1) { - // augment normal equations A = A+uI - for (int i=0; i < xsize; ++i) - A(i,i) += mu; - - //solve augmented functions A*h=-g - h = A.fullPivLu().solve(g); - double rel_error = (A*h - g).norm() / g.norm(); - - // check if solving works - if (rel_error < 1e-5) { -/* - double scale = subsys->maxStep() / h.lpNorm(); - if ( scale < 1.) - h *= scale; -*/ - // compute par's new estimate and ||d_par||^2 - x_new = x + h; - double h_norm = h.squaredNorm(); - - if (h_norm <= eps1*eps1*x.norm()) { // relative change in p is small, stop - stop = 3; - break; - } - else if (h_norm >= (x.norm()+eps1)/(DBL_EPSILON*DBL_EPSILON)) { // almost singular - stop = 4; - break; - } - - subsys->setParams(x_new); - subsys->calcResidual(e_new); - e_new *= -1; - - double dF = e.squaredNorm() - e_new.squaredNorm(); - double dL = h.dot(mu*h+g); - - if (dF>0. && dL>0.) { // reduction in error, increment is accepted - double tmp=2*dF/dL-1.; - mu *= std::max(1./3., 1.-tmp*tmp*tmp); - nu=2; - - // update par's estimate - x = x_new; - e = e_new; - break; - } - } - - // if this point is reached, either the linear system could not be solved or - // the error did not reduce; in any case, the increment must be rejected - - mu*=nu; - nu*=2.0; - for (int i=0; i < xsize; ++i) // restore diagonal J^T J entries - A(i,i) = diag_A(i); - } - } - - if (iter >= maxIterNumber) - stop = 5; - - std::cout << "Error after LM solving: " << subsys->error() << std::endl; - - subsys->revertParams(); - - return (stop == 1) ? Success : Failed; -} - - -int System::solve_DL(SubSystem* subsys) -{ - double tolg=1e-80, tolx=1e-80, tolf=1e-10; - - int xsize = subsys->pSize(); - int csize = subsys->cSize(); - - Eigen::VectorXd x(xsize), x_new(xsize); - Eigen::VectorXd fx(csize), fx_new(csize); - Eigen::MatrixXd Jx(csize, xsize), Jx_new(csize, xsize); - Eigen::VectorXd g(xsize), h_sd(xsize), h_gn(xsize), h_dl(xsize); - - subsys->redirectParams(); - - double err; - subsys->getParams(x); - subsys->calcResidual(fx, err); - subsys->calcJacobi(Jx); - - g = Jx.transpose()*(-fx); - - // get the infinity norm fx_inf and g_inf - double g_inf = g.lpNorm(); - double fx_inf = fx.lpNorm(); - - int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*err + 1e12; - - double delta=0.1; - double alpha=0.; - double nu=2.; - int iter=0, stop=0, reduce=0; - while (!stop) { - - // check if finished - if (fx_inf <= tolf) // Success - stop = 1; - else if (g_inf <= tolg) - stop = 2; - else if (delta <= tolx*(tolx + x.norm())) - stop = 3; - else if (iter >= maxIterNumber) - stop = 4; - else if (err > diverging_lim || err != err) { // check for diverging and NaN - stop = 6; - } - else { - // get the steepest descent direction - alpha = g.squaredNorm()/(Jx*g).squaredNorm(); - h_sd = alpha*g; - - // get the gauss-newton step - h_gn = Jx.fullPivLu().solve(-fx); - double rel_error = (Jx*h_gn + fx).norm() / fx.norm(); - if (rel_error > 1e15) - break; - - // compute the dogleg step - if (h_gn.norm() < delta) { - h_dl = h_gn; - if (h_dl.norm() <= tolx*(tolx + x.norm())) { - stop = 5; - break; - } - } - else if (alpha*g.norm() >= delta) { - h_dl = (delta/(alpha*g.norm()))*h_sd; - } - else { - //compute beta - double beta = 0; - Eigen::VectorXd b = h_gn - h_sd; - double bb = (b.transpose()*b).norm(); - double gb = (h_sd.transpose()*b).norm(); - double c = (delta + h_sd.norm())*(delta - h_sd.norm()); - - if (gb > 0) - beta = c / (gb + sqrt(gb * gb + c * bb)); - else - beta = (sqrt(gb * gb + c * bb) - gb)/bb; - - // and update h_dl and dL with beta - h_dl = h_sd + beta*b; - } - } - - // see if we are already finished - if (stop) - break; -/* - double scale = subsys->maxStep() / h_dl.lpNorm(); - if ( scale < 1.) - h_dl *= scale; -*/ - // get the new values - double err_new; - x_new = x + h_dl; - subsys->setParams(x_new); - subsys->calcResidual(fx_new, err_new); - subsys->calcJacobi(Jx_new); - - // calculate the linear model and the update ratio - double dL = err - 0.5*(fx + Jx*h_dl).squaredNorm(); - double dF = err - err_new; - double rho = dL/dF; - - if (dF > 0 && dL > 0) { - x = x_new; - Jx = Jx_new; - fx = fx_new; - err = err_new; - - g = Jx.transpose()*(-fx); - - // get infinity norms - g_inf = g.lpNorm(); - fx_inf = fx.lpNorm(); - } - else - rho = -1; - - // update delta - if (fabs(rho-1.) < 0.2 && h_dl.norm() > delta/3. && reduce <= 0) { - delta = 3*delta; - nu = 2; - reduce = 0; - } - else if (rho < 0.25) { - delta = delta/nu; - nu = 2*nu; - reduce = 2; - } - else - reduce--; - - // count this iteration and start again - iter++; - } - - std::cout << "Error after DogLeg solving: " << subsys->error() << std::endl; - - - subsys->revertParams(); - - return (stop == 1) ? Success : Failed; -} - -// The following solver variant solves a system compound of two subsystems -// treating the first of them as of higher priority than the second -int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) -{ - int xsizeA = subsysA->pSize(); - int xsizeB = subsysB->pSize(); - int csizeA = subsysA->cSize(); - - VEC_pD plist(xsizeA+xsizeB); - { - VEC_pD plistA, plistB; - subsysA->getParamList(plistA); - subsysB->getParamList(plistB); - - std::sort(plistA.begin(),plistA.end()); - std::sort(plistB.begin(),plistB.end()); - - VEC_pD::const_iterator it; - it = std::set_union(plistA.begin(),plistA.end(), - plistB.begin(),plistB.end(),plist.begin()); - plist.resize(it-plist.begin()); - } - int xsize = plist.size(); - - Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize); - Eigen::MatrixXd JA(csizeA, xsize); - Eigen::MatrixXd Y,Z; - - Eigen::VectorXd resA(csizeA); - Eigen::VectorXd lambda(csizeA), lambda0(csizeA), lambdadir(csizeA); - Eigen::VectorXd x(xsize), x0(xsize), xdir(xsize), xdir1(xsize); - Eigen::VectorXd grad(xsize); - Eigen::VectorXd h(xsize); - Eigen::VectorXd y(xsize); - Eigen::VectorXd Bh(xsize); - - // We assume that there are no common constraints in subsysA and subsysB - subsysA->redirectParams(); - subsysB->redirectParams(); - - subsysB->getParams(plist,x); - subsysA->getParams(plist,x); - subsysB->setParams(plist,x); // just to ensure that A and B are synchronized - - subsysB->calcGrad(plist,grad); - subsysA->calcJacobi(plist,JA); - subsysA->calcResidual(resA); - - double convergence = isFine ? XconvergenceFine : XconvergenceRough; - int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*subsysA->error() + 1e12; - - double mu = 0; - lambda.setZero(); - for (int iter=1; iter < maxIterNumber; iter++) { - int status = qp_eq(B, grad, JA, resA, xdir, Y, Z); - if (status) - break; - - x0 = x; - lambda0 = lambda; - lambda = Y.transpose() * (B * xdir + grad); - lambdadir = lambda - lambda0; - - // line search - { - double eta=0.25; - double tau=0.5; - double rho=0.5; - double alpha=1; - alpha = std::min(alpha, subsysA->maxStep(plist,xdir)); - - // Eq. 18.32 - // double mu = lambda.lpNorm() + 0.01; - // Eq. 18.33 - // double mu = grad.dot(xdir) / ( (1.-rho) * resA.lpNorm<1>()); - // Eq. 18.36 - mu = std::max(mu, - (grad.dot(xdir) + std::max(0., 0.5*xdir.dot(B*xdir))) / - ( (1. - rho) * resA.lpNorm<1>() ) ); - - // Eq. 18.27 - double f0 = subsysB->error() + mu * resA.lpNorm<1>(); - - // Eq. 18.29 - double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>(); - - x = x0 + alpha * xdir; - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); - subsysA->calcResidual(resA); - double f = subsysB->error() + mu * resA.lpNorm<1>(); - - // line search, Eq. 18.28 - bool first = true; - while (f > f0 + eta * alpha * deriv) { - if (first) { // try a second order step - // xdir1 = JA.jacobiSvd(Eigen::ComputeThinU | - // Eigen::ComputeThinV).solve(-resA); - xdir1 = -Y*resA; - x += xdir1; // = x0 + alpha * xdir + xdir1 - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); - subsysA->calcResidual(resA); - f = subsysB->error() + mu * resA.lpNorm<1>(); - if (f < f0 + eta * alpha * deriv) - break; - } - alpha = tau * alpha; - x = x0 + alpha * xdir; - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); - subsysA->calcResidual(resA); - f = subsysB->error() + mu * resA.lpNorm<1>(); - } - lambda = lambda0 + alpha * lambdadir; - - } - h = x - x0; - - y = grad - JA.transpose() * lambda; - { - subsysB->calcGrad(plist,grad); - subsysA->calcJacobi(plist,JA); - subsysA->calcResidual(resA); - } - y = grad - JA.transpose() * lambda - y; // Eq. 18.13 - - if (iter > 1) { - double yTh = y.dot(h); - if (yTh != 0) { - Bh = B * h; - //Now calculate the BFGS update on B - B += 1./yTh * y * y.transpose(); - B -= 1./h.dot(Bh) * (Bh * Bh.transpose()); - } - } - - double err = subsysA->error(); - if (h.norm() <= convergence && err <= smallF) - break; - if (err > diverging_lim || err != err) // check for diverging and NaN - break; - } - - int ret; - if (subsysA->error() <= smallF) - ret = Success; - else if (h.norm() <= convergence) - ret = Converged; - else - ret = Failed; - - subsysA->revertParams(); - subsysB->revertParams(); - return ret; - -} - -void System::getSubSystems(std::vector &subsysvec) -{ - subsysvec.clear(); - if (subsys0) - subsysvec.push_back(subsys0); - if (subsys1) - subsysvec.push_back(subsys1); - if (subsys2) - subsysvec.push_back(subsys2); -} - -void System::applySolution() -{ - if (subsys2) - subsys2->applySolution(); - if (subsys1) - subsys1->applySolution(); - if (subsys0) - subsys0->applySolution(); - - for (MAP_pD_pD::const_iterator it=reductionmap.begin(); - it != reductionmap.end(); ++it) - *(it->first) = *(it->second); -} - -int System::diagnose(VEC_pD ¶ms, VEC_I &conflicting) -{ - // Analyses the constrainess grad of the system and provides feedback - // The vector "conflicting" will hold a group of conflicting constraints - conflicting.clear(); - std::vector conflictingIndex; - VEC_I tags; - Eigen::MatrixXd J(clist.size(), params.size()); - int count=0; - for (std::vector::iterator constr=clist.begin(); - constr != clist.end(); ++constr) { - (*constr)->revertParams(); - if ((*constr)->getTag() >= 0) { - count++; - tags.push_back((*constr)->getTag()); - for (int j=0; j < int(params.size()); j++) - J(count-1,j) = (*constr)->grad(params[j]); - } - } - - if (J.rows() > 0) { - Eigen::FullPivHouseholderQR qrJT(J.topRows(count).transpose()); - Eigen::MatrixXd Q = qrJT.matrixQ (); - int params_num = qrJT.rows(); - int constr_num = qrJT.cols(); - int rank = qrJT.rank(); - - Eigen::MatrixXd R; - if (constr_num >= params_num) - R = qrJT.matrixQR().triangularView(); - else - R = qrJT.matrixQR().topRows(constr_num) - .triangularView(); - - if (constr_num > rank) { // conflicting constraints - for (int i=1; i < rank; i++) { - // eliminate non zeros above pivot - assert(R(i,i) != 0); - for (int row=0; row < i; row++) { - if (R(row,i) != 0) { - double coef=R(row,i)/R(i,i); - R.block(row,i+1,1,constr_num-i-1) -= coef * R.block(i,i+1,1,constr_num-i-1); - R(row,i) = 0; - } - } - } - conflictingIndex.resize(constr_num-rank); - for (int j=rank; j < constr_num; j++) { - for (int row=0; row < rank; row++) { - if (R(row,j) != 0) { - int orig_col = qrJT.colsPermutation().indices()[row]; - conflictingIndex[j-rank].push_back(orig_col); - } - } - int orig_col = qrJT.colsPermutation().indices()[j]; - conflictingIndex[j-rank].push_back(orig_col); - } - - SET_I tags_set; - for (int i=0; i < conflictingIndex.size(); i++) { - for (int j=0; j < conflictingIndex[i].size(); j++) { - tags_set.insert(tags[conflictingIndex[i][j]]); - } - } - tags_set.erase(0); // exclude constraints tagged with zero - conflicting.resize(tags_set.size()); - std::copy(tags_set.begin(), tags_set.end(), conflicting.begin()); - - if (params_num == rank) // over-constrained - return params_num - constr_num; - } - - return params_num - rank; - } - return params.size(); -} - -void System::clearSubSystems() -{ - init = false; - std::vector subsystems; - getSubSystems(subsystems); - free(subsystems); - subsys0 = NULL; - subsys1 = NULL; - subsys2 = NULL; -} - - -//calculates the wolfe condition test functions p and g -Eigen::Vector2d PG(SubSystem* sys, Eigen::VectorXd xdir, double sigma) { - - int xsize = sys->pSize(); - Eigen::Vector2d PG; - Eigen::VectorXd x(xsize), x_new(xsize); - Eigen::VectorXd gr(xsize), grn(xsize); - double fx, fxn; - - sys->getParams(x); - fx = sys->error(); - sys->calcGrad(gr); - x_new = x-sigma*xdir; - sys->setParams(x_new); - fxn = sys->error(); - sys->calcGrad(grn); - sys->setParams(x); - - if (sigma == 0) - PG(1) = 1; - else - PG(1) = (fx-fxn) / (sigma * gr.transpose()*xdir).norm(); - - PG(0) = (grn.transpose()*xdir).norm() / (gr.transpose()*xdir).norm(); - - return PG; -} - - -double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir) -{ - double alpha, beta; - int xsize = subsys->pSize(); - - - - //get inital alpha and beta interval - //********************************** - double c3 = 0.1, c4 = 5; - double delta = 0.01, kappa = 0.9, mu = 0.8, sigma, gamma; - double fx, fxmd; - bool run = true; - - Eigen::VectorXd x(xsize), x_new(xsize); - Eigen::VectorXd grad(xsize); - - - subsys->getParams(x); - subsys->calcGrad(grad); - fx = subsys->error(); - x_new = x-xdir; - subsys->setParams(x_new); - fxmd= subsys->error(); - subsys->setParams(x); - - //calculate an guess for sigma - double comp1 = (grad.transpose()*xdir).norm() / std::pow(xdir.norm(),2); - double comp2 = (grad.transpose()*xdir).norm() /(2*(fxmd-fx+(grad.transpose()*xdir).norm())); - sigma = std::min(c4*comp1 , std::max(c3*comp1, comp2)); - - //calculate test functions with guess - Eigen::Vector2d pg = PG(subsys, xdir, sigma); - - //see if we are alread fisished - if ( pg(1)>=delta && pg(0) <= kappa) - run = false; - else if ( pg(1)>=delta && pg(0)>kappa) { - alpha = sigma; - //beta is sigma/mu^j with j minimal so that g(beta)=delta and p(alpha)>=kappa (j element natural numbers) - for (int i=1; i<=1000; i++) { - alpha = sigma*(std::pow(mu, i)); - pg = PG(subsys, xdir, alpha); - if (pg(0)>=kappa && pg(1) >= delta) break; - } - } - - //start sigma search in interval alpha beta - //***************************************** - while (run) { - - gamma = (alpha + beta)/2.; - pg = PG(subsys, xdir, gamma); - - if (pg(0) > kappa && pg(1) >= delta) alpha = gamma; - else if (pg(0) <= kappa && pg(1) >= delta) { - sigma = gamma; - run = false; - } - else beta = gamma; - - if (alpha == beta) break; - } - - x_new = x - sigma* xdir; - subsys->setParams(x_new); - - std::cout << "sigma: "<maxStep(xdir); - - Eigen::VectorXd x0, x; - - //Save initial values - subsys->getParams(x0); - - //Start at the initial position alpha1 = 0 - alpha1 = 0.; - f1 = subsys->error(); - - //Take a step of alpha2 = 1 - alpha2 = 1.; - x = x0 + alpha2 * xdir; - subsys->setParams(x); - f2 = subsys->error(); - - //Take a step of alpha3 = 2*alpha2 - alpha3 = alpha2*2; - x = x0 + alpha3 * xdir; - subsys->setParams(x); - f3 = subsys->error(); - - //Now reduce or lengthen alpha2 and alpha3 until the minimum is - //Bracketed by the triplet f1>f2 f1 || f2 > f3) { - if (f2 > f1) { - //If f2 is greater than f1 then we shorten alpha2 and alpha3 closer to f1 - //Effectively both are shortened by a factor of two. - alpha3 = alpha2; - f3 = f2; - alpha2 = alpha2 / 2; - x = x0 + alpha2 * xdir; - subsys->setParams(x); - f2 = subsys->error(); - } - else if (f2 > f3) { - if (alpha3 >= alphaMax) - break; - //If f2 is greater than f3 then we increase alpha2 and alpha3 away from f1 - //Effectively both are lengthened by a factor of two. - alpha2 = alpha3; - f2 = f3; - alpha3 = alpha3 * 2; - x = x0 + alpha3 * xdir; - subsys->setParams(x); - f3 = subsys->error(); - } - } - //Get the alpha for the minimum f of the quadratic approximation - alphaStar = alpha2 + ((alpha2-alpha1)*(f1-f3))/(3*(f1-2*f2+f3)); - - //Guarantee that the new alphaStar is within the bracket - if (alphaStar >= alpha3 || alphaStar <= alpha1) - alphaStar = alpha2; - - if (alphaStar > alphaMax) - alphaStar = alphaMax; - - if (alphaStar != alphaStar) - alphaStar = 0.; - - //Take a final step to alphaStar - x = x0 + alphaStar * xdir; - subsys->setParams(x); - - return alphaStar; -}*/ - - -void free(VEC_pD &doublevec) -{ - for (VEC_pD::iterator it = doublevec.begin(); - it != doublevec.end(); ++it) - if (*it) delete *it; - doublevec.clear(); -} - -void free(std::vector &constrvec) -{ - for (std::vector::iterator constr=constrvec.begin(); - constr != constrvec.end(); ++constr) { - if (*constr) { - switch ((*constr)->getTypeId()) { - - case None: - default: - delete *constr; - } - } - } - constrvec.clear(); -} - -void free(std::vector &subsysvec) -{ - for (std::vector::iterator it=subsysvec.begin(); - it != subsysvec.end(); ++it) - if (*it) delete *it; -} - -} //namespace GCS diff --git a/src/Mod/Assembly/App/gcs3d/GCS.h b/src/Mod/Assembly/App/gcs3d/GCS.h deleted file mode 100644 index c4a2ac671d13..000000000000 --- a/src/Mod/Assembly/App/gcs3d/GCS.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 FREEGCS_GCS_H -#define FREEGCS_GCS_H - -#include "SubSystem.h" - - -namespace GCS { - - - -/////////////////////////////////////// -// Solver -/////////////////////////////////////// - -enum SolveStatus { - Success = 0, // Found a solution zeroing the error function - Converged = 1, // Found a solution minimizing the error function - Failed = 2 // Failed to find any solution -}; - -enum Algorithm { - BFGS = 0, - LevenbergMarquardt = 1, - DogLeg = 2, - HOPS, -}; - -class System { - // This is the main class. It holds all constraints and information - // about partitioning into subsystems and solution strategies -private: - std::vector clist; - - std::map c2p; // constraint to parameter adjacency list - std::map > p2c; // parameter to constraint adjacency list - - SubSystem *subsys0; // has the highest priority, always used as the primary subsystem - SubSystem *subsys1; // normally used as secondary subsystem, it is considered primary only if subsys0 is missing - SubSystem *subsys2; // has the lowest priority, always used as secondary system - void clearSubSystems(); - - MAP_pD_D reference; - void clearReference(); - void resetToReference(); - - MAP_pD_pD reductionmap; // for simplification of equality constraints - - bool init; - - int solve_BFGS ( SubSystem *subsys, bool isFine ); - int solve_LM ( SubSystem *subsys ); - int solve_DL ( SubSystem *subsys ); - int solve_EX ( SubSystem *subsys ); -public: - System(); - System ( std::vector clist_ ); - ~System(); - - void clear(); - void clearByTag ( int tagId ); - - int addConstraint ( Constraint *constr ); - void removeConstraint ( Constraint *constr ); - - void initSolution ( VEC_pD ¶ms ); - - int solve ( bool isFine=true, Algorithm alg=DogLeg ); - int solve ( VEC_pD ¶ms, bool isFine=true, Algorithm alg=DogLeg ); - int solve ( SubSystem *subsys, bool isFine=true, Algorithm alg=DogLeg ); - int solve ( SubSystem *subsysA, SubSystem *subsysB, bool isFine=true ); - - void getSubSystems ( std::vector &subsysvec ); - void applySolution(); - - bool isInit() const { - return init; - } - - int diagnose ( VEC_pD ¶ms, VEC_I &conflicting ); -}; - -/////////////////////////////////////// -// BFGS Solver parameters -/////////////////////////////////////// -#define XconvergenceRough 1e-8 -#define XconvergenceFine 1e-10 -#define smallF 1e-20 -#define MaxIterations 100 //Note that the total number of iterations allowed is MaxIterations *xLength - -/////////////////////////////////////// -// Helper elements -/////////////////////////////////////// - -void free ( VEC_pD &doublevec ); -void free ( std::vector &constrvec ); -void free ( std::vector &subsysvec ); - -} //namespace GCS - -#endif // FREEGCS_GCS_H diff --git a/src/Mod/Assembly/App/gcs3d/Geo.h b/src/Mod/Assembly/App/gcs3d/Geo.h deleted file mode 100644 index c7629b51f001..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Geo.h +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 FREEGCS_GEO_H -#define FREEGCS_GEO_H - -namespace GCS -{ - - class Displacement { - - public: - Displacement(){x = 0; y = 0; z = 0;} - double *x, *y, *z; - }; - - class Point { - - public: - Point() { x=y=z=0;} - double x,y,z; - }; - - class Normal : public Point { - - public: - Normal() {}; - }; - - class Quaternion { - - public: - Quaternion() {a = b = c = d = 0;}; - double *a, *b, *c, *d; - }; - - class Solid { - - public: - Solid() {}; - Quaternion q; - Displacement d; - Normal n; - Point p; - }; -} //namespace GCS - -#endif // FREEGCS_GEO_H diff --git a/src/Mod/Assembly/App/gcs3d/InputParser.cpp b/src/Mod/Assembly/App/gcs3d/InputParser.cpp deleted file mode 100644 index 43f47f59ec00..000000000000 --- a/src/Mod/Assembly/App/gcs3d/InputParser.cpp +++ /dev/null @@ -1,359 +0,0 @@ -#include -#include - -#include "InputParser.h" - -#include - - - -InputParser::InputParser() -{ - try { - xercesc::XMLPlatformUtils::Initialize(); // Initialize Xerces infrastructure - } - catch (xercesc::XMLException& e) { - char* message = xercesc::XMLString::transcode(e.getMessage()); - std::cout << "XML toolkit initialization error: " << message << std::endl; - xercesc::XMLString::release(&message); - } - - // Tags and attributes used in XML file. - // Can't call transcode till after Xerces Initialize() - TAG_points = xercesc::XMLString::transcode("points"); - TAG_point = xercesc::XMLString::transcode("point"); - TAG_constraints= xercesc::XMLString::transcode("constraints"); - TAG_constraint = xercesc::XMLString::transcode("constraint"); - ATTR_id = xercesc::XMLString::transcode("id"); - ATTR_x = xercesc::XMLString::transcode("x"); - ATTR_y = xercesc::XMLString::transcode("y"); - ATTR_z = xercesc::XMLString::transcode("z"); - ATTR_point = xercesc::XMLString::transcode("point"); - ATTR_kind = xercesc::XMLString::transcode("kind"); - ATTR_distance = xercesc::XMLString::transcode("distance"); - - TAG_GCS_AS = xercesc::XMLString::transcode("GCS_AS"); - TAG_quaternion = xercesc::XMLString::transcode("quaternion"); - TAG_quaternions = xercesc::XMLString::transcode("quaternions"); - TAG_normal = xercesc::XMLString::transcode("normal"); - TAG_normals = xercesc::XMLString::transcode("normals"); - TAG_displacement = xercesc::XMLString::transcode("displacement"); - TAG_displacements = xercesc::XMLString::transcode("displacements"); - TAG_solid = xercesc::XMLString::transcode("solid"); - TAG_solids = xercesc::XMLString::transcode("solids"); - KIND_Parallel_AS = xercesc::XMLString::transcode("Parallel_AS"); - KIND_Distance_AS = xercesc::XMLString::transcode("Distance_AS"); - ATTR_a = xercesc::XMLString::transcode("a"); - ATTR_b= xercesc::XMLString::transcode("b"); - ATTR_c = xercesc::XMLString::transcode("c"); - ATTR_d = xercesc::XMLString::transcode("d"); - ATTR_type = xercesc::XMLString::transcode("type"); - ATTR_quaternion = xercesc::XMLString::transcode("quaternion"); - ATTR_normal = xercesc::XMLString::transcode("normal"); - ATTR_displacement = xercesc::XMLString::transcode("displacement"); - ATTR_solid1 = xercesc::XMLString::transcode("solid1"); - ATTR_solid2 = xercesc::XMLString::transcode("solid2"); - - - m_InputFileParser = new xercesc::XercesDOMParser; -} - -InputParser::~InputParser() -{ - // Free memory - delete m_InputFileParser; -} - -bool InputParser::readInputFileAS(std::string &fileName, - std::vector &variables, - std::vector ¶meters, - std::vector &points, - std::vector &norms, - std::vector &disps, - std::vector &quats, - std::vector &solids, - std::vector &constraints) -{ - int pointsOffset = points.size(); - int normsOffset = norms.size(); - int dispsOffset = disps.size(); - int quatsOffset = quats.size(); - int solidsOffset = solids.size(); - - // Test to see if the file is ok. - struct stat fileStatus; - if (stat(fileName.c_str(), &fileStatus) != 0) { - std::cout << "Error reading the file " << fileName << std::endl; - return false; - } - - // Configure DOM parser. - m_InputFileParser->setValidationScheme(xercesc::XercesDOMParser::Val_Never); - m_InputFileParser->setDoNamespaces(false); - m_InputFileParser->setDoSchema(false); - m_InputFileParser->setLoadExternalDTD(false); - - try { - m_InputFileParser->parse(fileName.c_str()); - - // no need to free this pointer - owned by the parent parser object - xercesc::DOMDocument* xmlDoc = m_InputFileParser->getDocument(); - - // Get the top-level element: Name is "GCS_3D". No attributes for "GCS_3D" - xercesc::DOMElement* elementRoot = xmlDoc->getDocumentElement(); - if (!elementRoot) { - std::cout << "empty XML document" << std::endl; - return false; - } - else if (!xercesc::XMLString::equals(elementRoot->getTagName(), TAG_GCS_AS)) { - std::cout << "wrong root element in the XML file" << std::endl; - return false; - } - - // Parse XML file for tags of interest: "ApplicationSettings" - // Look one level nested within "root". (child of root) - xercesc::DOMNodeList* children = elementRoot->getChildNodes(); - const XMLSize_t nodeCount = children->getLength(); - - // Points - xercesc::DOMNodeList* pointsNodes = elementRoot->getElementsByTagName(TAG_points); - const XMLSize_t pointsCount = pointsNodes->getLength(); - - for (XMLSize_t i = 0; i < pointsCount; ++i) { - xercesc::DOMNode* pointsNode = pointsNodes->item(i); - xercesc::DOMElement* pointsElement = dynamic_cast(pointsNode); - - xercesc::DOMNodeList* pointNodes = pointsElement->getElementsByTagName(TAG_point); - const XMLSize_t pointCount = pointNodes->getLength(); - - for (XMLSize_t j = 0; j < pointCount; ++j) { - xercesc::DOMNode* pointNode = pointNodes->item(j); - xercesc::DOMElement* pointElement = dynamic_cast(pointNode); - - int id = getIntAttr(pointElement, ATTR_id); - double x = getDoubleAttr(pointElement, ATTR_x); - double y = getDoubleAttr(pointElement, ATTR_y); - double z = getDoubleAttr(pointElement, ATTR_z); - - if (id + pointsOffset > points.size()) - points.resize(id + pointsOffset); - - GCS::Point p; - p.x = x; - p.y = y; - p.z = z; - points[id + pointsOffset -1] = p; - } - } - - // normals - xercesc::DOMNodeList* normsNodes = elementRoot->getElementsByTagName(TAG_normals); - const XMLSize_t normsCount = normsNodes->getLength(); - - for (XMLSize_t i = 0; i < normsCount; ++i) { - xercesc::DOMNode* normsNode = normsNodes->item(i); - xercesc::DOMElement* normsElement = dynamic_cast(normsNode); - - xercesc::DOMNodeList* lineNodes = normsElement->getElementsByTagName(TAG_normal); - const XMLSize_t lineCount = lineNodes->getLength(); - - for (XMLSize_t j = 0; j < lineCount; ++j) { - xercesc::DOMNode* normNode = lineNodes->item(j); - xercesc::DOMElement* normElement = dynamic_cast(normNode); - - int id = getIntAttr(normElement, ATTR_id); - double x = getDoubleAttr(normElement, ATTR_x); - double y = getDoubleAttr(normElement, ATTR_y); - double z = getDoubleAttr(normElement, ATTR_z); - - if (id + normsOffset > norms.size()) - norms.resize(id + normsOffset); - - GCS::Normal p; - p.x = x; - p.y = y; - p.z = z; - norms[id + normsOffset -1] = p; - } - } - - // Displacements - xercesc::DOMNodeList* dispsNodes = elementRoot->getElementsByTagName(TAG_displacements); - const XMLSize_t dispsCount = dispsNodes->getLength(); - - for (XMLSize_t i = 0; i < dispsCount; ++i) { - xercesc::DOMNode* dispsNode = dispsNodes->item(i); - xercesc::DOMElement* dispsElement = dynamic_cast(dispsNode); - - xercesc::DOMNodeList* lineNodes = dispsElement->getElementsByTagName(TAG_displacement); - const XMLSize_t lineCount = lineNodes->getLength(); - - for (XMLSize_t j = 0; j < lineCount; ++j) { - xercesc::DOMNode* dispNode = lineNodes->item(j); - xercesc::DOMElement* dispElement = dynamic_cast(dispNode); - - int id = getIntAttr(dispElement, ATTR_id); - double x = getDoubleAttr(dispElement, ATTR_x); - double y = getDoubleAttr(dispElement, ATTR_y); - double z = getDoubleAttr(dispElement, ATTR_z); - - if (id + dispsOffset > disps.size()) - disps.resize(id + dispsOffset); - - // Memory allocation!! - int varStartIndex = variables.size(); - variables.push_back(new double(x)); - variables.push_back(new double(y)); - variables.push_back(new double(z)); - - GCS::Displacement p; - p.x = variables[varStartIndex+0]; - p.y = variables[varStartIndex+1]; - p.z = variables[varStartIndex+2]; - disps[id + dispsOffset -1] = p; - } - } - - // Quaternions - xercesc::DOMNodeList* quatsNodes = elementRoot->getElementsByTagName(TAG_quaternions); - const XMLSize_t quatCount = quatsNodes->getLength(); - - for (XMLSize_t i = 0; i < quatCount; ++i) { - xercesc::DOMNode* quatsNode = quatsNodes->item(i); - xercesc::DOMElement* quatsElement = dynamic_cast(quatsNode); - - xercesc::DOMNodeList* quatNodes = quatsElement->getElementsByTagName(TAG_quaternion); - const XMLSize_t quatCount = quatNodes->getLength(); - - for (XMLSize_t j = 0; j < quatCount; ++j) { - xercesc::DOMNode* quatNode = quatNodes->item(j); - xercesc::DOMElement* quatElement = dynamic_cast(quatNode); - - int id = getIntAttr(quatElement, ATTR_id); - double a = getDoubleAttr(quatElement, ATTR_a); - double b = getDoubleAttr(quatElement, ATTR_b); - double c = getDoubleAttr(quatElement, ATTR_c); - double d = getDoubleAttr(quatElement, ATTR_d); - - if (id + quatsOffset > quats.size()) - quats.resize(id + quatsOffset); - - GCS::Quaternion q; - // Memory allocation!! - int varStartIndex = variables.size(); - variables.push_back(new double(a)); - variables.push_back(new double(b)); - variables.push_back(new double(c)); - variables.push_back(new double(d)); - - q.a = variables[varStartIndex+0]; - q.b = variables[varStartIndex+1]; - q.c = variables[varStartIndex+2]; - q.d = variables[varStartIndex+3]; - quats[id + quatsOffset -1] = q; - } - } - - // Solids - xercesc::DOMNodeList* solidsNodes = elementRoot->getElementsByTagName(TAG_solids); - const XMLSize_t solidCount = solidsNodes->getLength(); - - for (XMLSize_t i = 0; i < solidCount; ++i) { - xercesc::DOMNode* solidsNode = solidsNodes->item(i); - xercesc::DOMElement* solidsElement = dynamic_cast(solidsNode); - - xercesc::DOMNodeList* solidNodes = solidsElement->getElementsByTagName(TAG_solid); - const XMLSize_t solidCount = solidNodes->getLength(); - - for (XMLSize_t j = 0; j < solidCount; ++j) { - xercesc::DOMNode* solidNode = solidNodes->item(j); - xercesc::DOMElement* solidElement = dynamic_cast(solidNode); - - int id = getIntAttr(solidElement, ATTR_id); - int p = getIntAttr(solidElement, ATTR_point); - int n = getIntAttr(solidElement, ATTR_normal); - int d = getIntAttr(solidElement, ATTR_displacement); - int q = getIntAttr(solidElement, ATTR_quaternion); - - GCS::Solid s; - s.p = points[p-1]; - s.n = norms[n-1]; - s.d = disps[d-1]; - s.q = quats[q-1]; - - solids.push_back(s); - } - } - - - - // Constraints - xercesc::DOMNodeList* constraintsNodes = elementRoot->getElementsByTagName(TAG_constraints); - const XMLSize_t constraintsCount = constraintsNodes->getLength(); - - for (XMLSize_t i = 0; i < constraintsCount; ++i) { - xercesc::DOMNode* constraintsNode = constraintsNodes->item(i); - xercesc::DOMElement* constraintsElement = dynamic_cast(constraintsNode); - - xercesc::DOMNodeList* constraintNodes = constraintsElement->getElementsByTagName(TAG_constraint); - const XMLSize_t constraintCount = constraintNodes->getLength(); - - for (XMLSize_t j = 0; j < constraintCount; ++j) { - xercesc::DOMNode* constraintNode = constraintNodes->item(j); - xercesc::DOMElement* constraintElement = dynamic_cast(constraintNode); - - int id = getIntAttr(constraintElement, ATTR_id); - - const XMLCh* xmlch_kind = constraintElement->getAttribute(ATTR_kind); - - //PlaneParallel Assembly - if (xercesc::XMLString::equals(xmlch_kind, KIND_Parallel_AS)) { - int s1 = getIntAttr(constraintElement, ATTR_solid1); - int s2 = getIntAttr(constraintElement, ATTR_solid2); - int t = getIntAttr(constraintElement, ATTR_type); - - int paramStartIndex = parameters.size(); - parameters.push_back(new double(t)); - - GCS::Constraint *constr - = new GCS::ConstraintParralelFaceAS( solids[s1-1], solids[s2-1], - (GCS::ParallelType*) parameters[paramStartIndex] ); - constraints.push_back(constr); - } - //Distance Assembly - if (xercesc::XMLString::equals(xmlch_kind, KIND_Distance_AS)) { - int s1 = getIntAttr(constraintElement, ATTR_solid1); - int s2 = getIntAttr(constraintElement, ATTR_solid2); - double t = getDoubleAttr(constraintElement, ATTR_distance); - - int paramStartIndex = parameters.size(); - parameters.push_back(new double(t)); - - GCS::Constraint *constr - = new GCS::ConstraintFaceDistanceAS( solids[s1-1], solids[s2-1], parameters[paramStartIndex] ); - constraints.push_back(constr); - } - } - } - return true; - } - catch (xercesc::XMLException& e) { - char* message = xercesc::XMLString::transcode(e.getMessage()); - std::cout << "Error parsing file: " << message << std::endl; - xercesc::XMLString::release(&message); - } -} - -int InputParser::getIntAttr(xercesc::DOMElement* element, XMLCh* attr) -{ - const XMLCh* xmlch_val = element->getAttribute(attr); - return xercesc::XMLString::parseInt(xmlch_val); -} - -double InputParser::getDoubleAttr(xercesc::DOMElement* element, XMLCh* attr) -{ - const XMLCh* xmlch_val = element->getAttribute(attr); - xercesc::XMLDouble xmldouble_val(xmlch_val); - return xmldouble_val.getValue(); -} - diff --git a/src/Mod/Assembly/App/gcs3d/InputParser.h b/src/Mod/Assembly/App/gcs3d/InputParser.h deleted file mode 100644 index e6f71b1d57d9..000000000000 --- a/src/Mod/Assembly/App/gcs3d/InputParser.h +++ /dev/null @@ -1,60 +0,0 @@ - -#include -#include - -#include "GCS.h" - -class InputParser -{ -public: - InputParser(); - ~InputParser(); - - bool readInputFileAS(std::string &fileName, - std::vector &variables, - std::vector ¶meters, - std::vector &points, - std::vector &normals, - std::vector &displacements, - std::vector &quaternions, - std::vector &solids, - std::vector &constraints); - - int getIntAttr(xercesc::DOMElement* element, XMLCh* attr); - double getDoubleAttr(xercesc::DOMElement* element, XMLCh* attr); -private: - xercesc::XercesDOMParser *m_InputFileParser; - - XMLCh* TAG_points; - XMLCh* TAG_constraints; - XMLCh* TAG_point; - XMLCh* TAG_constraint; - XMLCh* ATTR_id; - XMLCh* ATTR_x; - XMLCh* ATTR_y; - XMLCh* ATTR_z; - XMLCh* ATTR_point; - XMLCh* ATTR_kind; - XMLCh* ATTR_distance; - XMLCh* TAG_GCS_AS; - XMLCh* TAG_quaternions; - XMLCh* TAG_quaternion; - XMLCh* TAG_normals; - XMLCh* TAG_normal; - XMLCh* TAG_displacements; - XMLCh* TAG_displacement; - XMLCh* TAG_solids; - XMLCh* TAG_solid; - XMLCh* KIND_Parallel_AS; - XMLCh* KIND_Distance_AS; - XMLCh* ATTR_a; - XMLCh* ATTR_b; - XMLCh* ATTR_c; - XMLCh* ATTR_d; - XMLCh* ATTR_quaternion; - XMLCh* ATTR_type; - XMLCh* ATTR_normal; - XMLCh* ATTR_displacement; - XMLCh* ATTR_solid1; - XMLCh* ATTR_solid2; -}; diff --git a/src/Mod/Assembly/App/gcs3d/SubSystem.cpp b/src/Mod/Assembly/App/gcs3d/SubSystem.cpp deleted file mode 100644 index e6bb8321231a..000000000000 --- a/src/Mod/Assembly/App/gcs3d/SubSystem.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 -#include -#include "SubSystem.h" - -namespace GCS -{ - -// SubSystem -SubSystem::SubSystem(std::vector &clist_, VEC_pD ¶ms) -: clist(clist_) -{ - MAP_pD_pD dummymap; - initialize(params, dummymap); -} - -SubSystem::SubSystem(std::vector &clist_, VEC_pD ¶ms, - MAP_pD_pD &reductionmap) -: clist(clist_) -{ - initialize(params, reductionmap); -} - -SubSystem::~SubSystem() -{ -} - -void SubSystem::initialize(VEC_pD ¶ms, MAP_pD_pD &reductionmap) -{ - csize = clist.size(); - - // tmpplist will contain the subset of parameters from params that are - // relevant for the constraints listed in clist - VEC_pD tmpplist; - { - SET_pD s1(params.begin(), params.end()); - SET_pD s2; - for (std::vector::iterator constr=clist.begin(); - constr != clist.end(); ++constr) { - (*constr)->revertParams(); // ensure that the constraint points to the original parameters - VEC_pD constr_params = (*constr)->params(); - s2.insert(constr_params.begin(), constr_params.end()); - } - std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), - std::back_inserter(tmpplist) ); - } - - plist.clear(); - MAP_pD_I rindex; - if (reductionmap.size() > 0) { - int i=0; - MAP_pD_I pindex; - for (VEC_pD::const_iterator itt=tmpplist.begin(); - itt != tmpplist.end(); itt++) { - MAP_pD_pD::const_iterator itr = reductionmap.find(*itt); - if (itr != reductionmap.end()) { - MAP_pD_I::const_iterator itp = pindex.find(itr->second); - if (itp == pindex.end()) { // the reduction target is not in plist yet, so add it now - plist.push_back(itr->second); - rindex[itr->first] = i; - pindex[itr->second] = i; - i++; - } - else // the reduction target is already in plist, just inform rindex - rindex[itr->first] = itp->second; - } - else if (pindex.find(*itt) == pindex.end()) { // not in plist yet, so add it now - plist.push_back(*itt); - pindex[*itt] = i; - i++; - } - } - } - else - plist = tmpplist; - - psize = plist.size(); - pvals.resize(psize); - pmap.clear(); - for (int j=0; j < psize; j++) { - pmap[plist[j]] = &pvals[j]; - pvals[j] = *plist[j]; - } - for (MAP_pD_I::const_iterator itr=rindex.begin(); itr != rindex.end(); ++itr) - pmap[itr->first] = &pvals[itr->second]; - - c2p.clear(); - p2c.clear(); - for (std::vector::iterator constr=clist.begin(); - constr != clist.end(); ++constr) { - (*constr)->revertParams(); // ensure that the constraint points to the original parameters - VEC_pD constr_params_orig = (*constr)->params(); - SET_pD constr_params; - for (VEC_pD::const_iterator p=constr_params_orig.begin(); - p != constr_params_orig.end(); ++p) { - MAP_pD_pD::const_iterator pmapfind = pmap.find(*p); - if (pmapfind != pmap.end()) - constr_params.insert(pmapfind->second); - } - for (SET_pD::const_iterator p=constr_params.begin(); - p != constr_params.end(); ++p) { -// jacobi.set(*constr, *p, 0.); - c2p[*constr].push_back(*p); - p2c[*p].push_back(*constr); - } -// (*constr)->redirectParams(pmap); // redirect parameters to pvec - } -} - -void SubSystem::redirectParams() -{ - // copying values to pvals - for (MAP_pD_pD::const_iterator p=pmap.begin(); - p != pmap.end(); ++p) - *(p->second) = *(p->first); - - // redirect constraints to point to pvals - for (std::vector::iterator constr=clist.begin(); - constr != clist.end(); ++constr) { - (*constr)->revertParams(); // this line will normally not be necessary - (*constr)->redirectParams(pmap); - } -} - -void SubSystem::revertParams() -{ - for (std::vector::iterator constr=clist.begin(); - constr != clist.end(); ++constr) - (*constr)->revertParams(); -} - -void SubSystem::getParamMap(MAP_pD_pD &pmapOut) -{ - pmapOut = pmap; -} - -void SubSystem::getParamList(VEC_pD &plistOut) -{ - plistOut = plist; -} - -void SubSystem::getParams(VEC_pD ¶ms, Eigen::VectorXd &xOut) -{ - if (xOut.size() != int(params.size())) - xOut.setZero(params.size()); - - for (int j=0; j < int(params.size()); j++) { - MAP_pD_pD::const_iterator - pmapfind = pmap.find(params[j]); - if (pmapfind != pmap.end()) - xOut[j] = *(pmapfind->second); - } -} - -void SubSystem::getParams(Eigen::VectorXd &xOut) -{ - if (xOut.size() != psize) - xOut.setZero(psize); - - for (int i=0; i < psize; i++) - xOut[i] = pvals[i]; -} - -void SubSystem::setParams(VEC_pD ¶ms, Eigen::VectorXd &xIn) -{ - assert(xIn.size() == int(params.size())); - for (int j=0; j < int(params.size()); j++) { - MAP_pD_pD::const_iterator - pmapfind = pmap.find(params[j]); - if (pmapfind != pmap.end()) - *(pmapfind->second) = xIn[j]; - } -} - -void SubSystem::setParams(Eigen::VectorXd &xIn) -{ - assert(xIn.size() == psize); - for (int i=0; i < psize; i++) - pvals[i] = xIn[i]; -} - -double SubSystem::error() -{ - double err = 0.; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr) { - double tmp = (*constr)->error(); - err += tmp*tmp; - } - err *= 0.5; - return err; -} - -void SubSystem::calcResidual(Eigen::VectorXd &r) -{ - assert(r.size() == csize); - - int i=0; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr, i++) { - r[i] = (*constr)->error(); - } -} - -void SubSystem::calcResidual(Eigen::VectorXd &r, double &err) -{ - assert(r.size() == csize); - - int i=0; - err = 0.; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr, i++) { - r[i] = (*constr)->error(); - err += r[i]*r[i]; - } - err *= 0.5; -} - -/* -void SubSystem::calcJacobi() -{ - assert(grad.size() != xsize); - - for (MAP_pD_pD::const_iterator param=pmap.begin(); - param != pmap.end(); ++param) { - // assert(p2c.find(param->second) != p2c.end()); - std::vector constrs=p2c[param->second]; - for (std::vector::const_iterator constr = constrs.begin(); - constr != constrs.end(); ++constr) - jacobi.set(*constr,param->second,(*constr)->grad(param->second)); - } -} -*/ - -void SubSystem::calcJacobi(VEC_pD ¶ms, Eigen::MatrixXd &jacobi) -{ - jacobi.setZero(csize, params.size()); - for (int j=0; j < int(params.size()); j++) { - MAP_pD_pD::const_iterator - pmapfind = pmap.find(params[j]); - if (pmapfind != pmap.end()) - for (int i=0; i < csize; i++) - jacobi(i,j) = clist[i]->grad(pmapfind->second); - } -} - -void SubSystem::calcJacobi(Eigen::MatrixXd &jacobi) -{ - calcJacobi(plist, jacobi); -} - -void SubSystem::calcGrad(VEC_pD ¶ms, Eigen::VectorXd &grad) -{ - assert(grad.size() == int(params.size())); - - grad.setZero(); - for (int j=0; j < int(params.size()); j++) { - MAP_pD_pD::const_iterator - pmapfind = pmap.find(params[j]); - if (pmapfind != pmap.end()) { - // assert(p2c.find(pmapfind->second) != p2c.end()); - std::vector constrs=p2c[pmapfind->second]; - for (std::vector::const_iterator constr = constrs.begin(); - constr != constrs.end(); ++constr) - grad[j] += (*constr)->error() * (*constr)->grad(pmapfind->second); - } - } -} - -void SubSystem::calcGrad(Eigen::VectorXd &grad) -{ - calcGrad(plist, grad); -} - -double SubSystem::maxStep(VEC_pD ¶ms, Eigen::VectorXd &xdir) -{ - assert(xdir.size() == int(params.size())); - - MAP_pD_D dir; - for (int j=0; j < int(params.size()); j++) { - MAP_pD_pD::const_iterator pmapfind = pmap.find(params[j]); - if (pmapfind != pmap.end()) - dir[pmapfind->second] = xdir[j]; - } - - double alpha=1e10; - for (std::vector::iterator constr=clist.begin(); - constr != clist.end(); ++constr) - alpha = (*constr)->maxStep(dir, alpha); - - return alpha; -} - -double SubSystem::maxStep(Eigen::VectorXd &xdir) -{ - return maxStep(plist, xdir); -} - -void SubSystem::applySolution() -{ - for (MAP_pD_pD::const_iterator it=pmap.begin(); - it != pmap.end(); ++it) - *(it->first) = *(it->second); -} - -void SubSystem::analyse(Eigen::MatrixXd &J, Eigen::MatrixXd &ker, Eigen::MatrixXd &img) -{ -} - -void SubSystem::report() -{ -} - -void SubSystem::printResidual() -{ - Eigen::VectorXd r(csize); - int i=0; - double err = 0.; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr, i++) { - r[i] = (*constr)->error(); - err += r[i]*r[i]; - } - err *= 0.5; - std::cout << "Residual r = " << r.transpose() << std::endl; - std::cout << "Residual err = " << err << std::endl; -} - - -} //namespace GCS diff --git a/src/Mod/Assembly/App/gcs3d/SubSystem.h b/src/Mod/Assembly/App/gcs3d/SubSystem.h deleted file mode 100644 index 1e313e35ea56..000000000000 --- a/src/Mod/Assembly/App/gcs3d/SubSystem.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 FREEGCS_SUBSYSTEM_H -#define FREEGCS_SUBSYSTEM_H - -#undef min -#undef max - -#include -#include "Constraints.h" - -namespace GCS -{ - - class SubSystem - { - private: - int psize, csize; - std::vector clist; - VEC_pD plist; // pointers to the original parameters - MAP_pD_pD pmap; // redirection map from the original parameters to pvals - VEC_D pvals; // current variables vector (psize) -// JacobianMatrix jacobi; // jacobi matrix of the residuals - std::map c2p; // constraint to parameter adjacency list - std::map > p2c; // parameter to constraint adjacency list - void initialize(VEC_pD ¶ms, MAP_pD_pD &reductionmap); // called by the constructors - public: - SubSystem(std::vector &clist_, VEC_pD ¶ms); - SubSystem(std::vector &clist_, VEC_pD ¶ms, - MAP_pD_pD &reductionmap); - ~SubSystem(); - - int pSize() { return psize; }; - int cSize() { return csize; }; - - void redirectParams(); - void revertParams(); - - void getParamMap(MAP_pD_pD &pmapOut); - void getParamList(VEC_pD &plistOut); - - void getParams(VEC_pD ¶ms, Eigen::VectorXd &xOut); - void getParams(Eigen::VectorXd &xOut); - void setParams(VEC_pD ¶ms, Eigen::VectorXd &xIn); - void setParams(Eigen::VectorXd &xIn); - - double error(); - void calcResidual(Eigen::VectorXd &r); - void calcResidual(Eigen::VectorXd &r, double &err); - void calcJacobi(VEC_pD ¶ms, Eigen::MatrixXd &jacobi); - void calcJacobi(Eigen::MatrixXd &jacobi); - void calcGrad(VEC_pD ¶ms, Eigen::VectorXd &grad); - void calcGrad(Eigen::VectorXd &grad); - - double maxStep(VEC_pD ¶ms, Eigen::VectorXd &xdir); - double maxStep(Eigen::VectorXd &xdir); - - void applySolution(); - void analyse(Eigen::MatrixXd &J, Eigen::MatrixXd &ker, Eigen::MatrixXd &img); - void report(); - -void printResidual(); - }; - - double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir); - -} //namespace GCS - -#endif // FREEGCS_SUBSYSTEM_H diff --git a/src/Mod/Assembly/App/gcs3d/Util.h b/src/Mod/Assembly/App/gcs3d/Util.h deleted file mode 100644 index 18eacf9ad6c6..000000000000 --- a/src/Mod/Assembly/App/gcs3d/Util.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 FREEGCS_UTIL_H -#define FREEGCS_UTIL_H - -#include -#include -#include - -namespace GCS -{ - typedef std::vector VEC_pD; - typedef std::vector VEC_D; - typedef std::vector VEC_I; - typedef std::map MAP_pD_pD; - typedef std::map MAP_pD_D; - typedef std::map MAP_pD_I; - typedef std::set SET_pD; - typedef std::set SET_I; - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -} //namespace GCS - -#endif // FREEGCS_UTIL_H diff --git a/src/Mod/Assembly/App/gcs3d/main.cpp b/src/Mod/Assembly/App/gcs3d/main.cpp deleted file mode 100644 index a68ac1f22450..000000000000 --- a/src/Mod/Assembly/App/gcs3d/main.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include - -#include "Geo.h" -#include "Constraints.h" -#include "InputParser.h" -#include "OutputWriter.h" - -#include - -using namespace std; -using namespace Eigen; - -Vector3d Place(GCS::Point p, GCS::Quaternion q, GCS::Displacement di) { - - double a=*q.a, b=*q.b, c=*q.c, d=*q.d; - double norm = sqrt(pow(a,2)+pow(b,2)+pow(c,2)+pow(d,2)); - double x=a/norm, y=b/norm, z=c/norm, w=d/norm; - - Matrix3d rot; - rot(0,0) = 1-2*(pow(y,2)+pow(z,2)); - rot(0,1) = -2.0*w*z + 2.0*x*y; - rot(0,2) = 2.0*w*y + 2.0*x*z; - rot(1,0) = 2.0*w*z + 2.0*x*y; - rot(1,1) = 1-2*(pow(x,2)+pow(z,2)); - rot(1,2) = -2.0*w*x + 2.0*y*z; - rot(2,0) = -2.0*w*y + 2.0*x*z; - rot(2,1) = 2.0*w*x + 2.0*y*z; - rot(2,2) = 1-2*(pow(x,2)+pow(y,2)); - - Vector3d v(p.x, p.y, p.z); - Vector3d n = rot*v; - - if (di.x != NULL) { - n(0) += *di.x; - n(1) += *di.y; - n(2) += *di.z; - } - - return n; -} - -std::string Vec(Vector3d vec) { - - std::stringstream s; - s<<"Base.Vector(" << vec(0) << ", " << vec(1) << ", " << vec(2) <<")"; - return s.str(); -} - - -int main(int argc, char **argv) { - - if (argc<3) return 1; - - cout << endl << "loading file: " << argv[1]; - cout << endl << "generating output: " << argv[2] << endl << endl; - - vector variables; - vector parameters; - vector points; - vector norms; - vector disps; - vector quats; - vector solids; - vector constraints; - - string inputfile(argv[1]); - string outputfile(argv[2]); - - bool d2,d3; - - InputParser parser; - d3 = parser.readInputFileAS(inputfile, variables, parameters, points, norms, disps, quats, solids, constraints); - - cout << "Variables: " << variables.size() << endl << "parameters: " << parameters.size() << endl; - cout << "Points: " << points.size() << endl << "Normals: " << norms.size() << endl; - cout << "Displacements: " << disps.size() << endl; - cout << "Quaternions: " << quats.size() << endl; - cout << "Solids: " << solids.size() << endl; - cout << "Constraints: " << constraints.size() << endl; - - //init output writing - remove(outputfile.c_str()); - ofstream file; - file.open (outputfile.c_str()); - if (!file.is_open()) return 0; - //import all needed modules - file << "import Part" << endl << "from FreeCAD import Base" << endl << endl; - //open new document - file << "App.newDocument(\"solver\")" << endl << endl; - GCS::Displacement emd; - for (int i=0; i -#include - -using namespace Eigen; - -// minimizes ( 0.5 * x^T * H * x + g^T * x ) under the condition ( A*x + c = 0 ) -// it returns the solution in x, the row-space of A in Y, and the null space of A in Z -int qp_eq(MatrixXd &H, VectorXd &g, MatrixXd &A, VectorXd &c, - VectorXd &x, MatrixXd &Y, MatrixXd &Z) -{ - FullPivHouseholderQR qrAT(A.transpose()); - MatrixXd Q = qrAT.matrixQ (); - - size_t params_num = qrAT.rows(); - size_t constr_num = qrAT.cols(); - size_t rank = qrAT.rank(); - - if (rank != constr_num || constr_num > params_num) - return -1; - - // A^T = Q*R*P^T = Q1*R1*P^T - // Q = [Q1,Q2], R=[R1;0] - // Y = Q1 * inv(R^T) * P^T - // Z = Q2 - Y = qrAT.matrixQR().topRows(constr_num) - .triangularView() - .transpose() - .solve(Q.leftCols(rank)) - * qrAT.colsPermutation().transpose(); - if (params_num == rank) - x = - Y * c; - else { - Z = Q.rightCols(params_num-rank); - - MatrixXd ZTHZ = Z.transpose() * H * Z; - VectorXd rhs = Z.transpose() * (H * Y * c - g); - - VectorXd y = ZTHZ.colPivHouseholderQr().solve(rhs); - - x = - Y * c + Z * y; - } - - return 0; -} diff --git a/src/Mod/Assembly/App/gcs3d/qp_eq.h b/src/Mod/Assembly/App/gcs3d/qp_eq.h deleted file mode 100644 index f05ca6d52247..000000000000 --- a/src/Mod/Assembly/App/gcs3d/qp_eq.h +++ /dev/null @@ -1,25 +0,0 @@ -/*************************************************************************** - * Copyright (c) Konstantinos Poulios (logari81@gmail.com) 2011 * - * * - * 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 - -int qp_eq(Eigen::MatrixXd &H, Eigen::VectorXd &g, Eigen::MatrixXd &A, Eigen::VectorXd &c, - Eigen::VectorXd &x, Eigen::MatrixXd &Y, Eigen::MatrixXd &Z); diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index b28a58e02b06..133be2982fd4 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -6,6 +6,7 @@ endif(MSVC) include_directories( ${CMAKE_SOURCE_DIR}/src + ${CMAKE_SOURCE_DIR}/src/Mod/Assembly/App ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${COIN_INCLUDE_DIR} @@ -15,7 +16,7 @@ include_directories( ${PYTHON_INCLUDE_DIRS} ${COIN3D_INCLUDE_DIRS} ${XercesC_INCLUDE_DIRS} - #${ODE_INCLUDE_DIRS} + ${EIGEN3_INCLUDE_DIR} ) set(AssemblyGui_LIBS diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 4af10a38c584..f655e857d133 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -77,7 +77,7 @@ void CmdAssemblyAddNewPart::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",PartName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); - doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),PartName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addPart(App.activeDocument().%s) ",fatherName.c_str(),PartName.c_str()); } Command::addModule(App,"PartDesign"); Command::addModule(Gui,"PartDesignGui"); @@ -139,7 +139,7 @@ void CmdAssemblyAddNewComponent::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','%s')",CompName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); - doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),CompName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addComponent(App.activeDocument().%s) ",fatherName.c_str(), CompName.c_str()); } } diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index 6ef91bffc26a..349950c56db0 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -83,6 +84,17 @@ bool getConstraintPrerequisits(Assembly::ItemAssembly **Asm,Assembly::Constraint return false; } + +std::string asSubLinkString(Assembly::ItemPart* part, std::string element) { + std::string buf; + buf += "(App.ActiveDocument."; + buf += part->getNameInDocument(); + buf += ",['"; + buf += element; + buf += "'])"; + return buf; +} + //=========================================================================== DEF_STD_CMD(CmdAssemblyConstraintAxle); @@ -108,11 +120,26 @@ void CmdAssemblyConstraintAxle::activated(int iMsg) // retrive the standard objects needed if(getConstraintPrerequisits(&Asm,&ConstGrp)) return; + + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { + Base::Console().Message("you must select two geometries on two diffrent parts\n"); + return; + }; + + Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); + Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); + if(!part1 || !part2) { + Base::Console().Message("The selected objects need to belong to the active assembly\n"); + return; + }; openCommand("Insert Constraint Axle"); std::string ConstrName = getUniqueObjectName("Axle"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintAxis','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().%s.addConstraint(App.activeDocument().ActiveObject)",ConstGrp->getNameInDocument()); } From 952d9140d3dd0d4f5f5e41d06789b59f009dde4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 25 Apr 2013 12:14:01 +0200 Subject: [PATCH 047/664] add opendcm constraint solver --- .../Assembly/App/opendcm/.kdev_include_paths | 1 + src/Mod/Assembly/App/opendcm/core.hpp | 28 + .../App/opendcm/core/clustergraph.hpp | 1520 +++++++++++++++++ .../Assembly/App/opendcm/core/constraint.hpp | 512 ++++++ .../Assembly/App/opendcm/core/equations.hpp | 189 ++ .../Assembly/App/opendcm/core/geometry.hpp | 481 ++++++ src/Mod/Assembly/App/opendcm/core/kernel.hpp | 425 +++++ src/Mod/Assembly/App/opendcm/core/logging.hpp | 94 + src/Mod/Assembly/App/opendcm/core/object.hpp | 269 +++ .../Assembly/App/opendcm/core/property.hpp | 167 ++ .../Assembly/App/opendcm/core/sheduler.hpp | 100 ++ src/Mod/Assembly/App/opendcm/core/system.hpp | 327 ++++ src/Mod/Assembly/App/opendcm/core/traits.hpp | 101 ++ .../App/opendcm/core/transformation.hpp | 292 ++++ src/Mod/Assembly/App/opendcm/externalize.hpp | 73 + src/Mod/Assembly/App/opendcm/module3d.hpp | 32 + .../Assembly/App/opendcm/module3d/angle.hpp | 149 ++ .../App/opendcm/module3d/clustermath.hpp | 770 +++++++++ .../Assembly/App/opendcm/module3d/defines.hpp | 33 + .../App/opendcm/module3d/distance.hpp | 292 ++++ src/Mod/Assembly/App/opendcm/module3d/dof.hpp | 133 ++ .../App/opendcm/module3d/geometry.hpp | 160 ++ .../Assembly/App/opendcm/module3d/module.hpp | 546 ++++++ .../App/opendcm/module3d/parallel.hpp | 215 +++ .../Assembly/App/opendcm/module3d/solver.hpp | 367 ++++ .../Assembly/App/opendcm/module3d/state.hpp | 95 ++ .../App/opendcm/modulePart/geometry.hpp | 92 + .../App/opendcm/modulePart/module.hpp | 558 ++++++ .../App/opendcm/moduleState/defines.hpp | 36 + .../moduleState/edge_vertex_generator.hpp | 72 + .../moduleState/edge_vertex_generator_imp.hpp | 57 + .../moduleState/edge_vertex_parser.hpp | 71 + .../moduleState/edge_vertex_parser_imp.hpp | 55 + .../App/opendcm/moduleState/extractor.hpp | 119 ++ .../App/opendcm/moduleState/generator.hpp | 82 + .../App/opendcm/moduleState/generator_imp.hpp | 72 + .../App/opendcm/moduleState/indent.hpp | 63 + .../App/opendcm/moduleState/karma_trans.hpp | 155 ++ .../App/opendcm/moduleState/module.hpp | 98 ++ .../opendcm/moduleState/object_generator.hpp | 72 + .../moduleState/object_generator_imp.hpp | 57 + .../App/opendcm/moduleState/object_parser.hpp | 98 ++ .../opendcm/moduleState/object_parser_imp.hpp | 63 + .../App/opendcm/moduleState/parser.hpp | 82 + .../App/opendcm/moduleState/parser_imp.hpp | 71 + .../moduleState/property_generator.hpp | 102 ++ .../moduleState/property_generator_imp.hpp | 43 + .../opendcm/moduleState/property_parser.hpp | 120 ++ .../moduleState/property_parser_imp.hpp | 60 + .../App/opendcm/moduleState/traits.hpp | 53 + .../App/opendcm/moduleState/traits_impl.hpp | 160 ++ src/Mod/Assembly/App/opendcm/modulepart.hpp | 29 + src/Mod/Assembly/App/opendcm/modulestate.hpp | 29 + 53 files changed, 9940 insertions(+) create mode 100644 src/Mod/Assembly/App/opendcm/.kdev_include_paths create mode 100644 src/Mod/Assembly/App/opendcm/core.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/clustergraph.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/constraint.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/equations.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/kernel.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/logging.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/object.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/property.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/sheduler.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/system.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/traits.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/transformation.hpp create mode 100644 src/Mod/Assembly/App/opendcm/externalize.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/angle.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/defines.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/distance.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/dof.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/parallel.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/solver.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/state.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulePart/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/defines.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/indent.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/traits.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulepart.hpp create mode 100644 src/Mod/Assembly/App/opendcm/modulestate.hpp diff --git a/src/Mod/Assembly/App/opendcm/.kdev_include_paths b/src/Mod/Assembly/App/opendcm/.kdev_include_paths new file mode 100644 index 000000000000..c0f755818ff9 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/.kdev_include_paths @@ -0,0 +1 @@ +/usr/include/eigen3 diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp new file mode 100644 index 000000000000..8d03a1d7fe62 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -0,0 +1,28 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_CORE_H +#define DCM_CORE_H + +#include "core/geometry.hpp" +#include "core/kernel.hpp" +#include "core/system.hpp" + +#endif //DCM_CORE_H + diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp new file mode 100644 index 000000000000..fac9f172ce60 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -0,0 +1,1520 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef CLUSTERGRAPH_HPP +#define CLUSTERGRAPH_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "property.hpp" +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace details { + +typedef boost::adjacency_list_traits list_traits; +typedef int universalID; + +struct IDgen { + universalID* counter; + + IDgen() { + counter = new universalID(10); + }; + IDgen(universalID id) { + counter = new universalID(id); + }; + ~IDgen() { + delete counter; + }; + universalID generate() { + return ++(*counter); + }; + universalID count() { + return (*counter); + }; + void setCount(universalID id) { + *counter = id; + }; +}; + +typedef boost::shared_ptr IDpointer; + +struct clear_ptr { + template + void operator()(T& t) const { + t.reset(); + }; +}; + +template +struct sps { //shared_ptr sequence + typedef typename mpl::transform >::type spv; + typedef typename fusion::result_of::as_vector::type type; +}; + +} + +typedef details::list_traits::vertex_descriptor LocalVertex; +typedef details::list_traits::edge_descriptor LocalEdge; +typedef details::universalID GlobalVertex; +struct GlobalEdge { + GlobalVertex source; + GlobalVertex target; + details::universalID ID; + + bool operator==(const GlobalEdge& second) const { + return ID==second.ID; + }; + bool operator!=(const GlobalEdge& second) const { + return ID!=second.ID; + }; + bool valid() { + return ID>9; + }; +}; + + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, + boost::undirectedS, + fusion::vector< GlobalVertex, typename details::pts::type, + typename details::sps::type>, + fusion::vector< typename details::pts::type, + std::vector< fusion::vector< typename details::sps::type, GlobalEdge > > > >, + public boost::noncopyable, + public boost::enable_shared_from_this > { + +public: + typedef fusion::vector< typename details::sps::type, GlobalEdge > edge_bundle_single; + typedef fusion::vector< typename details::pts::type, std::vector< edge_bundle_single > > edge_bundle; + typedef typename std::vector< edge_bundle_single >::iterator edge_single_iterator; + typedef fusion::vector< GlobalVertex, typename details::pts::type, + typename details::sps::type > vertex_bundle; + + + typedef boost::adjacency_list< boost::listS, boost::listS, + boost::undirectedS, vertex_bundle, edge_bundle > Graph; + + typedef boost::enable_shared_from_this > sp_base; + + //if changed_prop is not a property we have to add it now + typedef typename mpl::if_< + boost::is_same< + typename mpl::find::type, + typename mpl::end::type >, + typename mpl::push_back::type, + cluster_prop >::type cluster_properties; + + typedef typename details::pts::type cluster_bundle; + + typedef typename boost::graph_traits::vertex_iterator local_vertex_iterator; + typedef typename boost::graph_traits::edge_iterator local_edge_iterator; + typedef typename boost::graph_traits::out_edge_iterator local_out_edge_iterator; + + typedef std::map > ClusterMap; + + cluster_bundle m_cluster_bundle; + + typedef edge_prop edge_properties; + typedef vertex_prop vertex_properties; + +private: + struct global_extractor { + typedef GlobalEdge& result_type; + template + result_type operator()(T& bundle) const { + return fusion::at_c<1>(bundle); + }; + }; + struct global_vertex_extractor { + typedef GlobalVertex result_type; + ClusterGraph& graph; + global_vertex_extractor(ClusterGraph& g) : graph(g) {}; + result_type operator()(LocalVertex& v) const { + return graph.getGlobalVertex(v); + }; + }; + + template + struct object_extractor { + + typedef boost::shared_ptr base_type; + typedef base_type& result_type; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + + result_type operator()(vertex_bundle& bundle) const { + return fusion::at(fusion::at_c<2>(bundle)); + }; + result_type operator()(edge_bundle_single& bundle) const { + return fusion::at(fusion::at_c<0>(bundle)); + }; + }; + + template + struct property_extractor { + + typedef typename prop::type base_type; + typedef base_type& result_type; + + typedef typename mpl::if_< is_edge_property, edge_properties, vertex_properties >::type sequence; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + typedef typename mpl::if_< is_edge_property, mpl::int_<0>, mpl::int_<1> >::type pos; + + template< typename seq> + result_type operator()(seq& b) const { + return fusion::at(fusion::at(b)); + }; + }; + + struct edge_copier { + edge_copier(const ClusterGraph& g1, ClusterGraph& g2) + : graph1(g1), graph2(g2) { } + + void operator()(LocalEdge e1, LocalEdge e2) const { + graph2[e2] = graph1[e1]; + } + const ClusterGraph& graph1; + ClusterGraph& graph2; + }; + + struct vertex_copier { + vertex_copier(const ClusterGraph& g1, ClusterGraph& g2) + : graph1(g1), graph2(g2) { } + + void operator()(LocalVertex v1, LocalVertex v2) const { + graph2[v2] = graph1[v1]; + } + const ClusterGraph& graph1; + ClusterGraph& graph2; + }; + +public: + //iterators + typedef boost::transform_iterator global_edge_iterator; + typedef boost::transform_iterator global_vertex_iterator; + + template + struct object_iterator : public boost::transform_iterator, edge_single_iterator> { + object_iterator(edge_single_iterator it, object_extractor f) + : boost::transform_iterator,edge_single_iterator>(it, f) {}; + }; + + typedef typename ClusterMap::iterator cluster_iterator; + typedef typename ClusterMap::const_iterator const_cluster_iterator; + + ClusterGraph() : m_id(new details::IDgen) {}; + + ClusterGraph(boost::shared_ptr g) : m_parent(g), m_id(new details::IDgen) { + if(g) m_id = g->m_id; + }; + + ~ClusterGraph() {}; + + /** + * @brief Copys the Clustergraph into a new one + * + * Copys this cluster and all subclusters into the give one, which is cleared bevore copying. Be + * aware that all objects and properties are only copied, and as some are shared pointers (namely + * all objects) you may have to clone them. If needed this can be done with the supplied functor, + * which receives all copied objects to his function operator which returns the new object. + * @param into The Graph that should be a copy of this + * @param functor The function objects which gets the graph objects and returns the ones for the + * copied graph + */ + template + void copyInto(boost::shared_ptr into, Functor& functor) const { + + //lists does not provide vertex index, so we have to build our own + typedef std::map IndexMap; + IndexMap mapIndex; + boost::associative_property_map propmapIndex(mapIndex); + + std::pair vit = boost::vertices(*this); + for(int c=0; vit.first != vit.second; vit.first++, c++) + put(propmapIndex, *vit.first, c); + + //first copy all vertices and edges, but be aware that the objects in the new graph + //are also copys only and point to the old graph. there is a bug in older boost version + //(<1.5 i belive) that breaks vertex_all propety map for bundled properties, so we + //have to create our own copie functors + into->clear(); + vertex_copier vc(*this, *into); + edge_copier ec(*this, *into); + boost::copy_graph(*this, *into, boost::vertex_index_map(propmapIndex).vertex_copy(vc).edge_copy(ec)); + + //set the IDgen to the same value to avoid duplicate id's in the copied cluster + into->m_id->setCount(m_id->count()); + + //now that we have all vertices we can recreate the subclusters + std::pair it = clusters(); + for(; it.first!=it.second; it.first++) { + //create the new Graph + boost::shared_ptr ng = boost::shared_ptr(new ClusterGraph(into)); + + //we already have the new vertex, however, we need to find it + GlobalVertex gv = getGlobalVertex((*it.first).first); + LocalVertex lv = into->getLocalVertex(gv).first; + + //add the new graph to the subclustermap + into->m_clusters[lv] = ng; + + //copy the subcluster + (*it.first).second->copyInto(ng, functor); + } + + //lets see if the objects need special treatment + into->for_each_object(functor, false); + }; + + template + bool operator==(const T& other) const { + return this == &other; + }; + + template + bool operator!=(const T& other) const { + return !(this == &other); + }; + + void setChanged() { + setClusterProperty(true); + }; + + /* ******************************************************* + * Cluster Property + * *******************************************************/ + template + typename P::type& getClusterProperty() { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(m_cluster_bundle); + }; + template + typename P::type& getSubclusterProperty(LocalVertex v) { + return getVertexCluster(v)->getClusterProperty

(); + }; + + template + void setClusterProperty(typename P::type p) { + getClusterProperty

() = p; + }; + + + /* ******************************************************* + * Subclustering + * *******************************************************/ + std::pair, LocalVertex> createCluster() { + vertex_bundle vp; + fusion::at_c<0>(vp) = m_id->generate(); + LocalVertex v= boost::add_vertex(vp, *this); + return std::pair, LocalVertex>(m_clusters[v] = boost::shared_ptr(new ClusterGraph(sp_base::shared_from_this())), v); + }; + + boost::shared_ptr parent() { + return m_parent; + }; + + const boost::shared_ptr parent() const { + return m_parent; + }; + bool isRoot() const { + return m_parent ? false : true; + }; + + boost::shared_ptr root() { + return isRoot() ? sp_base::shared_from_this() : m_parent->root(); + }; + + const boost::shared_ptr root() const { + return isRoot() ? sp_base::shared_from_this() : m_parent->root(); + }; + + std::pair clusters() { + return std::make_pair(m_clusters.begin(), m_clusters.end()); + } + std::pair clusters() const { + return std::make_pair(m_clusters.begin(), m_clusters.end()); + } + + std::size_t numClusters() const { + return m_clusters.size(); + } + + bool isCluster(LocalVertex v) { + return (m_clusters.find(v) != m_clusters.end()); + }; + + boost::shared_ptr getVertexCluster(LocalVertex v) { + if(isCluster(v)) + return m_clusters[v]; + //TODO:throw if not a cluster + return sp_base::shared_from_this(); + }; + + LocalVertex getClusterVertex(boost::shared_ptr g) { + std::pair it = clusters(); + for(; it.first!=it.second; it.first++) { + if((*it.first).second == g) + return (*it.first).first; + } + return LocalVertex(); + }; + + template + void removeCluster(boost::shared_ptr g, Functor& f) { + removeCluster(getClusterVertex(g), f); + }; + void removeCluster(boost::shared_ptr g) { + placehoder p; + removeCluster(getClusterVertex(g), p); + }; + void clearClusters() { + m_clusters.clear(); + }; + + /** + * @brief Remove a subcluster and applys the functor to all removed edges and vertices + * + * All downstream elements of the local vertex v will be removed after the functor is applied to there + * edges and vertices. Note that the LocalVertex which represents the cluster to delete is not passed + * to the functor. When ever the cluster is changed it will be passed to the functor, so that it need + * to have three overloads: operator()(GlobalEdge), operator()(GlobalVertex), operator()(ClusterGraph&) + * + * @param v Local vertex which is a cluster and which should be deleted + * @param f Functor to apply on all graph elements + */ + template + void removeCluster(LocalVertex v, Functor& f) { + + typename ClusterMap::iterator it = m_clusters.find(v); + if(it == m_clusters.end()) + return; //TODO:throw + + std::pair > res = *it; + + //apply functor to all vertices and edges in the subclusters + f(res.second); + res.second->remove_vertices(f, true); + + //remove from map, delete subcluster and remove vertex + m_clusters.erase(v); + boost::clear_vertex(v, *this); //should not be needed, just to ensure it + boost::remove_vertex(v, *this); + }; + void removeCluster(LocalVertex v) { + placehoder p; + removeCluster(v, p); + }; + +protected: + template + void remove_vertices(Functor& f, bool recursive = false) { + + std::pair vit = boost::vertices(*this); + //we iterate forward before deleting to not invalidate our iterator + while(vit.first != vit.second) { + LocalVertex v = *(vit.first); + vit.first++; + + if(!isCluster(v)) { + //let the functor know we remove this vertex + f(getGlobalVertex(v)); + //need to do this to allow the removal of all relevant edges to this vertex, even upstream + removeVertex(v, f); + } + }; + + if(recursive) { + cluster_iterator cit; + for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->remove_vertices(f, recursive); + } + } + }; + + + + /* ******************************************************* + * Creation Handling + * *******************************************************/ + +public: + /** + * @brief Add a vertex to the local cluster + * + * @return fusion:vector< LocalVertex, GlobalVertex > with the local and global vertex descriptor + **/ + fusion::vector addVertex() { + + vertex_bundle vp; + fusion::at_c<0>(vp) = m_id->generate(); + LocalVertex v= boost::add_vertex(vp, *this); + + setChanged(); + return fusion::make_vector(v, m_id->count()); + }; + + std::pair globalVertices() { + std::pair res = boost::vertices(*this); + global_vertex_iterator begin = boost::make_transform_iterator(res.first, global_vertex_extractor(*this)); + global_vertex_iterator end = boost::make_transform_iterator(res.second, global_vertex_extractor(*this)); + + return std::pair(begin, end); + }; + + /** + * @brief Returns the edge between the local vertices + * + * This function is the same as boost::edge(source, target, Graph) and only added for convienience. + * + * @param source LocalEdge as edge source + * @param target LocalEdge as edge target + * @return std::pair with the local edge descriptor if existing. The bool value shows if the + * edge exists or not + **/ + std::pair edge(LocalVertex source, LocalVertex target) { + return boost::edge(source, target, *this); + }; + + /** + * @brief Add a edge between two vertices, defined by local descriptors. + * + * Add an edge that connects the two vertices and in the local clustergraph and assign the GlobalEdge to it. The + * LocalVertex parameters should not represent a cluster which would result in the functions failure. If there's + * already a local edge between the vertices a new global edge will be added and returned. Failure will be + * recocnisable by a false value in the returned type sequence. + * + * @param source The first vertex the edge should connect + * @param target The second vertex the edge should connect + * @return fusion::vector with the local and global descriptors of the edge and an bool + * value indicationg the successful creation. + **/ + fusion::vector addEdge(LocalVertex source, LocalVertex target) { + + //manual edge creation with cluster is not allowed + if((source==target) || isCluster(source) || isCluster(target)) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + + LocalEdge e; + bool done; + boost::tie(e,done) = boost::edge(source, target, *this); + + //if done=true the edge alredy existed + if(!done) boost::tie(e,done) = boost::add_edge(source, target, *this); + if(!done) return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + + //init the bundle corecctly for new edge + GlobalEdge global = { fusion::at_c<0>((*this)[source]), fusion::at_c<0>((*this)[target]), m_id->generate() }; + edge_bundle_single s; + fusion::at_c<1>(s) = global; + fusion::at_c<1>((*this)[e]).push_back(s); + + setChanged(); + return fusion::make_vector(e, global, true); + }; + + /** + * @brief Add a edge between two vertices, defined by global descriptors. + * + * Adds an edge between vertices which are not nesseccarily in this local cluster and have therefore to be + * identified with global descriptors. The only condition for source and target vertex is that both must be + * in the local cluster or any of its subclusters. If thats not the case, the function will fail. On success + * a new GlobalEdge will be created, but not neccessarily a local one. If the vertices are in different cluster + * which are already connected the global edge will be added to this connecting local edge. Thats the one returned + * in the seqence. Note that it's possible that the local edge belongs to another subcluster and therefore can't be + * used in the local cluster. This case is indicated by the scope return value. + * + * @param source The first vertex the edge should connect + * @param target The second vertex the edge should connect + * @return fusion:vector< LocalEdge, GlobalEdge, success, scope > with the new global edge descriptor and the local + * one where it was added. Success indicates if the function was successful and scope shows the validy of the local + * descriptor in this cluster (true means the edge is in this cluster). + **/ + fusion::vector addEdge(GlobalVertex source, GlobalVertex target) { + + LocalVertex v1,v2; + LocalEdge e; + bool d1,d2,d3; + boost::tie(v1,d1) = getContainingVertex(source); + boost::tie(v2,d2) = getContainingVertex(target); + + //if one vertex is not accessible from here this function fails + if(!(d1&&d2)) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + + //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here + if(v1==v2 && isCluster(v1)) { + fusion::vector res = getVertexCluster(v1)->addEdge(source, target); + fusion::at_c<3>(res)=false; + return res; + } + + //check if we already have that Local edge + boost::tie(e,d3) = boost::edge(v1,v2, *this); + if(!d3) boost::tie(e,d3) = boost::add_edge(v1, v2, *this); + if(!d3) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + + //init the bundle corectly for new edge + GlobalEdge global = { source, target, m_id->generate() }; + edge_bundle_single s; + fusion::at_c<1>(s) = global; + fusion::at_c<1>((*this)[e]).push_back(s); + + setChanged(); + return fusion::make_vector(e, global, true, true); + + }; + + fusion::vector addEdgeGlobal(GlobalVertex source, GlobalVertex target) { + return addEdge(source, target); + }; + + /** + * @brief Get an iterator to all the global edges hold by this local edge + * + * Local edges can hold multiple global ones, for example when they connect at least one cluster. Therefore a direct + * LocalEdge - GlobalEdge mapping is not possible. Instead you can access all GlobalEdge's hold by this local one in + * a normal iterating manner. + * + * @param e the local edge for which the global descriptors are wanted + * @return std::pair with the global_edge_iterator's pointing to the vector's start + * and end + **/ + std::pair getGlobalEdges(LocalEdge e) { + + std::vector& vec = fusion::at_c<1>((*this)[e]); + global_edge_iterator begin = boost::make_transform_iterator(vec.begin(), global_extractor()); + global_edge_iterator end = boost::make_transform_iterator(vec.end(), global_extractor()); + + setChanged(); + return std::pair(begin, end); + }; + + /** + * @brief Get the count of all global edges + * + * Local edges can hold multiple global ones, for example when they connect at least one cluster. To get the + * number of all global edges in this local one you can use this function. + * + * @param e the local edge for which the global descriptors are wanted + * @return std::pair with the global_edge_iterator's pointing to the vector's start + * and end + **/ + int getGlobalEdgeCount(LocalEdge e) { + + return fusion::at_c<1>((*this)[e]).size(); + }; + + /** + * @brief Get the local edge which holds the specified global edge. + * + * Note that GlobalEdge must be in a local edge of this cluster, means the connected vertices must be in this + * or one of it's subclusters (but not the same). Also if the containing LocalEdge is not in this cluster, but in one of it's + * subclusters, the function fails and the returned edge is invalid. + * + * @param e GlobalEdge for which the containing local one is wanted + * @return std:pair< LocalEdge, bool > with the containing LocalEdge and a bool indicator if function was successful. + **/ + std::pair getLocalEdge(GlobalEdge e) { + return getContainingEdge(e); + }; + + /** + * @brief Get the local edge which holds the specified global one and the subcluster in which it is valid. + * + * The function only fails when the global edge is hold by a local one upstream in the cluster + * herarchy. + * + * @param e GlobalEdge for which the containing local one is wanted + * @return fusion::vector with the containing LocalEdge, the cluster which holds it and a bool indicator if function was successful. + **/ + fusion::vector getLocalEdgeGraph(GlobalEdge e) { + return getContainingEdgeGraph(e); + }; + + /** + * @brief Get the GlobalVertex assiociated with this local one. + * + * @param v LocalVertex + * @return GlobalVertex + **/ + GlobalVertex getGlobalVertex(LocalVertex v) const { + return fusion::at_c<0>((*this)[v]); + }; + + /** + * @brief Set the GlobalVertex assiociated with this local one. + * + * Be carefull, LocalVertices get an global value assigned while created, override it only when your + * are sure that it is unique + * + * @param lv LocalVertex which sould get assigned the global one + * @param gv The value which the localVertex should get assigned + * @return GlobalVertex which was assigned + **/ + GlobalVertex setGlobalVertex(LocalVertex lv, GlobalVertex gv) { + fusion::at_c<0>((*this)[lv]) = gv; + return gv; + }; + + /** + * @brief Get the LocalVertex which corresponds to the golab one + * + * The GlobalVertex has to be in this cluster or any of it's subclusters. If its in a subcluster, the returned + * LocalVertex will represent this cluster. If the GlobalVertex is not in this clusters scope the function fails. + * + * @param GlobalVertex + * @return std::pair< LocalVertex, bool > The LocalVertex containing the global one and an success indicator + **/ + std::pair getLocalVertex(GlobalVertex e) { + return getContainingVertex(e); + }; + + /** + * @brief Get the local vertex which holds the specified global one and the subcluster in which it is valid. + * + * The function only fails when the global vertex is hold by a local one upstream in the cluster + * herarchy. + * + * @param v GlobalVertex for which the containing local one is wanted + * @return fusion::vector with the containing LocalVertex, the cluster which holds it and a bool indicator if function was successful. + **/ + fusion::vector, bool> getLocalVertexGraph(GlobalVertex v) { + return getContainingVertexGraph(v); + }; + + + /* ******************************************************* + * Remove Handling + * *******************************************************/ +private: + + template + struct apply_remove_prediacte { + Functor& func; + GlobalVertex vert; + GlobalEdge edge; + bool isEdge; + + apply_remove_prediacte(Functor& f, GlobalVertex v) : func(f), vert(v), isEdge(false) {}; + apply_remove_prediacte(Functor& f, GlobalEdge e) : func(f), edge(e), vert(0), isEdge(true) {}; + bool operator()(edge_bundle_single& e) { + bool res; + if(isEdge) + res = (edge==fusion::at_c<1>(e)); + else + res = (vert==fusion::at_c<1>(e).source) || (vert==fusion::at_c<1>(e).target); + + if(res || vert<0) + func(fusion::at_c<1>(e)); + + return res || vert<0; + } + }; + + struct placehoder { + template + void operator()(T t) {}; + }; + + template + void downstreamRemoveVertex(GlobalVertex v, Functor& f) { + + std::pair res = getContainingVertex(v); + if(!res.second) + return; //TODO:throw + + //iterate over every edge that connects to the global vertex or the cluster in which it is in + std::vector re; //remove edges + std::pair it = boost::out_edges(res.first, *this); + for(; it.first != it.second; it.first++) { + std::vector& vec = fusion::at_c<1>((*this)[*(it.first)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte(f,v)), vec.end()); + if(vec.empty()) + re.push_back(*(it.first)); + }; + + std::for_each(re.begin(), re.end(), boost::bind(&ClusterGraph::simpleRemoveEdge, this, _1)); + + //if we have the real vertex here and not only a containing cluster we can delete it + if(!isCluster(res.first)) { + boost::clear_vertex(res.first, *this); //just to make sure, should be done already + boost::remove_vertex(res.first, *this); + }; + + //lets go downstream + for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) + ((*it).second)->downstreamRemoveVertex(v, f); + }; + + void simpleRemoveEdge(LocalEdge e) { + boost::remove_edge(e, *this); + }; + +public: + /** + * @brief Removes a vertex from the local cluster and applys functor to removed edges + * + * Removes the vertex from the local graph and invalidates the global vertex id. Also all edges connecting + * to this vertex will be removed after the functor was applied to them. The functor needs to implement + * operato()(GlobalEdge e). Remark that there is no checking done if the vertex is a cluster, so you + * need to make sure it's not, as removing a clustervertex will not delete the coresponding cluster. + * + * @param id Local Vertex which should be removed from the graph + **/ + template + void removeVertex(LocalVertex id, Functor& f) { + removeVertex(getGlobalVertex(id), f); + }; + //no default template arguments for template functions allowed before c++0x, so a little workaround + void removeVertex(LocalVertex id) { + placehoder p; + removeVertex(getGlobalVertex(id), p); + }; + + /** + * @brief Removes a vertex from the cluster or it's subclusters and applys functor to removed edges + * + * Removes the vertex from the graph or subclusters and invalidates the global vertex id. Also all edges connecting + * to this vertex will be removed (upstream and downstream) after the functor was applied to them. The functor + * needs to implement operato()(LocalEdge edge). + * + * @param id Global Vertex which should be removed from the graph + **/ + template + void removeVertex(GlobalVertex id, Functor& f) { + root()->downstreamRemoveVertex(id, f); + }; + //no default template arguments for template functions allowed before c++0x, so a little workaround + void removeVertex(GlobalVertex id) { + placehoder p; + removeVertex(id, p); + }; + + /** + * @brief Removes a global Edge from the cluster or it's subclusters + * + * Removes the edge from the graph or subclusters and invalidates the global edge id. If the local edge holds + * only this global one it will be removed also. + * + * @param id Global Edge which should be removed from the graph + * @return bool indicates if the global id could be removed + **/ + void removeEdge(GlobalEdge id) { + fusion::vector res = getContainingEdgeGraph(id); + if(!fusion::at_c<2>(res)) + return; //TODO:throw + + placehoder p; + std::vector& vec = fusion::at_c<1>((*fusion::at_c<1>(res))[fusion::at_c<0>(res)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte(p,id)), vec.end()); + + if(vec.empty()) + boost::remove_edge(fusion::at_c<0>(res), *fusion::at_c<1>(res)); + }; + + /** + * @brief Removes a local edge from the cluster and calls the functor for all removed global edges + * + * Removes the edge from the graph and invalidates the global edges. The Functor needs to provide + * operator()(GlobalEdge). If no functor is needed just use boost::remove_edge. + * + * @param id Global Edge which should be removed from the graph + * @return bool indicates if the global id could be removed + **/ + template + void removeEdge(LocalEdge id, Functor& f) { + + std::vector& vec = fusion::at_c<1>((*this)[id]); + std::for_each(vec.begin(), vec.end(), boost::bind(boost::ref(apply_remove_prediacte(f,-1)),_1)); + boost::remove_edge(id, *this); + }; + + + /* ******************************************************* + * Object Handling + * *******************************************************/ + +protected: + //types needed to distinguish when objects need to be reset + struct get : public boost::false_type {}; + struct set : public boost::true_type {}; + + template + struct obj_helper { + + typedef typename object_extractor::result_type result_type; + + obj_helper(key k) : m_key(k) {}; + + //used with vertex bundle type + template + typename boost::enable_if::type>, + result_type >::type operator()(bundle& p) { + + if(Type::value) fusion::for_each(fusion::at_c<2>(p), details::clear_ptr()); + return object_extractor()(p); + } + + //used with edge bundle type and global edge descriptor + template + typename boost::enable_if::type>, + boost::is_same >, result_type>::type operator()(bundle& p) { + + edge_single_iterator e; + //need to search the edge_bundle for the global descriptor + std::vector& ebsv = fusion::at_c<1>(p); + for(edge_single_iterator it= ebsv.begin(); it != ebsv.end(); it++) { + if(global_extractor()(*it) == m_key) { + if(Type::value) fusion::for_each(fusion::at_c<0>(*it), details::clear_ptr()); + e = it; + break; + } + } + return object_extractor()(*e); + } + + //used with edge bundle type and local edge descriptor + template + typename boost::enable_if::type>, + boost::is_same >, result_type>::type operator()(bundle& p) { + if(Type::value) fusion::for_each(fusion::at_c<0>(fusion::at_c<1>(p).front()), details::clear_ptr()); + return object_extractor()(fusion::at_c<1>(p).front()); + } + + key m_key; + }; + + template + struct valid_ptr_apply { + + Functor& func; + valid_ptr_apply(Functor& f) : func(f) {}; + + template + void operator()(Ptr& p) const { + if(p) + func(p); + } + }; + +public: + + /** + * @brief Get the desired object at the specified vertex or edge + * + * This function allows to access the objects stored in the graph. If no object of the desired type + * was set before, a empty shared_ptr will be returned. Accessing the object at a local edge is a special + * case, as it can hold many global edges, each with it's own objetcs. Using a LocalEdge as key will + * always return the object for the first GlobalEdge. + * + * @param local or global Vertex/Edge descriptor for which the object is desired + * @return shared_ptr< Obj > the pointer to the desired object + **/ + template + boost::shared_ptr getObject(key k) { + return apply_to_bundle(k, obj_helper(k)); + }; + + /** + * @brief Set a object at the specified vertex or edge + * + * Sets the given value at the given key. Note that every entity can hold only one object, so setting + * a new value resets all other objects which were set before. Setting the object at a local edge is a special + * case, as it can hold many global edges, each with it's own objects. Using a LocalEdge as key will + * always set the object for the first GlobalEdge. + * + * @param k local or global Vertex/Edge descriptor for which the object should be set + * @param val the object which should be stored + * @return void + **/ + template + void setObject(key k, boost::shared_ptr val) { + apply_to_bundle(k, obj_helper(k)) = val; + + setChanged(); + }; + + /** + * @brief Get iterator range for all GlobalEdge objects hold by this local edge + * + * LocalEdge's can hold multiple global ones and the iterators can be used to access a specific object type in + * all global edges hold by this local edge. + * + * @param k the LocalEdge over which all Objects should be iterated. + * @return pair< begin, end > the iterator rang from begin (first element) to end (first undefined element) + **/ + template + std::pair< object_iterator, object_iterator > getObjects(LocalEdge k) { + + std::vector& vec = fusion::at_c<1>((*this)[k]); + object_iterator begin(vec.begin(), object_extractor()); + object_iterator end(vec.end(), object_extractor()); + return std::pair< object_iterator, object_iterator >(begin, end); + }; + + /** + * @brief Applys the functor to each occurence of an object + * + * Each valid object of the given type is extractet and passed to the function object. Vertices + * and edges are searched for valid object pointers, it happens in this order. When a recursive + * search is specified, all subclusters are searched too, but the cluster is passt to the Functor + * first. So make sure a function overload for clusters exist in this case. + * + * @param f the functor to which all valid objects get passed to. + * @param recursive specifies if the subclusters should be searched for objects too + **/ + template + void for_each(Functor& f, bool recursive = false) { + + std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { + boost::shared_ptr ptr = getObject(*(it.first)) ; + if(ptr) + f(ptr); + } + + std::pair eit = boost::edges(*this); + for(; eit.first != eit.second; eit.first++) { + std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects(*(eit.first)); + for(; goit.first != goit.second; goit.first++) { + if(*goit.first) + f(*goit.first); + } + } + + if(recursive) { + cluster_iterator cit; + for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->for_each(f, recursive); + } + } + }; + + /** + * @brief Applys the functor to each object + * + * Each valid object of any type is extractet and passed to the function object. Vertices + * and edges are searched for valid object pointers, it happens in this order. When a recursive + * search is specified, all subclusters are searched too, but the cluster is passt to the Functor + * first. So make sure a function overload for clusters exist in this case. + * + * @param f the functor to which all valid objects get passed to. + * @param recursive specifies if the subclusters should be searched for objects too + **/ + template + void for_each_object(Functor& f, bool recursive = false) { + + valid_ptr_apply func(f); + + std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { + typename details::sps::type& seq = fusion::at_c<2>((*this)[*it.first]); + fusion::for_each(seq, func); + } + + typedef typename std::vector::iterator iter; + std::pair eit = boost::edges(*this); + for(; eit.first != eit.second; eit.first++) { + std::vector& vec = fusion::at_c<1>((*this)[*eit.first]); + for(iter git = vec.begin(); git != vec.end(); git++) { + typename details::sps::type& seq = fusion::at_c<0>(*git); + fusion::for_each(seq, func); + } + } + + if(recursive) { + cluster_iterator cit; + for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->for_each_object(f, recursive); + } + } + }; + + /* ******************************************************* + * Property Handling + * *******************************************************/ + +protected: + + template + struct get_prop_helper { + + get_prop_helper(key k) : m_key(k) {}; + + typedef typename prop::type base_type; + typedef base_type& result_type; + typedef typename mpl::find::type vertex_iterator; + typedef typename mpl::find::type edge_iterator; + typedef typename mpl::if_::type >, + edge_iterator, vertex_iterator>::type iterator; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + + //used with vertex bundle type + template + typename boost::enable_if::type>, + result_type>::type operator()(bundle& p) { + return property_extractor()(p); + } + + //used with edge bundle type + template + typename boost::enable_if::type>, + result_type>::type operator()(bundle& p) { + return property_extractor()(p); + } + + key m_key; + }; + +public: + /** + * @brief Get the desired property at the specified vertex or edge + * + * This function allows to access the properties stored in the graph. If no property of the desired type + * was set before, a default construced will be returned. Accessing the property at a global edge will return + * the property of the holding local edge. + * + * @param local or global Vertex/Edge descriptor for which the property is desired + * @return property::type& the reference to the desired property + **/ + template + typename property::type& getProperty(key k) { + return apply_to_bundle(k, get_prop_helper(k)); + }; + + /** + * @brief Set a property at the specified vertex or edge + * + * Sets the given value at the given key. Note that every entity can hold one of each property, as opposed + * to objects. Setting the property at a local edge is a special case, as it can hold many global edges, + * each with it's own propertys. Using a LocalEdge as key will always set the property for the first GlobalEdge. + * + * @param k local or global Vertex/Edge descriptor for which the property should be set + * @param val the property value which should be stored + * @return void + **/ + template + void setProperty(key k, typename property::type val) { + apply_to_bundle(k, get_prop_helper(k)) = val; + + setChanged(); + }; + + + /******************************************************** + * Vertex and Cluster moving + * *******************************************************/ + + /** + * @brief Move a vertex to a subcluster + * + * Overloaded convinience function which fetches the local descriptor for the cluster reference and calls + * the full parameter equivalent. Both cluster and vertex must be in the local cluster. + * + * @param v the LocalVertex to be moved + * @param cg reference to the subcluster to which v should be moved + * @return LocalVertex the local descriptor of the moved vertex in the subcluster + **/ + LocalVertex moveToSubcluster(LocalVertex v, boost::shared_ptr cg) { + + LocalVertex cv = getClusterVertex(cg); + return moveToSubcluster(v, cv, cg); + }; + + /** + * @brief Move a vertex to a subcluster + * + * Overloaded convinience function which fetches the the cluster reference for the local descriptor and calls + * the full parameter equivalent. Both cluster and vertex must be in the local cluster. + * + * @param v the LocalVertex to be moved + * @param Cluster the local vertex descriptor representing the subcluster to which v should be moved + * @return LocalVertex the local descriptor of the moved vertex in the subcluster + **/ + LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster) { + + boost::shared_ptr cg = getVertexCluster(Cluster); + return moveToSubcluster(v, Cluster, cg); + }; + + /** + * @brief Move a vertex to a subcluster + * + * This function moves the LocalVertex to the subcluster and reconnects all other vertices and clusters. The + * moved vertex will hold it's global descriptor but get a new local one assigned (the one returned). The same + * stands for all edges which use the moved vertex: global descriptors stay the same, but they are moved to new + * local edges. It's allowed to move cluster vertices with this function. + * The specified cluster has of course to be a valid and direct subcluster, the move vertex also has to be in the + * local cluster. + * + * @param v the LocalVertex to be moved + * @param Cluster the local vertex descriptor representing the subcluster to which v should be moved + * @param cg reference to the subcluster to which v should be moved + * @return LocalVertex the local descriptor of the moved vertex in the subcluster + **/ + LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg) { + + std::pair it = boost::out_edges(v, *this); + + /* add the later removed edges to the coressponding existing edges + * (or create new edges between adjacent vertices of moved vertex and cluster). + * also get the edge between cluster and vertex while iterating */ + for(; it.first!=it.second; it.first++) { + + LocalVertex target = boost::target(*it.first, *this); + if(target != Cluster) { + + //get or create the edge between the old edge target and the cluster + LocalEdge e; + bool done; + boost::tie(e,done) = boost::edge(target, Cluster, *this); + if(!done) boost::tie(e,done) = boost::add_edge(target, Cluster, *this); + //if(!done) TODO: throw + + std::vector& ep = fusion::at_c<1>((*this)[*it.first]); + std::vector& nep = fusion::at_c<1>((*this)[e]); + nep.insert(nep.end(), ep.begin(), ep.end()); + } + } + + /* Create new Vertex in Cluster and map the edge to vertices and clusters in the cluster + * if a connection existed */ + LocalVertex nv= boost::add_vertex((*this)[v], *cg); + //resort cluster parentship if needed + if(isCluster(v)) { + + cg->m_clusters[nv] = m_clusters[v]; + cg->m_clusters[nv]->m_parent = cg; + m_clusters.erase(v); + } + + std::pair moveedge = boost::edge(v, Cluster, *this); + if(moveedge.second) { + std::vector& vec = fusion::at_c<1>((*this)[moveedge.first]); + for(edge_single_iterator i = vec.begin(); i != vec.end(); i++) { + + //get the global vertex to which the global edge points and find the local vertex holding this + //global one + GlobalEdge global = global_extractor()(*i); + GlobalVertex target; + //bit cumbersome to support moving clusters + target = (cg->getContainingVertex(global.source).first == nv) ? global.target : global.source; + std::pair res = cg->getContainingVertex(target); + //if(!res.second) TODO: throw + + //get or create the edge between the new vertex and the target + LocalEdge e; + bool done; + boost::tie(e,done) = boost::edge(nv, res.first, *cg); + if(!done) boost::tie(e,done) = boost::add_edge(nv, res.first, *cg); + //if(!done) TODO: throw + + //push the global edge to the local edge + fusion::at_c<1>((*cg)[e]).push_back(*i); + }; + } + + //all global edges concerning the move vertex are processed and it is moved to the subcluster, + //lets destroy it in the local cluster + boost::clear_vertex(v, *this); + boost::remove_vertex(v, *this); + + setChanged(); + cg->setChanged(); + + return nv; + }; + + + /** + * @brief Move a vertex to the parent cluster. + * + * This function moves a vertex one step up in the subcluster hierarchie and reconnects all other vertices and clusters. + * The moved vertex will hold it's global descriptor but get a new local one assigned (the one returned). The same + * stands for all edges which use the moved vertex: global descriptors stay the same, but they are moved to new + * local edges. Note that this function is the inverse of moveToSubcluster, and doing Pseudocode: + * moveToParent(moveToSubcluster(v)) does nothing (only the local descriptor of the moved vertex is + * diffrent afterwards). + * + * @param v Local vertex which should be moved to the parents cluster + * @return LocalVertex the local descriptor of the moved vertex, valid in the parent cluster only. + **/ + LocalVertex moveToParent(LocalVertex v) { + + //if(isRoot()) TODO:throw + + //create new vertex + vertex_bundle& vb = (*this)[v]; + LocalVertex nv = boost::add_vertex(vb, *parent()); + //regrouping if needed + if(isCluster(v)) { + m_parent->m_clusters[nv] = m_clusters[v]; + m_parent->m_clusters[nv]->m_parent = m_parent; + m_clusters.erase(v); + } + + GlobalVertex gv= fusion::at_c<0>(vb); + + //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) + std::vector edge_vec; + LocalVertex this_v = m_parent->getClusterVertex(sp_base::shared_from_this()); + std::pair it = boost::out_edges(this_v, *parent()); + for(; it.first != it.second; it.first++) { + //iterate all global edges and find relevant ones + std::vector& vec = fusion::at_c<1>((*parent())[*it.first]); + edge_single_iterator i = vec.begin(); + while(i != vec.end()) { + + GlobalEdge global = global_extractor()(*i); + GlobalVertex target; + //a bit cumbersome to allow cluster moving + if(m_parent->getContainingVertex(global.source).first == nv) target = global.target; + else if(m_parent->getContainingVertex(global.target).first == nv) target = global.source; + else { + i++; + continue; + } + + std::pair res = m_parent->getContainingVertex(target); + + //get or create the edge between the new vertex and the target + LocalEdge e; + bool done; + boost::tie(e,done) = boost::edge(nv, res.first, *parent()); + if(!done) boost::tie(e,done) = boost::add_edge(nv, res.first, *parent()); + //if(!done) TODO: throw + + //push the global edge bundle to the new local edge and erase it in the old + fusion::at_c<1>((*parent())[e]).push_back(*i); + i = vec.erase(i); + } + //see if we should destroy this edge (no global edges remain in local one) + if(vec.empty()) edge_vec.push_back(*it.first); + } + + //create a edge between new vertex and this cluster and add all global edges from within this cluster + it = boost::out_edges(v, *this); + LocalEdge e; + if(it.first != it.second) e = boost::add_edge(nv, this_v, *parent()).first; + for(; it.first != it.second; it.first++) { + std::vector& ep = fusion::at_c<1>((*this)[*it.first]); + std::vector& nep = fusion::at_c<1>((*parent())[e]); + nep.insert(nep.end(), ep.begin(), ep.end()); + } + + //all global edges concerning the move vertex are processed and it is moved to the parent, + //lets destroy it in the local cluster + boost::clear_vertex(v, *this); + boost::remove_vertex(v, *this); + + //it's possible that some local edges in the parent are empty now, let's destroy them + for(std::vector::iterator it=edge_vec.begin(); it!=edge_vec.end(); it++) + boost::remove_edge(*it, *parent()); + + setChanged(); + parent()->setChanged(); + return nv; + }; + + + /******************************************************** + * Stuff + * *******************************************************/ + + ClusterMap m_clusters; + int test; +protected: + boost::shared_ptr m_parent; + details::IDpointer m_id; + + + /* Searches the global vertex in all local vertices of this graph, and returns the local + * one which holds the global vertex. If not successfull the local vertex returned will be + * invalid and the bool parameter will be false. If recursive = true, all subclusters will + * be seached too, however, if found there the retourned local vertex will be the vertex + * representing the toplevel cluster holding the global vertex in the initial graph. + * */ + std::pair getContainingVertex(GlobalVertex id, bool recursive = true) { + + //check all vertices if they are the id + std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { + if(id == fusion::at_c<0>((*this)[*it.first])) + return std::make_pair(*it.first, true); + } + + //check all clusters if they have the id + if(recursive) { + for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { + std::pair res = ((*it).second)->getContainingVertex(id); + if(res.second) return std::make_pair((*it).first, true); + } + } + + return std::make_pair((LocalVertex)NULL, false); + }; + + /* Searches the local vertex holding the specified global one in this and all it's subclusters. + * If found, the holding local vertex and the graph in which it is valid will be returned. + * */ + fusion::vector, bool> getContainingVertexGraph(GlobalVertex id) { + + LocalVertex v; + bool done; + boost::tie(v, done) = getContainingVertex(id); + if(!done) return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); + + if(isCluster(v) && (getGlobalVertex(v) != id)) + return m_clusters[v]->getContainingVertexGraph(id); + else return fusion::make_vector(v,sp_base::shared_from_this(),true); + }; + + /* Searches the global edge in all local edges of this graph, and returns the local + * one which holds the global edge. If not successfull the local edge returned will be + * invalid and the bool parameter will be false. + * */ + std::pair getContainingEdge(GlobalEdge id) { + + LocalVertex v1,v2; + bool d1,d2; + boost::tie(v1,d1) = getContainingVertex(id.source, true); + boost::tie(v2,d2) = getContainingVertex(id.target, true); + + if(!((d1&&d2) && (v1!=v2))) return std::make_pair(LocalEdge(), false); + + return boost::edge(v1,v2,*this); + }; + + /* Searches the local edge holding the specified global one in this and all it's subclusters. + * If found, the holding local edge and the graph in which it is valid will be returned. + * */ + fusion::vector getContainingEdgeGraph(GlobalEdge id) { + + LocalVertex v1,v2; + bool d1,d2; + boost::tie(v1,d1) = getContainingVertex(id.source, true); + boost::tie(v2,d2) = getContainingVertex(id.target, true); + + if(!(d1&&d2)) return fusion::make_vector(LocalEdge(), (ClusterGraph*)NULL, false); + if(v1==v2) return m_clusters[v1]->getContainingEdgeGraph(id); + + return fusion::make_vector(boost::edge(v1,v2,*this).first, this, true); + }; + + template + typename functor::result_type apply_to_bundle(LocalVertex k, functor f) { + return f((*this)[k]); + }; + + template + typename functor::result_type apply_to_bundle(LocalEdge k, functor f) { + return f((*this)[k]); + }; + + template + typename functor::result_type apply_to_bundle(GlobalVertex k, functor f) { + + //check all vertices if they are the id + std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { + vertex_bundle& p = (*this)[*it.first]; + if(k == fusion::at_c<0>(p)) + return f(p); + } + + //check all clusters if they have the object + fusion::vector, bool> res = getContainingVertexGraph(k); + if(!fusion::at_c<2>(res)) { + //TODO: Throw (propeties return reference, but cant init a reference temporarily) + } + + return fusion::at_c<1>(res)->apply_to_bundle(k, f); + }; + + template + typename functor::result_type apply_to_bundle(GlobalEdge k, functor f) { + + LocalVertex v1,v2; + bool d1,d2; + boost::tie(v1,d1) = getContainingVertex(k.source); + boost::tie(v2,d2) = getContainingVertex(k.target); + + if(!(d1&&d2)) { + //TODO:Throw + } + + if((v1==v2) && isCluster(v1)) return m_clusters[v1]->apply_to_bundle(k, f); + else { + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(v1,v2,*this); + //if(!done) TODO: throw, as there has to be a edge! + return f((*this)[e]); + }; + + + }; +}; + +} //namespace solver + +#endif // CLUSTERGRAPH_HPP + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp new file mode 100644 index 000000000000..c2f74117fda3 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -0,0 +1,512 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_CONSTRAINT_H +#define GCM_CONSTRAINT_H + + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include + +#include "traits.hpp" +#include "object.hpp" +#include "equations.hpp" + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace detail { + +//type erasure container for constraints +template +class Constraint : public Object { + + typedef typename system_traits::Kernel Kernel; + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::DynStride DS; + + typedef boost::shared_ptr geom_ptr; + typedef std::vector > Vec; + +public: + Constraint(Sys& system, geom_ptr f, geom_ptr s); + ~Constraint(); + + virtual boost::shared_ptr clone(Sys& newSys); + +protected: + + template + void initialize(typename fusion::result_of::as_vector::type& obj); + + int equationCount(); + + template< typename creator_type> + void resetType(creator_type& c); + + void calculate(Scalar scale); + + void setMaps(MES& mes); + + void geometryReset(geom_ptr g) { + /* placeholder* p = content->resetConstraint(first, second); + delete content; + content = p;*/ + }; + + void collectPseudoPoints(Vec& vec1, Vec& vec2); + + //Equation is the constraint with types, the EquationSet hold all needed Maps for calculation + template + struct EquationSet { + EquationSet() : m_diff_first(NULL,0,DS(0,0)), m_diff_second(NULL,0,DS(0,0)), + m_residual(NULL,0,DS(0,0)) {}; + + Equation m_eq; + typename Kernel::VectorMap m_diff_first; //first geometry diff + typename Kernel::VectorMap m_diff_second; //second geometry diff + typename Kernel::VectorMap m_residual; + + typedef Equation eq_type; + }; + + struct placeholder { + virtual ~placeholder() {} + virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const = 0; + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale) = 0; + virtual int equationCount() = 0; + virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; + virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; + virtual placeholder* clone() = 0; + }; + +public: + template< typename ConstraintVector, typename EquationVector> + struct holder : public placeholder { + + //create a vector of EquationSets with some mpl trickery + typedef typename mpl::fold< EquationVector, mpl::vector<>, + mpl::push_back > >::type eq_set_vector; + typedef typename fusion::result_of::as_vector::type EquationSets; + + typedef typename fusion::result_of::as_vector::type Objects; + + template + struct has_option { + //we get the index of the eqaution in the eqaution vector, and as it is the same + //as the index of the constraint in the constraint vector we can extract the + //option type and check if it is no_option + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + typedef typename mpl::at::type option_type; + typedef mpl::not_ > type; + }; + + struct OptionSetter { + + Objects& objects; + + OptionSetter(Objects& val); + + //only set the value if the equation has a option + template< typename T > + typename boost::enable_if::type, void>::type + operator()(EquationSet& val) const; + //if the equation has no otpion we do nothing! + template< typename T > + typename boost::enable_if::type>, void>::type + operator()(EquationSet& val) const; + }; + + struct Calculater { + + geom_ptr first, second; + Scalar scale; + + Calculater(geom_ptr f, geom_ptr s, Scalar sc); + + template< typename T > + void operator()(T& val) const; + }; + + struct MapSetter { + MES& mes; + geom_ptr first, second; + + MapSetter(MES& m, geom_ptr f, geom_ptr s); + + template< typename T > + void operator()(T& val) const; + }; + + struct PseudoCollector { + Vec& points1; + Vec& points2; + geom_ptr first,second; + + PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); + + template< typename T > + void operator()(T& val) const; + }; + + holder(Objects& obj); + + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale); + virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const; + virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); + virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); + virtual placeholder* clone(); + virtual int equationCount() { + return mpl::size::value; + }; + + EquationSets m_sets; + }; + +protected: + template< typename ConstraintVector > + struct creator : public boost::static_visitor { + + typedef typename fusion::result_of::as_vector::type Objects; + Objects& objects; + + creator(Objects& obj); + + template + struct equation { + typedef typename C::template type type; + }; + + template + void operator()(const T1&, const T2&); + + placeholder* p; + bool need_swap; + }; + + placeholder* content; + geom_ptr first, second; + Connection cf, cs; +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template +Constraint::Constraint(Sys& system, geom_ptr f, geom_ptr s) + : first(f), second(s), content(0) { + + this->m_system = &system; + cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); + cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); +}; + +template +Constraint::~Constraint() { + delete content; + first->template disconnectSignal(cf); + second->template disconnectSignal(cs); +}; + +template +boost::shared_ptr Constraint::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //copy the internals + np->content = content->clone(); + //and get the geometry pointers right + if(first) { + GlobalVertex v = first->template getProperty(); + np->first = newSys.m_cluster->template getObject(v); + } + if(second) { + GlobalVertex v = second->template getProperty(); + np->second = newSys.m_cluster->template getObject(v); + } + return np; +}; + +template +template +void Constraint::initialize(typename fusion::result_of::as_vector::type& obj) { + + //first create the new placeholder + creator c(obj); + boost::apply_visitor(c, first->m_geometry, second->m_geometry); + + //and now store it + content = c.p; + //geometry order needs to be the one needed by equations + if(c.need_swap) first.swap(second); + +}; + +template +int Constraint::equationCount() { + return content->equationCount(); +}; + +template +template< typename creator_type> +void Constraint::resetType(creator_type& c) { + boost::apply_visitor(c, first->m_geometry, second->m_geometry); + content = c.p; + if(c.need_swap) first.swap(second); +}; + +template +void Constraint::calculate(Scalar scale) { + content->calculate(first, second, scale); +}; + +template +void Constraint::setMaps(MES& mes) { + content->setMaps(mes, first, second); +}; + +template +void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { + content->collectPseudoPoints(first, second, vec1, vec2); +}; + +template +template +Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; + +template +template +template +typename boost::enable_if::template holder::template has_option::type, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { + + //get the index of the corresbonding equation + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + val.m_eq.value = fusion::at(objects).value; +}; + +template +template +template +typename boost::enable_if::template holder::template has_option::type>, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { + +}; + +template +template +Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc) : first(f), second(s), scale(sc) { + +}; + +template +template +template< typename T > +void Constraint::holder::Calculater::operator()(T& val) const { + + val.m_eq.setScale(scale); + + val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); + + //now see which way we should calculate the gradient (may be diffrent for both geometries) + if(first->m_parameterCount) { + if(first->getClusterMode()) { + //when the cluster is fixed no maps are set as no parameters exist. + if(!first->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<6; i++) { + typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); + val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + } + } + } else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); + } + } + if(second->m_parameterCount) { + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<6; i++) { + typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); + val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, block); + } + } + } else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); + } + } +}; + +template +template +Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) + : mes(m), first(f), second(s) { + +}; + +template +template +template< typename T > +void Constraint::holder::MapSetter::operator()(T& val) const { + + //when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat + //for every parameter in the geometry; + int equation = mes.setResidualMap(val.m_residual); + if(first->getClusterMode()) { + if(!first->isClusterFixed()) { + mes.setJacobiMap(equation, first->m_offset, 6, val.m_diff_first); + } + } else mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); + + + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + mes.setJacobiMap(equation, second->m_offset, 6, val.m_diff_second); + } + } else mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); +}; + +template +template +Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) + : first(f), second(s), points1(vec1), points2(vec2) { + +}; + +template +template +template< typename T > +void Constraint::holder::PseudoCollector::operator()(T& val) const { + if(first->m_isInCluster && second->m_isInCluster) { + val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); + } else if(first->m_isInCluster) { + typename Kernel::Vector sec = second->m_parameter; + val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); + } else if(second->m_isInCluster) { + typename Kernel::Vector fir = first->m_parameter; + val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); + } +}; + +template +template +Constraint::holder::holder(Objects& obj) { + //set the initial values in the equations + fusion::for_each(m_sets, OptionSetter(obj)); +}; + +template +template +void Constraint::holder::calculate(geom_ptr first, geom_ptr second, Scalar scale) { + fusion::for_each(m_sets, Calculater(first, second, scale)); +}; + +template +template +typename Constraint::placeholder* +Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { + //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); + //if(creator.need_swap) first.swap(second); + return NULL; +}; + +template +template +void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { + fusion::for_each(m_sets, MapSetter(mes, first, second)); +}; + +template +template +void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { + fusion::for_each(m_sets, PseudoCollector(f, s, vec1, vec2)); +}; + +template +template +typename Constraint::placeholder* +Constraint::holder::clone() { + return new holder(*this); +}; + +template +template< typename ConstraintVector > +Constraint::creator::creator(Objects& obj) : objects(obj) { + +}; + +template +template< typename ConstraintVector > +template +void Constraint::creator::operator()(const T1&, const T2&) { + typedef tag_order< typename geometry_traits::tag, typename geometry_traits::tag > order; + + //transform the constraints into eqautions with the now known types + typedef typename mpl::fold< ConstraintVector, mpl::vector<>, + mpl::push_back > >::type EquationVector; + + //and build the placeholder + p = new holder(objects); + need_swap = order::swapt::value; +}; + + +};//detail + +};//dcm + +#endif //GCM_CONSTRAINT_H + diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp new file mode 100644 index 000000000000..0e391f48e811 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -0,0 +1,189 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_EQUATIONS_H +#define GCM_EQUATIONS_H + +#include + +namespace dcm { + +struct no_option {}; + +template +struct Pseudo { + typedef std::vector > Vec; + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; +}; + +template +struct Scale { + void setScale(typename Kernel::number_type scale) {}; +}; + +template +struct PseudoScale { + typedef std::vector > Vec; + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; + void setScale(typename Kernel::number_type scale) {}; +}; + +struct Distance { + + typedef double option_type; + option_type value; + + Distance() : value(0) {}; + + Distance& operator=(const option_type val) { + value = val; + return *this; + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + Scalar value; + //template definition + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) { + assert(false); + }; + void setScale(Scalar scale) { + assert(false); + }; + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +//the possible directions +enum Direction { Same, Opposite, Both }; + +struct Parallel { + + typedef Direction option_type; + option_type value; + + Parallel() : value(Both) {}; + + Parallel& operator=(const option_type val) { + value = val; + return *this; + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +struct Angle { + + typedef double option_type; + option_type value; + + Angle() : value(0) {}; + + Angle& operator=(const option_type val) { + value = val; + return *this; + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +//static is needed to restrain the scope of the objects to the current compilation unit. Without it +//every compiled file including this header would define these as global and the linker would find +//multiple definitions of the same objects +static Distance distance; +static Parallel parallel; +static Angle angle; + +}; + +#endif //GCM_EQUATIONS_H + diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp new file mode 100644 index 000000000000..045e68589380 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -0,0 +1,481 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef GCM_GEOMETRY_H +#define GCM_GEOMETRY_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "object.hpp" +#include "traits.hpp" +#include "logging.hpp" +#include "transformation.hpp" + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace tag { + +struct undefined { + typedef mpl::int_<0> parameters; + typedef mpl::int_<0> transformations; +}; + +//we need to order tags, this values make it easy for module tags +namespace weight { +struct direction : mpl::int_<0> {}; +struct point : mpl::int_<1> {}; +struct line : mpl::int_<2> {}; +struct plane : mpl::int_<3> {}; +struct cylinder : mpl::int_<4> {}; +} +} + +struct orderd_bracket_accessor { + + template + Scalar get(T& t) { + return t[ID]; + }; + template + void set(Scalar value, T& t) { + t[ID] = value; + }; +}; + +struct orderd_roundbracket_accessor { + + template + Scalar get(T& t) { + return t(ID); + }; + template + void set(Scalar value, T& t) { + t(ID) = value; + }; +}; + +//tag ordering (smaller weight is first tag) +template +struct tag_order { + + BOOST_MPL_ASSERT((mpl::not_< mpl::or_< + boost::is_same< typename T1::weight, mpl::int_<0> >, + boost::is_same< typename T2::weight, mpl::int_<0> > > >)); + + typedef typename mpl::less::type swapt; + typedef typename mpl::if_::type first_tag; + typedef typename mpl::if_::type second_tag; +}; + + +//template +//struct type_order : public tag_order< typename geometry_traits::tag, typename geometry_traits::tag > {}; + + +template< typename T> +struct geometry_traits { + BOOST_MPL_ASSERT_MSG(false, NO_GEOMETRY_TRAITS_SPECIFIED_FOR_TYPE, (T)); +}; + +template< typename T> +struct geometry_clone_traits { + T operator()(T& val) { + return T(val); + }; +}; + +struct reset {}; //signal namespace + +namespace detail { + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +class Geometry : public Object) > >, + mpl::pair) > > , + mpl::pair)> > > > { + + typedef mpl::map3< mpl::pair) > >, + mpl::pair) > >, + mpl::pair)> > > Signals; + + typedef typename boost::make_variant_over< GeometrieTypeList >::type Variant; + typedef Object Base; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::DynStride DS; + typedef typename Kernel::template transform_type::type Transform; + typedef typename Kernel::template transform_type::diff_type DiffTransform; + + struct cloner : boost::static_visitor { + typedef typename boost::make_variant_over< GeometrieTypeList >::type Variant; + + Variant variant; + cloner(Variant& v) : variant(v) {}; + + template + void operator()(T& t) { + variant = geometry_clone_traits()(t); + }; + }; + +#ifdef USE_LOGGING +protected: + src::logger log; +#endif + +public: + typedef mpl::int_ Dimension; + + template + Geometry(T geometry, Sys& system); + + template + void set(T geometry); + + template + typename Visitor::result_type apply(Visitor& vis) { + return boost::apply_visitor(vis, m_geometry); + }; + + //basic ation + void transform(const Transform& t); + + virtual boost::shared_ptr clone(Sys& newSys); + + //allow accessing the internal values in unittests without making them public, + //so that access control of the internal classes is not changed and can be tested +#ifdef TESTING + typename Kernel::Vector& toplocal() { + return m_toplocal; + }; + typename Kernel::Vector& rotated() { + return m_rotated; + }; + int& offset() { + return m_offset; + }; + void clusterMode(bool iscluster, bool isFixed) { + setClusterMode(iscluster, isFixed); + }; + void trans(const Transform& t) { + transform(t); + }; + void recalc(DiffTransform& trans) { + recalculate(trans); + }; + typename Kernel::Vector3 point() { + return getPoint(); + }; + int parameterCount() { + return m_parameterCount; + }; +#endif + +//protected would be the right way, however, visual studio 10 does not find a way to access them even when constraint::holder structs +//are declared friend +//protected: + Variant m_geometry; //Variant holding the real geometry type + int m_BaseParameterCount; //count of the parameters the variant geometry type needs + int m_parameterCount; //count of the used parameters (when in cluster:6, else m_BaseParameterCount) + int m_offset; //the starting point of our parameters in the math system parameter vector + int m_rotations; //count of rotations to be done when original vector gets rotated + int m_translations; //count of translations to be done when original vector gets rotated + bool m_isInCluster, m_clusterFixed, m_init; + typename Kernel::Vector m_toplocal; //the local value in the toplevel cluster used for cuttent solving + typename Kernel::Vector m_global; //the global value outside of all clusters + typename Kernel::Vector m_rotated; //the global value as the rotation of toplocal (used as temp) + typename Kernel::Matrix m_diffparam; //gradient vectors combined as matrix when in cluster + typename Kernel::VectorMap m_parameter; //map to the parameters in the solver + + template + void init(T& t); + + void normalize(); + + typename Sys::Kernel::VectorMap& getParameterMap(); + void initMap(); + + void setClusterMode(bool iscluster, bool isFixed); + bool getClusterMode() { + return m_isInCluster; + }; + bool isClusterFixed() { + return m_clusterFixed; + }; + + void recalculate(DiffTransform& trans); + + typename Kernel::Vector3 getPoint() { + return m_toplocal.template segment(0); + }; + + //visitor to write the calculated value into the variant + struct apply_visitor : public boost::static_visitor { + + apply_visitor(typename Kernel::Vector& v) : value(v) {}; + template + void operator()(T& t) const { + (typename geometry_traits::modell()).template inject::accessor >(t, value); + } + typename Kernel::Vector& value; + }; + + //use m_value or parametermap as new value, dependend on the solving mode + void finishCalculation(); + + template + void transform(const Transform& t, VectorType& vec); + void scale(Scalar value); +}; + + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +Geometry::Geometry(T geometry, Sys& system) + : m_isInCluster(false), m_geometry(geometry), m_parameter(NULL,0,DS(0,0)), + m_clusterFixed(false), m_init(false) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif + + this->m_system = &system; + init(geometry); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +void Geometry::set(T geometry) { + m_geometry = geometry; + init(geometry); + //Base::template emitSignal( ((Derived*)this)->shared_from_this() ); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +void Geometry::transform(const Transform& t) { + + if(m_isInCluster) + transform(t, m_toplocal); + else if(m_init) + transform(t, m_rotated); + else + transform(t, m_global); +}; + +template +boost::shared_ptr Geometry::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //it's possible that the variant contains pointers, so we need to clone them + cloner clone_fnc(np->m_geometry); + boost::apply_visitor(clone_fnc, m_geometry); + return np; +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +void Geometry::init(T& t) { + + m_BaseParameterCount = geometry_traits::tag::parameters::value; + m_parameterCount = m_BaseParameterCount; + m_rotations = geometry_traits::tag::rotations::value; + m_translations = geometry_traits::tag::translations::value; + + m_toplocal.setZero(m_parameterCount); + m_global.resize(m_parameterCount); + m_rotated.resize(m_parameterCount); + m_rotated.setZero(); + + m_diffparam.resize(m_parameterCount,6); + m_diffparam.setZero(); + + (typename geometry_traits::modell()).template extract::accessor >(t, m_global); + normalize(); + + //new value which is not set into parameter, so init is false + m_init = false; + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init: "< +void Geometry::normalize() { + //directions are not nessessarily normalized, but we need to ensure this in cluster mode + for(int i=m_translations; i!=m_rotations; i++) + m_global.template segment(i*Dim).normalize(); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +typename Sys::Kernel::VectorMap& Geometry::getParameterMap() { + m_isInCluster = false; + m_parameterCount = m_BaseParameterCount; + return m_parameter; +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +void Geometry::initMap() { + //when direct parameter solving the global value is wanted (as it's the initial rotation*toplocal) + m_parameter = m_global; + m_init = true; +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +void Geometry::setClusterMode(bool iscluster, bool isFixed) { + + m_isInCluster = iscluster; + m_clusterFixed = isFixed; + if(iscluster) { + //we are in cluster, therfore the parameter map should not point to a solver value but to + //the rotated original value; + new(&m_parameter) typename Sys::Kernel::VectorMap(&m_rotated(0), m_parameterCount, DS(1,1)); + //the local value is the global one as no transformation was applied yet + m_toplocal = m_global; + m_rotated = m_global; + } else new(&m_parameter) typename Sys::Kernel::VectorMap(&m_global(0), m_parameterCount, DS(1,1)); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +void Geometry::recalculate(DiffTransform& trans) { + if(!m_isInCluster) return; + + for(int i=0; i!=m_rotations; i++) { + //first rotate the original to the transformed value + m_rotated.block(i*Dim,0,Dim,1) = trans.rotation()*m_toplocal.template segment(i*Dim); + + //now calculate the gradient vectors and add them to diffparam + for(int j=0; j(i*Dim); + } + //after rotating the needed parameters we translate the stuff that needs to be moved + for(int i=0; i!=m_translations; i++) { + m_rotated.block(i*Dim,0,Dim,1) += trans.translation().vector(); + m_rotated.block(i*Dim,0,Dim,1) *= trans.scaling().factor(); + //calculate the gradient vectors and add them to diffparam + m_diffparam.block(i*Dim,Dim,Dim,Dim).setIdentity(); + } + +#ifdef USE_LOGGING + if(!boost::math::isnormal(m_rotated.norm()) || !boost::math::isnormal(m_diffparam.norm())) { + BOOST_LOG(log) << "Unnormal recalculated value detected: "< +void Geometry::finishCalculation() { + //if fixed nothing needs to be changed + if(m_isInCluster) { + //recalculate(1.); //remove scaling to get right global value + m_global = m_rotated; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish cluster calculation"; +#endif + } + //TODO:non cluster paramter scaling + else { + m_global = m_parameter; + normalize(); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish calculation"; +#endif + }; + apply_visitor v(m_global); + apply(v); + m_init = false; + m_isInCluster = false; + + //emit the signal for recalculation + Base::template emitSignal( ((Derived*)this)->shared_from_this() ); +}; + +template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template +void Geometry::transform(const Transform& t, VectorType& vec) { + + //everything that needs to be translated needs to be fully transformed + for(int i=0; i!=m_translations; i++) { + typename Kernel::Vector3 v = vec.template segment(i*Dim); + vec.template segment(i*Dim) = t*v; + } + + for(int i=m_translations; i!=m_rotations; i++) { + typename Kernel::Vector3 v = vec.template segment(i*Dim); + vec.template segment(i*Dim) = t.rotate(v); + } + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Transformed with cluster: "< +void Geometry::scale(Scalar value) { + + for(int i=0; i!=m_translations; i++) + m_parameter.template segment(i*Dim) *= 1./value; + +}; + +} +} + +#endif // GCM_GEOMETRY_H diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp new file mode 100644 index 000000000000..949e3b654929 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -0,0 +1,425 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_KERNEL_H +#define GCM_KERNEL_H + +#include +#include +#include + +#include + +#include +#include + +#include "transformation.hpp" +#include "logging.hpp" + + +namespace dcm { + +namespace E = Eigen; + +struct nothing { + void operator()() {}; +}; + +template +struct Dogleg { + +#ifdef USE_LOGGING + src::logger log; +#endif + + typedef typename Kernel::number_type number_type; + number_type tolg, tolx, tolf; + + Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-5) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); +#endif + }; + + template + int calculateStep(const Eigen::MatrixBase& g, const Eigen::MatrixBase& jacobi, + const Eigen::MatrixBase& residual, Eigen::MatrixBase& h_dl, + const double delta) { + + // get the steepest descent stepsize and direction + const double alpha(g.squaredNorm()/(jacobi*g).squaredNorm()); + const typename Kernel::Vector h_sd = -g; + + // get the gauss-newton step + const typename Kernel::Vector h_gn = (jacobi).fullPivLu().solve(-residual); +#ifdef USE_LOGGING + if(!boost::math::isfinite(h_gn.norm())) { + BOOST_LOG(log)<< "Unnormal gauss-newton detected: "<= delta) { + //h_dl = alpha*h_sd; + h_dl = (delta/(h_sd.norm()))*h_sd; +#ifdef USE_LOGGING + if(!boost::math::isfinite(h_dl.norm())) { + BOOST_LOG(log)<< "Unnormal dogleg descent detected: "< + int solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale) { + + clock_t start = clock(); + clock_t inc_rec = clock(); + + if(!sys.isValid()) return 5; + + bool translate = true; + + typename Kernel::Vector h_dl, F_old(sys.m_eqns), g(sys.m_eqns); + typename Kernel::Matrix J_old(sys.m_eqns, sys.m_params); + + sys.recalculate(); + +#ifdef USE_LOGGING + BOOST_LOG(log)<< "initial jacobi: "<(); +#endif + + number_type err = sys.Residual.norm(); + + F_old = sys.Residual; + J_old = sys.Jacobi; + + g = sys.Jacobi.transpose()*(sys.Residual); + + // get the infinity norm fx_inf and g_inf + number_type g_inf = g.template lpNorm(); + number_type fx_inf = sys.Residual.template lpNorm(); + + int maxIterNumber = 10000;//MaxIterations * xsize; + number_type diverging_lim = 1e6*err + 1e12; + + number_type delta=5; + number_type nu=2.; + int iter=0, stop=0, reduce=0, unused=0, counter=0; + + + while(!stop) { + + // check if finished + if(fx_inf <= tolf*sys.Scaling) // Success + stop = 1; + else if(g_inf <= tolg) + stop = 2; + else if(delta <= tolx) + stop = 3; + else if(iter >= maxIterNumber) + stop = 4; + else if(!boost::math::isfinite(err)) + stop = 5; + else if(err > diverging_lim) + stop = 6; + + + // see if we are already finished + if(stop) + break; + + number_type err_new; + number_type dF=0, dL=0; + number_type rho; + + //get the update step + calculateStep(g, sys.Jacobi, sys.Residual, h_dl, delta); + + // calculate the linear model + dL = 0.5*sys.Residual.norm() - 0.5*(sys.Residual + sys.Jacobi*h_dl).norm(); + + // get the new values + sys.Parameter += h_dl; + + clock_t start_rec = clock(); + sys.recalculate(); + clock_t end_rec = clock(); + inc_rec += end_rec-start_rec; + +#ifdef USE_LOGGING + if(!boost::math::isfinite(sys.Residual.norm())) { + BOOST_LOG(log)<< "Unnormal residual detected: "<0.85) { + delta = std::max(delta,2*h_dl.norm()); + nu = 2; + } else if(rho < 0.25) { + delta = delta/nu; + nu = 2*nu; + } + + if(dF > 0 && dL > 0) { + + //see if we got too high differentials + if(sys.Jacobi.template lpNorm() > 2) { +#ifdef USE_LOGGING + BOOST_LOG(log)<< "High differential detected: "<()<<" in iteration: "<1 && (counter>50)) { + rescale(); + sys.recalculate(); + counter = 0; + } + + F_old = sys.Residual; + J_old = sys.Jacobi; + + err = sys.Residual.norm(); + g = sys.Jacobi.transpose()*(sys.Residual); + + // get infinity norms + g_inf = g.template lpNorm(); + fx_inf = sys.Residual.template lpNorm(); + + } else { + sys.Residual = F_old; + sys.Jacobi = J_old; + sys.Parameter -= h_dl; + unused++; +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Reject step in iter "< class Nonlinear = Dogleg> +struct Kernel { + + //basics + typedef Scalar number_type; + + //linear algebra types 2D + typedef E::Matrix Vector2; + + //Linear algebra types 3D + typedef E::Matrix Vector3; + typedef E::Matrix CVector3; + typedef E::Matrix Matrix3; + typedef E::Matrix Vector; + typedef E::Matrix CVector; + typedef E::Matrix Matrix; + + //mapped types + typedef E::Stride DynStride; + typedef E::Map< Vector3 > Vector3Map; + typedef E::Map< CVector3> CVector3Map; + typedef E::Map< Matrix3 > Matrix3Map; + typedef E::Map< Vector, 0, DynStride > VectorMap; + typedef E::Map< CVector, 0, DynStride > CVectorMap; + typedef E::Map< Matrix, 0, DynStride > MatrixMap; + + //Special types + typedef E::Quaternion Quaternion; + typedef E::Matrix Matrix39; + typedef E::Map< Matrix39 > Matrix39Map; + typedef E::Block MatrixBlock; + + typedef detail::Transform Transform3D; + typedef detail::DiffTransform DiffTransform3D; + + typedef detail::Transform Transform2D; + typedef detail::DiffTransform DiffTransform2D; + + typedef Nonlinear< Kernel > NonlinearSolver; + + template + struct transform_type { + typedef typename boost::mpl::if_c::type type; + typedef typename boost::mpl::if_c::type diff_type; + }; + + template + struct vector_type { + typedef E::Matrix type; + }; + + + struct MappedEquationSystem { + + Matrix Jacobi; + Vector Parameter; + Vector Residual; + number_type Scaling; + int m_params, m_eqns; //total amount + int m_param_offset, m_eqn_offset; //current positions while creation + + MappedEquationSystem(int params, int equations) + : Jacobi(equations, params), + Parameter(params), Residual(equations), + m_params(params), m_eqns(equations), Scaling(1.) { + + m_param_offset = 0; + m_eqn_offset = 0; + + Jacobi.setZero(); //important as some places are never written + }; + + int setParameterMap(int number, VectorMap& map) { + + new(&map) VectorMap(&Parameter(m_param_offset), number, DynStride(1,1)); + m_param_offset += number; + return m_param_offset-number; + }; + int setParameterMap(Vector3Map& map) { + + new(&map) Vector3Map(&Parameter(m_param_offset)); + m_param_offset += 3; + return m_param_offset-3; + }; + int setResidualMap(VectorMap& map) { + new(&map) VectorMap(&Residual(m_eqn_offset), 1, DynStride(1,1)); + return m_eqn_offset++; + }; + void setJacobiMap(int eqn, int offset, int number, CVectorMap& map) { + new(&map) CVectorMap(&Jacobi(eqn, offset), number, DynStride(0,m_eqns)); + }; + void setJacobiMap(int eqn, int offset, int number, VectorMap& map) { + new(&map) VectorMap(&Jacobi(eqn, offset), number, DynStride(0,m_eqns)); + }; + + bool isValid() { + if(!m_params || !m_eqns) return false; + return true; + }; + + virtual void recalculate() = 0; + + }; + + Kernel() {}; + + template + static bool isSame(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1-p2).squaredNorm() < 0.00001); + } + static bool isSame(number_type t1, number_type t2) { + return (std::abs(t1-t2) < 0.00001); + } + template + static bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1+p2).squaredNorm() < 0.00001); + } + + static int solve(MappedEquationSystem& mes) { + nothing n; + return Nonlinear< Kernel >().solve(mes, n); + }; + + template + static int solve(MappedEquationSystem& mes, Functor& f) { + return Nonlinear< Kernel >().solve(mes, f); + }; + +}; + +} + +#endif //GCM_KERNEL_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/logging.hpp b/src/Mod/Assembly/App/opendcm/core/logging.hpp new file mode 100644 index 000000000000..fd915a36fbd7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/logging.hpp @@ -0,0 +1,94 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_LOGGING_H +#define GCM_LOGGING_H + +#ifdef USE_LOGGING + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace logging = boost::log; +namespace sinks = boost::log::sinks; +namespace src = boost::log::sources; +namespace fmt = boost::log::formatters; +namespace flt = boost::log::filters; +namespace attrs = boost::log::attributes; +namespace keywords = boost::log::keywords; + +namespace dcm { + +static int counter = 0; +typedef sinks::synchronous_sink< sinks::text_file_backend > sink_t; + +inline boost::shared_ptr< sink_t > init_log() { + + //create the filename + std::stringstream str; + str<<"openDCM_"< core = logging::core::get(); + + boost::shared_ptr< sinks::text_file_backend > backend = + boost::make_shared< sinks::text_file_backend >( + keywords::file_name = str.str(), //file name pattern + keywords::rotation_size = 10 * 1024 * 1024 //Rotation size is 10MB + ); + + // Wrap it into the frontend and register in the core. + // The backend requires synchronization in the frontend. + boost::shared_ptr< sink_t > sink(new sink_t(backend)); + + sink->set_formatter( + fmt::stream <<"[" << fmt::attr("Tag") <<"] " + << fmt::if_(flt::has_attr("ID")) [ + fmt::stream << "["<< fmt::attr< std::string >("ID")<<"] "] + << fmt::message() + ); + + core->add_sink(sink); + return sink; +}; + +inline void stop_log(boost::shared_ptr< sink_t >& sink) { + + boost::shared_ptr< logging::core > core = logging::core::get(); + + // Remove the sink from the core, so that no records are passed to it + core->remove_sink(sink); + sink.reset(); +}; + +}; //dcm + +#endif //USE_LOGGING + +#endif //GCM_LOGGING_H diff --git a/src/Mod/Assembly/App/opendcm/core/object.hpp b/src/Mod/Assembly/App/opendcm/core/object.hpp new file mode 100644 index 000000000000..09a1d1ac3e76 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/object.hpp @@ -0,0 +1,269 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_OBJECT_H +#define GCM_OBJECT_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "property.hpp" + + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +#define EMIT_ARGUMENTS(z, n, data) \ + BOOST_PP_CAT(data, n) + +#define EMIT_CALL_DEF(z, n, data) \ + template < \ + typename S \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + void emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ); + +#define EMIT_CALL_DEC(z, n, data) \ + template \ + template < \ + typename S \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + void Object::emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ) \ + { \ + typedef typename mpl::find::type iterator; \ + typedef typename mpl::distance::type, iterator>::type distance; \ + typedef typename fusion::result_of::value_at::type list_type; \ + list_type& list = fusion::at(m_signals); \ + for (typename list_type::iterator it=list.begin(); it != list.end(); it++) \ + (*it)(BOOST_PP_ENUM(n, EMIT_ARGUMENTS, arg)); \ + }; + +namespace dcm { + +//few standart signal names +struct remove {}; +struct recalculated {}; + +typedef boost::any Connection; + +/** + * @brief Base class for all object types + * + * This class add's property and signal capabilitys to all deriving classes. For properties it is tigthly + * integrated with the system class: It searches systems property list for the derived class as specified by + * the second template parameter and makes it accessible via appopriate functions. Signals are speciefied by a + * mpl::map with signal name type as key and a boost::function as values. + * + * \tparam Sys class of type System of which the properties are taken + * \tparam Obj the type of the derived object + * \tparam Sig a mpl::map specifing the object's signals by (type - boost::function) pairs + **/ +template +struct Object : public boost::enable_shared_from_this { + + Object() {}; + Object(Sys& system); + + /** + * @brief Create a new object of the same type with the same values + * + * Returns a new shared_ptr for the Drived type with the same properties as the initial one. If + * the new pointer should be used in a new system the parameter \param newSys needs to be that + * new system. Overload this function if you have datamembers in any derived class wich are not + * copyconstructable. + * @tparam Prop property type which should be accessed + * @return Prop::type& a reference to the properties actual value. + **/ + virtual boost::shared_ptr clone(Sys& newSys); + + /** + * @brief Access properties + * + * Returns a reference to the propertys actual value. The property type has to be registerd to the + * System type which was given as template parameter to this object. + * @tparam Prop property type which should be accessed + * @return Prop::type& a reference to the properties actual value. + **/ + template + typename Prop::type& getProperty(); + + /** + * @brief Set properties + * + * Set'S the value of a specified property. The property type has to be registerd to the + * System type which was given as template parameter to this object. Note that setProperty(value) + * is equivalent to getProperty() = value. + * @tparam Prop property type which should be setProperty + * @param value value of type Prop::type which should be set in this object + **/ + template + void setProperty(typename Prop::type value); + + /** + * @brief Connects a slot to a specified signal. + * + * Slots are boost::functions which get called when the signal is emitted. Any valid boost::function + * which ressembles the signal tyes signature can be registert. It is important that the signal type + * was registerd to this object on creation by the appropriate template parameter. + * + * @tparam S the signal which should be intercepted + * @param function boost::function which resembles the signal type's signature + * @return void + **/ + template + Connection connectSignal(typename mpl::at::type function); + + /** + * @brief Disconnects a slot for a specific signal. + * + * Disconnects a slot so that it dosn't get called at signal emittion. It's important to + * disconnect the slot by the same boost:function it was connected with. + * + * @tparam S the signal type of interest + * @param function boost::function with which the slot was connected + * @return void + **/ + template + void disconnectSignal(Connection c); + + /*properties + * search the property map of the system class and get the mpl::vector of properties for the + * derived type. It's imortant to not store the properties but their types. These types are + * stored and accessed as fusion vector. + * */ + typedef typename mpl::at::type Mapped; + typedef typename mpl::if_< boost::is_same, mpl::vector0<>, Mapped>::type Sequence; + typedef typename details::pts::type Properties; + + Properties m_properties; + Sys* m_system; + +protected: + /*signal handling + * extract all signal types to allow index search (inex search on signal functions would fail as same + * signatures are supported for multiple signals). Create std::vectors to allow multiple slots per signal + * and store these vectors in a fusion::vector for easy access. + * */ + typedef typename mpl::fold< Sig, mpl::vector<>, + mpl::push_back > >::type sig_name; + typedef typename mpl::fold< Sig, mpl::vector<>, + mpl::push_back > >::type sig_functions; + typedef typename mpl::fold< sig_functions, mpl::vector<>, + mpl::push_back > >::type sig_vectors; + typedef typename fusion::result_of::as_vector::type Signals; + + Signals m_signals; + +public: + //with no vararg templates before c++11 we need preprocessor to create the overloads of emit signal we need + BOOST_PP_REPEAT(5, EMIT_CALL_DEF, ~) +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template +Object::Object(Sys& system) : m_system(&system) {}; + +template +boost::shared_ptr Object::clone(Sys& newSys) { + + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + return np; +}; + +template +template +typename Prop::type& Object::getProperty() { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(m_properties); +}; + +template +template +void Object::setProperty(typename Prop::type value) { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + fusion::at(m_properties) = value; +}; + +template +template +Connection Object::connectSignal(typename mpl::at::type function) { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + typedef typename fusion::result_of::value_at::type list_type; + list_type& list = fusion::at(m_signals); + return list.insert(list.begin(),function); +}; + +template +template +void Object::disconnectSignal(Connection c) { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + + typedef typename fusion::result_of::value_at::type list_type; + list_type& list = fusion::at(m_signals); + list.erase(boost::any_cast(c)); +}; + +BOOST_PP_REPEAT(5, EMIT_CALL_DEC, ~) + +} + +#endif //GCM_OBJECT_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp new file mode 100644 index 000000000000..dd7b68bbaa03 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/property.hpp @@ -0,0 +1,167 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_PROPERTY_H +#define GCM_PROPERTY_H + +#include +#include +#include +#include + +#include +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +struct vertex_property {}; +struct edge_property {}; +struct cluster_property {}; +struct object_property {}; + +namespace details { + +template +struct vertex_selector { + typedef typename boost::graph_traits::vertex_descriptor key_type; + typedef typename Graph::vertex_properties sequence_type; +}; + +template +struct edge_selector { + typedef typename boost::graph_traits::edge_descriptor key_type; + typedef typename Graph::edge_properties sequence_type; +}; + +template< typename Kind, typename Graph> +struct property_selector : public mpl::if_, + vertex_selector, edge_selector >::type {}; + +template +struct property_type { + typedef typename T::type type; +}; +template +struct property_kind { + typedef typename T::kind type; +}; + +//property vector to a fusion sequence of the propety types +template +struct pts { //property type sequence + typedef typename mpl::transform >::type ptv; + typedef typename fusion::result_of::as_vector< ptv >::type type; +}; +} + +template +struct is_edge_property : boost::is_same {}; + +template +struct is_vertex_property : boost::is_same {}; + +template +struct is_cluster_property : boost::is_same {}; + +template +struct is_object_property : boost::is_same {}; + +template +class property_map { + +public: + typedef typename dcm::details::property_selector::key_type key_type; + typedef typename Property::type value_type; + typedef typename Property::type& reference; + typedef boost::lvalue_property_map_tag category; + + typedef Property property; + typedef typename dcm::details::property_selector::sequence_type sequence; + + property_map(Graph& g) + : m_graph(g) { } + + Graph& m_graph; +}; + +template +typename property_map::value_type get(const property_map& map, + typename property_map::key_type key) { + + typedef property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + return fusion::at(fusion::at_c<0>(map.m_graph[key])); +}; + +template +void put(const property_map& map, + typename property_map::key_type key, + const typename property_map::value_type& value) { + + typedef property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + fusion::at(fusion::at_c<0>(map.m_graph[key])) = value; +}; + + +template +typename property_map::reference at(const property_map& map, + typename property_map::key_type key) { + typedef property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + return fusion::at(fusion::at_c<0>(map.m_graph[key])); +} + + +//now create some standart properties +//*********************************** + +struct empty_prop { + typedef int kind; + typedef int type; +}; + +struct type_prop { + //states the type of a cluster + typedef cluster_property kind; + typedef int type; +}; + +struct changed_prop { + typedef cluster_property kind; + typedef bool type; +}; + +template +struct id_prop { + typedef object_property kind; + typedef T type; +}; + +} + + +#endif //GCM_PROPERTY_H diff --git a/src/Mod/Assembly/App/opendcm/core/sheduler.hpp b/src/Mod/Assembly/App/opendcm/core/sheduler.hpp new file mode 100644 index 000000000000..873caf6ba3d2 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/sheduler.hpp @@ -0,0 +1,100 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_SHEDULER_H +#define GCM_SHEDULER_H + +#include +#include + +namespace dcm { + +template +struct Job { + + virtual ~Job() {}; + + virtual void execute(Sys& sys) = 0; + + bool operator<(const Job& j) const { + return priority < j.priority; + }; + int priority; +}; + +template +struct FunctorJob : Job { + FunctorJob(functor f) : m_functor(f) { + Job::priority = prior; + }; + virtual void execute(System& sys) { + m_functor(sys); + }; + + functor m_functor; +}; + +template +class Sheduler { + +public: + Sheduler() {}; + ~Sheduler() { + + std::for_each(m_preprocess.begin(), m_preprocess.end(), Deleter()); + std::for_each(m_process.begin(), m_process.end(), Deleter()); + std::for_each(m_postprocess.begin(), m_postprocess.end(), Deleter()); + }; + + void addPreprocessJob(Job* j) { + m_preprocess.insert(j); + }; + void addPostprocessJob(Job* j) { + m_postprocess.insert(j); + }; + void addProcessJob(Job* j) { + m_process.insert(j); + }; + + void execute(Sys& system) { + std::for_each(m_preprocess.begin(), m_preprocess.end(), Executer(system)); + std::for_each(m_process.begin(), m_process.end(), Executer(system)); + std::for_each(m_postprocess.begin(), m_postprocess.end(), Executer(system)); + }; + +protected: + struct Executer { + Executer(Sys& s) : m_system(s) {}; + void operator()(Job* j) { + j->execute(m_system); + }; + Sys& m_system; + }; + struct Deleter { + void operator()(Job* j) { + delete j; + }; + }; + + std::set< Job* > m_preprocess, m_process, m_postprocess; +}; + +} + +#endif //GCM_SHEDULER_H diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp new file mode 100644 index 000000000000..16c931cf4d97 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -0,0 +1,327 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_SYSTEM_H +#define GCM_SYSTEM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "property.hpp" +#include "clustergraph.hpp" +#include "sheduler.hpp" +#include "logging.hpp" +#include "traits.hpp" + +namespace mpl = boost::mpl; + +namespace dcm { + +struct No_Identifier {}; +struct Unspecified_Identifier {}; + + +namespace details { + +enum { subcluster = 10}; + +template +struct vector_fold : mpl::fold< seq, state, + mpl::push_back > {}; + +template +struct edge_fold : mpl::fold< seq, state, + mpl::if_< is_edge_property, + mpl::push_back, mpl::_1 > > {}; + +template +struct vertex_fold : mpl::fold< seq, state, + mpl::if_< is_vertex_property, + mpl::push_back, mpl::_1 > > {}; + +template +struct cluster_fold : mpl::fold< seq, state, + mpl::if_< is_cluster_property, + mpl::push_back, mpl::_1 > > {}; + +template +struct obj_fold : mpl::fold< seq, state, + mpl::if_< mpl::or_< + boost::is_same< details::property_kind, obj>, is_object_property >, + mpl::push_back, mpl::_1 > > {}; + +template +struct property_map { + typedef typename mpl::fold< + objects, mpl::map<>, mpl::insert< mpl::_1, mpl::pair< + mpl::_2, details::obj_fold, mpl::_2 > > > >::type type; +}; +template +struct get_identifier { + typedef typename T::Identifier type; +}; + +template +struct map_fold : mpl::fold< seq, state, mpl::insert > {}; + +struct nothing {}; + +template +struct EmptyModule { + + template + struct type { + struct inheriter {}; + typedef mpl::vector<> properties; + typedef mpl::vector<> objects; + typedef Unspecified_Identifier Identifier; + + static void system_init(T& sys) {}; + static void system_copy(const T& from, T& into) {}; + }; +}; + +template +struct is_shared_ptr : boost::mpl::false_ {}; +template +struct is_shared_ptr > : boost::mpl::true_ {}; + +} + +template< typename KernelType, + typename T1 = details::EmptyModule<1>, + typename T2 = details::EmptyModule<2>, + typename T3 = details::EmptyModule<3> > +class System : public T1::template type< System >::inheriter, + public T2::template type< System >::inheriter, + public T3::template type< System >::inheriter { + + typedef System BaseType; +public: + typedef typename T1::template type< BaseType > Type1; + typedef typename T2::template type< BaseType > Type2; + typedef typename T3::template type< BaseType > Type3; + typedef mpl::vector3 TypeVector; + + //Check if all Identifiers are the same and find out which type it is + typedef typename mpl::fold, + mpl::if_, Unspecified_Identifier>, + mpl::_1, mpl::push_back > > >::type Identifiers; + BOOST_MPL_ASSERT((mpl::or_< + mpl::less_equal::type, mpl::int_<1> >, + mpl::equal< typename mpl::count >::type, typename mpl::size::type > >)); + + typedef typename mpl::if_< mpl::empty, + No_Identifier, typename mpl::at_c::type >::type Identifier; + + +public: + //get all module objects and properties + typedef typename details::vector_fold >::type >::type>::type objects; + + typedef typename details::vector_fold > >::type >::type>::type properties; + + //make the subcomponent lists of objects and properties + typedef typename details::edge_fold< properties, mpl::vector<> >::type edge_properties; + typedef typename details::vertex_fold< properties, mpl::vector<> >::type vertex_properties; + typedef typename details::cluster_fold< properties, + mpl::vector >::type cluster_properties; + + typedef typename details::property_map::type object_properties; + +protected: + //object storage + typedef typename mpl::transform >::type sp_objects; + typedef typename mpl::fold< sp_objects, mpl::vector<>, + mpl::push_back > >::type object_vectors; + typedef typename fusion::result_of::as_vector::type Storage; + + template + friend struct Object; + + struct clearer { + template + void operator()(T& vector) const { + vector.clear(); + }; + }; + +#ifdef USE_LOGGING + boost::shared_ptr< sink_t > sink; +#endif + +public: + typedef ClusterGraph Cluster; + typedef Sheduler< BaseType > Shedule; + typedef KernelType Kernel; + +public: + System() : m_cluster(new Cluster), m_storage(new Storage) +#ifdef USE_LOGGING + , sink(init_log()) +#endif + { + Type1::system_init(*this); + Type2::system_init(*this); + Type3::system_init(*this); + + }; + + + ~System() { +#ifdef USE_LOGGING + stop_log(sink); +#endif + }; + + void clear() { + + m_cluster->clearClusters(); + m_cluster->clear(); + fusion::for_each(*m_storage, clearer()); + }; + + template + typename std::vector< boost::shared_ptr >::iterator begin() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage).begin(); + }; + + template + typename std::vector< boost::shared_ptr >::iterator end() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage).end(); + }; + + template + std::vector< boost::shared_ptr >& objectVector() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage); + }; + + template + void push_back(boost::shared_ptr ptr) { + objectVector().push_back(ptr); + }; + + template + void erase(boost::shared_ptr ptr) { + + std::vector< boost::shared_ptr >& vec = objectVector(); + vec.erase(std::remove(vec.begin(), vec.end(), ptr), vec.end()); + }; + + void solve() { + clock_t start = clock(); + m_sheduler.execute(*this); + clock_t end = clock(); + double ms = (double(end-start)* 1000.) / double(CLOCKS_PER_SEC); + //Base::Console().Message("overall solving time in ms: %f\n", ms); + + }; + + System* createSubsystem() { + + System* s = new System(); + s->m_cluster = m_cluster->createCluster().first; + s->m_storage = m_storage; + s->m_cluster->template setClusterProperty(details::subcluster); + return s; + }; + +private: + struct cloner { + + System& newSys; + cloner(System& ns) : newSys(ns) {}; + + template + struct test : mpl::and_, + mpl::not_ > > > {}; + + template + typename boost::enable_if< test, void>::type operator()(T& p) const { + p = p->clone(newSys); + newSys.push_back(p); + }; + template + typename boost::enable_if< mpl::not_ >, void>::type operator()(const T& p) const {}; + }; + +public: + void copyInto(System& into) const { + + //copy the clustergraph and clone all objects while at it. They are also pushed to the storage + cloner cl(into); + m_cluster->copyInto(into.m_cluster, cl); + + //notify all modules that they are copied + Type1::system_copy(*this, into); + Type2::system_copy(*this, into); + Type3::system_copy(*this, into); + }; + + System* clone() const { + + System* ns = new System(); + this->copyInto(*ns); + return ns; + }; + + boost::shared_ptr m_cluster; + boost::shared_ptr m_storage; + Shedule m_sheduler; + Kernel m_kernel; +}; + +} +#endif //GCM_SYSTEM_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/traits.hpp b/src/Mod/Assembly/App/opendcm/core/traits.hpp new file mode 100644 index 000000000000..1d296f820a5b --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/traits.hpp @@ -0,0 +1,101 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_TRAITS_H +#define GCM_TRAITS_H + +#include +#include +#include + +#include +#include +#include + +#include + +namespace mpl = boost::mpl; + +namespace dcm { + +template< typename T > +struct system_traits { + typedef typename T::Kernel Kernel; + typedef typename T::Cluster Cluster; + + template + struct getModule { + + typedef typename mpl::if_< boost::is_base_of, typename T::Type1, typename T::Type2 >::type test1; + typedef typename mpl::if_< boost::is_base_of, test1, typename T::Type3 >::type test2; + typedef typename mpl::if_< boost::is_base_of, test2, mpl::void_ >::type type; + + typedef boost::is_same has_module; + }; +}; + +template +struct compare_traits { + + BOOST_MPL_ASSERT_MSG((mpl::not_ >::value), + YOU_SHOULD_NOT_USE_THIS_TYPE_AS_IDENTIFIER, + (const char*)); + + static bool compare(T& first, T& second) { + return first == second; + }; +}; + +template<> +struct compare_traits { + + static bool compare(std::string& first, std::string& second) { + return !(first.compare(second)); + }; +}; + +template +struct vector_shrink { + typedef typename mpl::copy< seq, mpl::back_inserter< mpl::vector<> > >::type type; +}; + +template +struct vector_shrink< seq, 0 > { + typedef mpl::vector0<> type; +}; +template +struct vector_shrink< seq, 1 > { + typedef mpl::vector1< typename mpl::at_c< seq, 0 >::type > type; +}; + +#define SEQ_TYPES(z, n, data) \ + typename mpl::at_c< seq, n >::type + +#define VECTOR_SHRINK(z, n, data) \ + template< typename seq> \ + struct vector_shrink { \ + typedef BOOST_PP_CAT(mpl::vector, n) < \ + BOOST_PP_ENUM(n, SEQ_TYPES, ~) > type; \ + }; + + BOOST_PP_REPEAT_FROM_TO(2,10, VECTOR_SHRINK, ~) + +}//namespace dcm + +#endif //GCM_TRAITS_H diff --git a/src/Mod/Assembly/App/opendcm/core/transformation.hpp b/src/Mod/Assembly/App/opendcm/core/transformation.hpp new file mode 100644 index 000000000000..cec6c0d469b0 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/transformation.hpp @@ -0,0 +1,292 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef DCM_TRANSFORMATION_H +#define DCM_TRANSFORMATION_H + +#include +#include +#include + +#include + +namespace dcm { +namespace detail { + +template +class Transform { + +public: + typedef Eigen::Matrix Vector; + typedef typename boost::mpl::if_c< Dim == 3, + Eigen::Quaternion, + Eigen::Rotation2D >::type Rotation; + typedef Eigen::Translation Translation; + typedef Eigen::UniformScaling Scaling; + typedef typename Rotation::RotationMatrixType RotationMatrix; + +protected: + Rotation m_rotation; + Translation m_translation; + Scaling m_scale; + +public: + Transform() : m_rotation(Rotation::Identity()), + m_translation(Translation::Identity()), + m_scale(Scaling(1.)) { }; + + Transform(const Rotation& r) : m_rotation(r), + m_translation(Translation::Identity()), + m_scale(Scaling(1.)) { + m_rotation.normalize(); + }; + + Transform(const Rotation& r, const Translation& t) : m_rotation(r), + m_translation(t), + m_scale(Scaling(1.)) { + m_rotation.normalize(); + }; + + Transform(const Rotation& r, const Translation& t, const Scaling& s) : m_rotation(r), + m_translation(t), + m_scale(s) { + m_rotation.normalize(); + }; + + //access the single parts and manipulate them + //*********************** + const Rotation& rotation() const { + return m_rotation; + } + template + Transform& rotate(const Eigen::RotationBase& rotation) { + m_rotation = rotation.derived().normalized()*m_rotation; + return *this; + } + + const Translation& translation() const { + return m_translation; + } + Transform& translate(const Translation& translation) { + m_translation = m_translation*translation; + return *this; + } + + const Scaling& scaling() const { + return m_scale; + } + Transform& scale(const Scalar& scaling) { + m_scale *= Scaling(scaling); + return *this; + } + Transform& scale(const Scaling& scaling) { + m_scale.factor() *= scaling.factor(); + return *this; + } + + Transform& invert() { + m_rotation = m_rotation.inverse(); + m_translation.vector() = (m_rotation*m_translation.vector()) * (-m_scale.factor()); + m_scale = Scaling(1./m_scale.factor()); + return *this; + }; + Transform inverse() { + Transform res(*this); + res.invert(); + return res; + }; + + //operators for value manipulation + //******************************** + + inline Transform& operator=(const Translation& t) { + m_translation = t; + m_rotation = Rotation::Identity(); + m_scale = Scaling(1.); + return *this; + } + inline Transform operator*(const Translation& t) const { + Transform res = *this; + res.translate(t); + return res; + } + inline Transform& operator*=(const Translation& t) { + return translate(t); + } + + inline Transform& operator=(const Scaling& s) { + m_scale = s; + m_translation = Translation::Identity(); + m_rotation = Rotation::Identity(); + return *this; + } + inline Transform operator*(const Scaling& s) const { + Transform res = *this; + res.scale(s); + return res; + } + inline Transform& operator*=(const Scaling& s) { + return scale(s); + } + + template + inline Transform& operator=(const Eigen::RotationBase& r) { + m_rotation = r.derived(); + m_rotation.normalize(); + m_translation = Translation::Identity(); + m_scale = Scaling(1); + return *this; + } + template + inline Transform operator*(const Eigen::RotationBase& r) const { + Transform res = *this; + res.rotate(r.derived()); + return res; + } + template + inline Transform& operator*=(const Eigen::RotationBase& r) { + return rotate(r.derived()); + } + + inline Transform operator* (const Transform& other) const { + Transform res(*this); + res*= other; + return res; + } + inline Transform& operator*= (const Transform& other) { + rotate(other.rotation()); + other.rotate(m_translation.vector()); + m_translation.vector() += other.translation().vector()/m_scale.factor(); + m_scale.factor() *= other.scaling().factor(); + return *this; + } + + //transform Vectors + //***************** + template + inline Derived& rotate(Eigen::MatrixBase& vec) const { + vec = m_rotation*vec; + return vec.derived(); + } + template + inline Derived& translate(Eigen::MatrixBase& vec) const { + vec = m_translation*vec; + return vec.derived(); + } + template + inline Derived& scale(Eigen::MatrixBase& vec) const { + vec*=m_scale.factor(); + return vec.derived(); + } + template + inline Derived& transform(Eigen::MatrixBase& vec) const { + vec = (m_rotation*vec + m_translation.vector())*m_scale.factor(); + return vec.derived(); + } + template + inline Derived operator*(const Eigen::MatrixBase& vec) const { + return (m_rotation*vec + m_translation.vector())*m_scale.factor(); + } + template + inline void operator()(Eigen::MatrixBase& vec) const { + transform(vec); + } + + //Stuff + //***** + bool isApprox(const Transform& other, Scalar prec) const { + return m_rotation.isApprox(other.rotation(), prec) + && ((m_translation.vector()- other.translation().vector()).norm() < prec) + && (std::abs(m_scale.factor()-other.scaling().factor()) < prec); + }; + void setIdentity() { + m_rotation.setIdentity(); + m_translation = Translation::Identity(); + m_scale = Scaling(1.); + } + static const Transform Identity() { + return Transform(Rotation::Identity(), Translation::Identity(), Scaling(1)); + } + + Transform& normalize() { + m_rotation.normalize(); + return *this; + } +}; + +template +class DiffTransform : public Transform { + + typedef typename Transform::Rotation Rotation; + typedef typename Transform::Translation Translation; + typedef typename Transform::Scaling Scaling; + typedef Eigen::Matrix DiffMatrix; + + DiffMatrix m_diffMatrix; + +public: + DiffTransform() : Transform() { }; + DiffTransform(const Rotation& r) : Transform(r) {}; + DiffTransform(const Rotation& r, const Translation& t) : Transform(r,t) {}; + DiffTransform(const Rotation& r, const Translation& t, const Scaling& s) : Transform(r,t,s) {}; + + DiffTransform(Transform& trans) + : Transform(trans.rotation(), trans.translation(), trans.scaling()) { + + m_diffMatrix.setZero(); + }; + + const DiffMatrix& differential() { + return m_diffMatrix; + }; + inline Scalar& operator()(int f, int s) { + return m_diffMatrix(f,s); + }; + inline Scalar& at(int f, int s) { + return m_diffMatrix(f,s); + }; +}; + +}//detail +}//DCM + +/*When you overload a binary operator as a member function of a class the overload is used + * when the first operand is of the class type.For stream operators, the first operand + * is the stream and not (usually) the custom class. +*/ +template +std::ostream& operator<<(std::ostream& os, const dcm::detail::Transform& t) { + os << "Rotation: " << t.rotation().coeffs().transpose() << std::endl + << "Translation: " << t.translation().vector().transpose() < +std::ostream& operator<<(std::ostream& os, dcm::detail::DiffTransform& t) { + os << "Rotation: " << t.rotation().coeffs().transpose() << std::endl + << "Translation: " << t.translation().vector().transpose() < + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EXTERNALIZE_H +#define DCM_EXTERNALIZE_H + +#include +#include +#include + +#ifdef USE_EXTERNAL + +#define DCM_EXTERNAL_INCLUDE_001 +#define DCM_EXTERNAL_001( System )\ + template struct dcm::details::edge_generator; \ + template struct dcm::details::vertex_generator; \ + + +#define DCM_EXTERNAL_INCLUDE_002 +#define DCM_EXTERNAL_002( System )\ + template struct dcm::details::obj_gen; \ + +#define DCM_EXTERNAL_INCLUDE_003 +#define DCM_EXTERNAL_003( System )\ + template struct dcm::details::vertex_prop_gen; \ + template struct dcm::details::edge_prop_gen; \ + template struct dcm::details::cluster_prop_gen; + +#define DCM_EXTERNAL_INCLUDE_004 +#define DCM_EXTERNAL_004( System )\ + template struct dcm::generator; \ + +#define DCM_EXTERNAL_INCLUDE_005 +#define DCM_EXTERNAL_005( System )\ + template struct dcm::details::vertex_prop_par; \ + template struct dcm::details::edge_prop_par; \ + template struct dcm::details::cluster_prop_par; + +#define DCM_EXTERNAL_INCLUDE_006 +#define DCM_EXTERNAL_006( System )\ + template struct dcm::details::obj_par; \ + +#define DCM_EXTERNAL_INCLUDE_007 +#define DCM_EXTERNAL_007( System )\ + template struct dcm::details::edge_parser; \ + template struct dcm::details::vertex_parser; \ + +#define DCM_EXTERNAL_INCLUDE_008 +#define DCM_EXTERNAL_008( System )\ + template struct dcm::parser; \ + +#else +#define DCM_EXTERNALIZE( System ) +#endif + +#endif //DCM_EXTERNALIZE_H + diff --git a/src/Mod/Assembly/App/opendcm/module3d.hpp b/src/Mod/Assembly/App/opendcm/module3d.hpp new file mode 100644 index 000000000000..a62bbb59a02a --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d.hpp @@ -0,0 +1,32 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULE3D_H +#define DCM_MODULE3D_H + +#define DCM_USE_MODULE3D + +#include "module3d/geometry.hpp" +#include "module3d/distance.hpp" +#include "module3d/parallel.hpp" +#include "module3d/angle.hpp" +#include "module3d/module.hpp" + +#endif //DCM_MODULE3D_H + diff --git a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp new file mode 100644 index 000000000000..94d9e9efbeae --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp @@ -0,0 +1,149 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_ANGLE_HPP +#define GCM_ANGLE_HPP + +#include "geometry.hpp" + +namespace dcm { + +//the calculations( same as we always calculate directions we can outsource the work to this functions) +namespace angle_detail { + +template +inline typename Kernel::number_type calc(T d1, + T d2, + typename Kernel::number_type angle) { + + return d1.dot(d2) / (d1.norm()*d2.norm()) - angle; +}; + + +template +inline typename Kernel::number_type calcGradFirst(T d1, + T d2, + T dd1) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + return dd1.dot(d2)/norm - (d1.dot(d2) * (d1.dot(dd1)/d1.norm())*d2.norm()) / std::pow(norm,2); +}; + +template +inline typename Kernel::number_type calcGradSecond(T d1, + T d2, + T dd2) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + return d1.dot(dd2)/norm - (d1.dot(d2) * (d2.dot(dd2)/d2.norm())*d1.norm()) / std::pow(norm,2); +}; + +template +inline void calcGradFirstComp(T d1, + T d2, + T grad) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + grad = d2/norm - (d1.dot(d2)/std::pow(norm,2))*d1/d1.norm(); +}; + +template +inline void calcGradSecondComp(T d1, + T d2, + T grad) { + + typename Kernel::number_type norm = d1.norm()*d2.norm(); + grad = d1/norm - (d1.dot(d2)/std::pow(norm,2))*d2/d2.norm(); +}; + +} +/* +template< typename Kernel, typename Tag1, typename Tag2 > +struct Angle3D { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + Scalar m_angle; + + Angle3D(Scalar d = 0.) : m_angle(std::cos(d)) {}; + + //template definition + void setScale(Scalar scale){ + assert(false); + }; + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; +}; + +template< typename Kernel > +struct Angle3D< Kernel, tag::line3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + Scalar m_angle; + + Angle3D(Scalar d = 0.) : m_angle(std::cos(d)) {}; + + Scalar getEquationScaling(typename Kernel::Vector& local1, typename Kernel::Vector& local2) { + return 1.; + } + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return angle::calc(param1.template tail<3>(), param2.template tail<3>(), m_angle); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return angle::calcGradFirst(param1.template tail<3>(), param2.template tail<3>(), dparam1.template tail<3>()); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return angle::calcGradSecond(param1.template tail<3>(), param2.template tail<3>(), dparam2.template tail<3>()); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + angle::calcGradFirstComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>()); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + angle::calcGradSecondComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>()); + }; +}; + +//planes like lines have the direction as segment 3-5, so we can use the same implementations +template< typename Kernel > +struct Angle3D< Kernel, tag::plane3D, tag::plane3D > : public Angle3D {}; +template< typename Kernel > +struct Angle3D< Kernel, tag::line3D, tag::plane3D > : public Angle3D {}; +*/ +} + +#endif //GCM_ANGLE_HPP \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp new file mode 100644 index 000000000000..13cb030ccbd8 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -0,0 +1,770 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_CLUSTERMATH_H +#define GCM_CLUSTERMATH_H + +#include +#include + +#include +#include +#include +#include "defines.hpp" + +#define MAXFAKTOR 1.2 //the maximal distance allowd by a point normed to the cluster size +#define MINFAKTOR 0.8 //the minimal distance allowd by a point normed to the cluster size +#define SKALEFAKTOR 1. //the faktor by which the biggest size is multiplied to get the scale value +#define NQFAKTOR 0.5 //the faktor by which the norm quaternion is multiplied with to get the RealScalar +//norm quaternion to generate the unit quaternion + +namespace dcm { +namespace details { + +enum Scalemode { + one, + two, + three, + multiple_inrange, + multiple_outrange +}; + +template +struct ClusterMath { + +public: + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::math_prop math_prop; + typedef typename module3d::fix_prop fix_prop; + + typedef typename Kernel::number_type Scalar; + + typename Kernel::Transform3D m_transform, m_ssrTransform, m_resetTransform; + typename Kernel::DiffTransform3D m_diffTrans; + typename Kernel::Vector3Map m_normQ; + typename Kernel::Quaternion m_resetQuaternion; + + int m_offset; + bool init, fix; + std::vector m_geometry; + + typename Kernel::Vector3Map m_translation; + //shift scale stuff + typename Kernel::Vector3 midpoint, m_shift, scale_dir, maxm, minm, max, fixtrans; + Scalemode mode; + Scalar m_scale; + + typedef std::vector > Vec; + Vec m_points, m_pseudo; + +#ifdef USE_LOGGING + src::logger log; +#endif + +public: + ClusterMath(); + + void setParameterOffset(int offset); + int getParameterOffset(); + + typename Kernel::Vector3Map& getNormQuaternionMap(); + typename Kernel::Vector3Map& getTranslationMap(); + void initMaps(); + void initFixMaps(); + + typename Kernel::Transform3D& getTransform(); + void mapsToTransform(typename Kernel::Transform3D& trans); + void transformToMaps(typename Kernel::Transform3D& trans); + + void finishCalculation(); + void finishFixCalculation(); + + void resetClusterRotation(typename Kernel::Transform3D& trans); + + void calcDiffTransform(typename Kernel::DiffTransform3D& trans); + void recalculate(); + + void addGeometry(Geom g); + void clearGeometry(); + std::vector& getGeometry(); + + struct map_downstream { + + details::ClusterMath& m_clusterMath; + typename Kernel::Transform3D m_transform; + bool m_isFixed; + + map_downstream(details::ClusterMath& cm, bool fix); + + void operator()(Geom g); + void operator()(boost::shared_ptr c); + }; + + void mapClusterDownstreamGeometry(boost::shared_ptr cluster); + + //Calculate the scale of the cluster. Therefore the midpoint is calculated and the scale is + // defined as the max distance between the midpoint and the points. + Scalar calculateClusterScale(); + + void applyClusterScale(Scalar scale, bool isFixed); + +private: + Scalar calcOnePoint(const typename Kernel::Vector3& p); + + Scalar calcTwoPoints(const typename Kernel::Vector3& p1, const typename Kernel::Vector3& p2); + + Scalar calcThreePoints(const typename Kernel::Vector3& p1, + const typename Kernel::Vector3& p2, const typename Kernel::Vector3& p3); +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + + +template +ClusterMath::ClusterMath() : m_normQ(NULL), m_translation(NULL), init(false) { + + m_resetTransform = typename Kernel::Quaternion(1,1,1,1); + m_shift.setZero(); + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Clustermath3D")); +#endif +}; + +template +void ClusterMath::setParameterOffset(int offset) { + m_offset = offset; +}; + +template +int ClusterMath::getParameterOffset() { + return m_offset; +}; + +template +typename ClusterMath::Kernel::Vector3Map& ClusterMath::getNormQuaternionMap() { + return m_normQ; +}; + +template +typename ClusterMath::Kernel::Vector3Map& ClusterMath::getTranslationMap() { + return m_translation; +}; + +template +void ClusterMath::initMaps() { + + transformToMaps(m_transform); + init = true; + midpoint.setZero(); + m_shift.setZero(); + m_ssrTransform.setIdentity(); + m_diffTrans = m_transform; + fix=false; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init transform: "< +void ClusterMath::initFixMaps() { + //when fixed no maps exist + new(&m_translation) typename Kernel::Vector3Map(&fixtrans(0)); + m_translation = m_transform.translation().vector(); + init = true; + midpoint.setZero(); + m_shift.setZero(); + m_ssrTransform.setIdentity(); + m_diffTrans = m_transform; + fix=true; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init fix transform: "< +typename ClusterMath::Kernel::Transform3D& ClusterMath::getTransform() { + return m_transform; +}; + +template +void ClusterMath::mapsToTransform(typename ClusterMath::Kernel::Transform3D& trans) { + //add scale only after possible reset + typename Kernel::Transform3D::Scaling scale(m_transform.scaling()); + trans = m_diffTrans; + trans *= scale; +}; + +template +void ClusterMath::transformToMaps(typename ClusterMath::Kernel::Transform3D& trans) { + + const typename Kernel::Quaternion& m_quaternion = trans.rotation(); + if(m_quaternion.w() < 1.) { + Scalar s = std::acos(m_quaternion.w())/std::sin(std::acos(m_quaternion.w())); + m_normQ = m_quaternion.vec()*s; + m_normQ /= NQFAKTOR; + } else { + m_normQ.setZero(); + } + m_translation = trans.translation().vector(); +}; + +template +void ClusterMath::finishCalculation() { + + mapsToTransform(m_transform); + init=false; + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish calculation"; +#endif + + m_transform = m_ssrTransform*m_transform; + + //scale all geometries back to the original size + m_diffTrans *= typename Kernel::Transform3D::Scaling(1./m_ssrTransform.scaling().factor()); + typedef typename std::vector::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->recalculate(m_diffTrans); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish transform:"< +void ClusterMath::finishFixCalculation() { +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish fix calculation"; +#endif + typedef typename std::vector::iterator iter; + m_transform *= m_ssrTransform.inverse(); + typename Kernel::DiffTransform3D diff(m_transform); + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->recalculate(diff); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish fix transform:"< +void ClusterMath::resetClusterRotation(typename ClusterMath::Kernel::Transform3D& trans) { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Reset cluster rotation:"<::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) { + (*it)->transform(m_resetTransform); + }; +}; + +template +void ClusterMath::calcDiffTransform(typename ClusterMath::Kernel::DiffTransform3D& trans) { + + Scalar norm = m_normQ.norm(); + trans.setIdentity(); + + if(norm < 0.1) { + if(norm == 0) { + trans *= typename Kernel::Transform3D::Translation(m_translation); + resetClusterRotation(trans); + } else { + const Scalar fac = std::sin(NQFAKTOR*norm)/norm; + trans = typename Kernel::Quaternion(std::cos(NQFAKTOR*norm), m_normQ(0)*fac, m_normQ(1)*fac,m_normQ(2)*fac); + trans *= typename Kernel::Transform3D::Translation(m_translation); + resetClusterRotation(trans); + } + transformToMaps(trans); + return; + } + + const Scalar fac = std::sin(NQFAKTOR*norm)/norm; + trans = typename Kernel::Quaternion(std::cos(NQFAKTOR*norm), m_normQ(0)*fac, m_normQ(1)*fac, m_normQ(2)*fac); + trans *= typename Kernel::Transform3D::Translation(m_translation); +}; + +template +void ClusterMath::recalculate() { + + + calcDiffTransform(m_diffTrans); + + const typename Kernel::Quaternion Q = m_diffTrans.rotation(); + + // now calculate the gradient quaternions and calculate the diff rotation matrices + // m_normQ = (a,b,c) + // n = ||m_normQ|| + // + // Q = (a/n sin(n), b/n sin(n), c/n sin(n), cos(n)) + // + + //n=||m_normQ||, sn = sin(n)/n, sn3 = sin(n)/n^3, cn = cos(n)/n, divn = 1/n; + const Scalar n = m_normQ.norm(); + const Scalar sn = std::sin(NQFAKTOR*n)/n; + const Scalar mul = (NQFAKTOR*std::cos(NQFAKTOR*n)-sn)/std::pow(n,2); + + //dxa = dQx/da + const Scalar dxa = sn + std::pow(m_normQ(0),2)*mul; + const Scalar dxb = m_normQ(0)*m_normQ(1)*mul; + const Scalar dxc = m_normQ(0)*m_normQ(2)*mul; + + const Scalar dya = m_normQ(1)*m_normQ(0)*mul; + const Scalar dyb = sn + std::pow(m_normQ(1),2)*mul; + const Scalar dyc = m_normQ(1)*m_normQ(2)*mul; + + const Scalar dza = m_normQ(2)*m_normQ(0)*mul; + const Scalar dzb = m_normQ(2)*m_normQ(1)*mul; + const Scalar dzc = sn + std::pow(m_normQ(2),2)*mul; + + const Scalar dwa = -sn*NQFAKTOR*m_normQ(0); + const Scalar dwb = -sn*NQFAKTOR*m_normQ(1); + const Scalar dwc = -sn*NQFAKTOR*m_normQ(2); + + //write in the diffrot matrix, starting with dQ/dx + m_diffTrans.at(0,0) = -4.0*(Q.y()*dya+Q.z()*dza); + m_diffTrans.at(0,1) = -2.0*(Q.w()*dza+dwa*Q.z())+2.0*(Q.x()*dya+dxa*Q.y()); + m_diffTrans.at(0,2) = 2.0*(dwa*Q.y()+Q.w()*dya)+2.0*(dxa*Q.z()+Q.x()*dza); + m_diffTrans.at(1,0) = 2.0*(Q.w()*dza+dwa*Q.z())+2.0*(Q.x()*dya+dxa*Q.y()); + m_diffTrans.at(1,1) = -4.0*(Q.x()*dxa+Q.z()*dza); + m_diffTrans.at(1,2) = -2.0*(dwa*Q.x()+Q.w()*dxa)+2.0*(dya*Q.z()+Q.y()*dza); + m_diffTrans.at(2,0) = -2.0*(dwa*Q.y()+Q.w()*dya)+2.0*(dxa*Q.z()+Q.x()*dza); + m_diffTrans.at(2,1) = 2.0*(dwa*Q.x()+Q.w()*dxa)+2.0*(dya*Q.z()+Q.y()*dza); + m_diffTrans.at(2,2) = -4.0*(Q.x()*dxa+Q.y()*dya); + + //dQ/dy + m_diffTrans.at(0,3) = -4.0*(Q.y()*dyb+Q.z()*dzb); + m_diffTrans.at(0,4) = -2.0*(Q.w()*dzb+dwb*Q.z())+2.0*(Q.x()*dyb+dxb*Q.y()); + m_diffTrans.at(0,5) = 2.0*(dwb*Q.y()+Q.w()*dyb)+2.0*(dxb*Q.z()+Q.x()*dzb); + m_diffTrans.at(1,3) = 2.0*(Q.w()*dzb+dwb*Q.z())+2.0*(Q.x()*dyb+dxb*Q.y()); + m_diffTrans.at(1,4) = -4.0*(Q.x()*dxb+Q.z()*dzb); + m_diffTrans.at(1,5) = -2.0*(dwb*Q.x()+Q.w()*dxb)+2.0*(dyb*Q.z()+Q.y()*dzb); + m_diffTrans.at(2,3) = -2.0*(dwb*Q.y()+Q.w()*dyb)+2.0*(dxb*Q.z()+Q.x()*dzb); + m_diffTrans.at(2,4) = 2.0*(dwb*Q.x()+Q.w()*dxb)+2.0*(dyb*Q.z()+Q.y()*dzb); + m_diffTrans.at(2,5) = -4.0*(Q.x()*dxb+Q.y()*dyb); + + //dQ/dz + m_diffTrans.at(0,6) = -4.0*(Q.y()*dyc+Q.z()*dzc); + m_diffTrans.at(0,7) = -2.0*(Q.w()*dzc+dwc*Q.z())+2.0*(Q.x()*dyc+dxc*Q.y()); + m_diffTrans.at(0,8) = 2.0*(dwc*Q.y()+Q.w()*dyc)+2.0*(dxc*Q.z()+Q.x()*dzc); + m_diffTrans.at(1,6) = 2.0*(Q.w()*dzc+dwc*Q.z())+2.0*(Q.x()*dyc+dxc*Q.y()); + m_diffTrans.at(1,7) = -4.0*(Q.x()*dxc+Q.z()*dzc); + m_diffTrans.at(1,8) = -2.0*(dwc*Q.x()+Q.w()*dxc)+2.0*(dyc*Q.z()+Q.y()*dzc); + m_diffTrans.at(2,6) = -2.0*(dwc*Q.y()+Q.w()*dyc)+2.0*(dxc*Q.z()+Q.x()*dzc); + m_diffTrans.at(2,7) = 2.0*(dwc*Q.x()+Q.w()*dxc)+2.0*(dyc*Q.z()+Q.y()*dzc); + m_diffTrans.at(2,8) = -4.0*(Q.x()*dxc+Q.y()*dyc); + + //recalculate all geometries + typedef typename std::vector::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->recalculate(m_diffTrans); +}; + +template +void ClusterMath::addGeometry(Geom g) { + m_geometry.push_back(g); +}; + +template +void ClusterMath::clearGeometry() { + m_geometry.clear(); +}; + +template +std::vector::Geom>& ClusterMath::getGeometry() { + return m_geometry; +}; + +template +ClusterMath::map_downstream::map_downstream(details::ClusterMath& cm, bool fix) + : m_clusterMath(cm), m_isFixed(fix) { + m_transform = m_clusterMath.getTransform(); +}; + +template +void ClusterMath::map_downstream::operator()(Geom g) { + //allow iteration over all maped geometries + m_clusterMath.addGeometry(g); + //set the offsets so that geometry knows where it is in the parameter map + g->m_offset = m_clusterMath.getParameterOffset(); + //position and offset of the parameters must be set to the clusters values + g->setClusterMode(true, m_isFixed); + //calculate the appropriate local values + typename Kernel::Transform3D trans = m_transform.inverse(); + g->transform(trans); +}; + +template +void ClusterMath::map_downstream::operator()(boost::shared_ptr c) { + m_transform *= c->template getClusterProperty().getTransform(); +}; + + +template +void ClusterMath::mapClusterDownstreamGeometry(boost::shared_ptr cluster) { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Map downstream geometry"; +#endif + + map_downstream down(cluster->template getClusterProperty(), + cluster->template getClusterProperty()); + cluster->template for_each(down, true); + //TODO: if one subcluster is fixed the hole cluster should be too, as there are no + // dof's remaining between parts and so nothing can be moved when one part is fixed. +}; + +template +typename ClusterMath::Scalar ClusterMath::calculateClusterScale() { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Calculate cluster scale with transform scale: "<::iterator g_iter; + for(g_iter it = m_geometry.begin(); it != m_geometry.end(); it++) + m_points.push_back((*it)->getPoint()); + + //start scale calculation + if(m_points.empty()) assert(false); //TODO: Throw + else if(m_points.size() == 1) { + const typename Kernel::Vector3 p = m_points[0]; + return calcOnePoint(p); + } else if(m_points.size() == 2) { + const typename Kernel::Vector3 p1 = m_points[0]; + const typename Kernel::Vector3 p2 = m_points[1]; + + if(Kernel::isSame((p1-p2).norm(), 0.)) + return calcOnePoint(p1); + + return calcTwoPoints(p1, p2); + } else if(m_points.size() == 3) { + + const typename Kernel::Vector3 p1 = m_points[0]; + const typename Kernel::Vector3 p2 = m_points[1]; + const typename Kernel::Vector3 p3 = m_points[2]; + + const typename Kernel::Vector3 d = p2-p1; + const typename Kernel::Vector3 e = p3-p1; + + if(Kernel::isSame(d.norm(), 0.)) { + + if(Kernel::isSame(e.norm(), 0.)) + return calcOnePoint(p1); + + return calcTwoPoints(p1, p3); + } else if(Kernel::isSame(e.norm(), 0.)) { + return calcTwoPoints(p1, p2); + } else if(!Kernel::isSame((d/d.norm() - e/e.norm()).norm(), 0.) && + !Kernel::isSame((d/d.norm() + e/e.norm()).norm(), 0.)) { + return calcThreePoints(p1, p2, p3); + } + //three points on a line need to be treaded as multiple points + } + + //more than 3 points dont have a exakt solution. we search for a midpoint from which all points + //are at least MAXFAKTOR*scale away, but not closer than MINFAKTOR*scale + + //get the bonding box to get the center of points + Scalar xmin=1e10, xmax=1e-10, ymin=1e10, ymax=1e-10, zmin=1e10, zmax=1e-10; + for(iter it = m_points.begin(); it != m_points.end(); it++) { + typename Kernel::Vector3 v = (*it); + xmin = (v(0) +void ClusterMath::applyClusterScale(Scalar scale, bool isFixed) { + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Apply cluster scale: "<::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) { + (*it)->recalculate(diff); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Fixed cluster geometry value:" << (*it)->m_rotated.transpose(); +#endif + }; + return; + } + + //if this is our scale then just applie the midpoint as shift + if(Kernel::isSame(scale, m_scale)) { + + } + //if only one point exists we extend the origin-point-line to match the scale + else if(mode==details::one) { + if(Kernel::isSame(midpoint.norm(),0)) + midpoint << scale, 0, 0; + else midpoint += scale*scale_dir; + } + //two and three points form a rectangular triangle, so same procedure + else if(mode==details::two || mode==details::three) { + + midpoint+= scale_dir*std::sqrt(std::pow(scale,2) - std::pow(m_scale,2)); + } + //multiple points + else if(mode==details::multiple_outrange) { + + if(scale_dir(0)) { + Scalar d = std::pow(maxm(1),2) + std::pow(maxm(2),2); + Scalar h = std::sqrt(std::pow(MAXFAKTOR*scale,2)-d); + midpoint(0) += maxm(0) + h; + } else if(scale_dir(1)) { + Scalar d = std::pow(maxm(0),2) + std::pow(maxm(2),2); + Scalar h = std::sqrt(std::pow(MAXFAKTOR*scale,2)-d); + midpoint(1) += maxm(1) + h; + } else { + Scalar d = std::pow(maxm(0),2) + std::pow(maxm(1),2); + Scalar h = std::sqrt(std::pow(MAXFAKTOR*scale,2)-d); + midpoint(2) += maxm(2) + h; + } + } else { + + //TODO: it's possible that for this case we get too far away from the outer points. + // The m_scale for "midpoint outside the bounding box" may be bigger than the + // scale to applie, so it results in an error. + //get the closest point + typedef typename Vec::iterator iter; + for(iter it = m_points.begin(); it != m_points.end(); it++) { + + const Eigen::Vector3d point = (*it)-midpoint; + if(point.norm()::iterator iter; + for(iter it = m_geometry.begin(); it != m_geometry.end(); it++) + (*it)->transform(ssTrans); + + //set the new rotation and translation + m_transform = ssTrans.inverse()*m_transform; + m_ssrTransform *= ssTrans; + + transformToMaps(m_transform); + +#ifdef USE_LOGGING + BOOST_LOG(log) << "sstrans scale: "< +typename ClusterMath::Scalar ClusterMath::calcOnePoint(const typename ClusterMath::Kernel::Vector3& p) { + + //one point can have every scale when moving the midpoint on the origin - point vector + midpoint = p; + scale_dir = -midpoint; + scale_dir.normalize(); + mode = details::one; + m_scale = 0.; + return 0.; +}; + +template +typename ClusterMath::Scalar ClusterMath::calcTwoPoints(const typename ClusterMath::Kernel::Vector3& p1, + const typename ClusterMath::Kernel::Vector3& p2) { + + //two points have their minimal scale at the mid position. Scaling perpendicular to this + //line allows arbitrary scale values. Best is to have the scale dir move towards the origin + //as good as possible. + midpoint = p1+(p2-p1)/2.; + scale_dir = (p2-p1).cross(midpoint); + scale_dir = scale_dir.cross(p2-p1); + if(!Kernel::isSame(scale_dir.norm(),0)) scale_dir.normalize(); + else scale_dir(0) = 1; + mode = details::two; + m_scale = (p2-p1).norm()/2.; + return m_scale; +}; + +template +typename ClusterMath::Scalar ClusterMath::calcThreePoints(const typename ClusterMath::Kernel::Vector3& p1, + const typename ClusterMath::Kernel::Vector3& p2, const typename ClusterMath::Kernel::Vector3& p3) { + + //Three points form a triangle with it's minimal scale at the center of it's outer circle. + //Arbitrary scale values can be achieved by moving perpendicular to the triangle plane. + typename Kernel::Vector3 d = p2-p1; + typename Kernel::Vector3 e = p3-p1; + + typename Kernel::Vector3 f = p1+0.5*d; + typename Kernel::Vector3 g = p1+0.5*e; + scale_dir = d.cross(e); + + typename Kernel::Matrix3 m; + m.row(0) = d.transpose(); + m.row(1) = e.transpose(); + m.row(2) = scale_dir.transpose(); + + typename Kernel::Vector3 res(d.transpose()*f, e.transpose()*g, scale_dir.transpose()*p1); + + midpoint = m.colPivHouseholderQr().solve(res); + scale_dir.normalize(); + mode = details::three; + m_scale = (midpoint-p1).norm(); + + return m_scale; + +}; + +}//details +}//dcm + + +#endif //GCM_CLUSTERMATH_H + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/module3d/defines.hpp b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp new file mode 100644 index 000000000000..60549e18cb36 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp @@ -0,0 +1,33 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_DEFINES_3D_H +#define GCM_DEFINES_3D_H + +namespace dcm { +namespace details { + +enum { cluster3D = 100}; + +struct m3d {}; //base of module3d::type to allow other modules check for it + +} +} + +#endif diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp new file mode 100644 index 000000000000..b36d30ad01dd --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -0,0 +1,292 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_DISTANCE3D_H +#define GCM_DISTANCE3D_H + +#include "geometry.hpp" +#include + +namespace dcm { + +template +struct Distance::type< Kernel, tag::point3D, tag::point3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + Scalar value, sc_value; + + //template definition + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& param1, Vector& param2) { + return (param1-param2).norm() - sc_value; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return (param1-param2).dot(dparam1) / (param1-param2).norm(); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return (param1-param2).dot(-dparam2) / (param1-param2).norm(); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient = (param1-param2) / (param1-param2).norm(); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient = (param2-param1) / (param1-param2).norm(); + }; +}; + +template +struct Distance::type< Kernel, tag::point3D, tag::plane3D > { + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + Scalar value, sc_value; + +#ifdef USE_LOGGING + src::logger log; + attrs::mutable_constant< std::string > tag; + + type() : tag("Distance point3D plane3D") { + log.add_attribute("Tag", tag); + }; +#endif + + //template definition + void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) { + //typename Kernel::Vector3 pp = param1.head(3)- ((param1.head(3)-param2.head(3)).dot(param2.tail(3)) / param2.tail(3).norm()*(param2.tail(3))); + //v2.push_back(pp); + typename Kernel::Vector3 dir = (param1.template head<3>()-param2.template head<3>()).cross(param2.template segment<3>(3)); + dir = param2.template segment<3>(3).cross(dir).normalized(); + typename Kernel::Vector3 pp = param2.head(3) + (param1.head(3)-param2.head(3)).norm()*dir; + v2.push_back(pp); +#ifdef USE_LOGGING + if(!boost::math::isnormal(pp.norm())) + BOOST_LOG(log) << "Unnormal pseudopoint detected"; +#endif + }; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& param1, Vector& param2) { + //(p1-p2)°n / |n| - distance + const Scalar res = (param1.head(3)-param2.head(3)).dot(param2.tail(3)) / param2.tail(3).norm() - sc_value; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal residual detected: "< +struct Distance::type< Kernel, tag::plane3D, tag::plane3D > : public Distance::type< Kernel, tag::point3D, tag::plane3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::point3D, tag::plane3D >() { + Distance::type< Kernel, tag::point3D, tag::plane3D >::tag.set("Distance plane3D plane3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); + g.segment(3,3).setZero(); + }; +}; + +template +struct Distance::type< Kernel, tag::point3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef typename Kernel::Vector3 Vector3; + typedef std::vector > Vec; + + Scalar value, sc_value; + Vector3 diff, n, dist; + +#ifdef USE_LOGGING + src::logger log; + attrs::mutable_constant< std::string > tag; + + type() : tag("Distance point3D line3D") { + log.add_attribute("Tag", tag); + }; +#endif + + //template definition + void calculatePseudo(typename Kernel::Vector& point, Vec& v1, typename Kernel::Vector& line, Vec& v2) { + Vector3 pp = line.head(3) + (line.head(3)-point.head(3)).norm()*line.segment(3,3); +#ifdef USE_LOGGING + if(!boost::math::isnormal(pp.norm())) + BOOST_LOG(log) << "Unnormal pseudopoint detected"; +#endif + v2.push_back(pp); + }; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& point, Vector& line) { + //diff = point1 - point2 + n = line.template segment<3>(3); + diff = line.template head<3>() - point.template head<3>(); + dist = diff - diff.dot(n)*n; + const Scalar res = dist.norm() - sc_value; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal residual detected: "<(); + const Vector3 d_dist = d_diff - d_diff.dot(n)*n; + const Scalar res = dist.dot(d_dist)/dist.norm(); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal first cluster gradient detected: "<(); + const Vector3 d_n = dline.template segment<3>(3); + const Vector3 d_dist = d_diff - ((d_diff.dot(n)+diff.dot(d_n))*n + diff.dot(n)*d_n); + const Scalar res = dist.dot(d_dist)/dist.norm(); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal second cluster gradient detected: "<(3) = -(mult*diff + diff.dot(n)*dist)/dist.norm(); + }; +}; + +template +struct Distance::type< Kernel, tag::line3D, tag::line3D > : public Distance::type< Kernel, tag::point3D, tag::line3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::point3D, tag::line3D >() { + Distance::type< Kernel, tag::point3D, tag::line3D >::tag.set("Distance line3D line3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); + g.segment(3,3).setZero(); + }; +}; + +template +struct Distance::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Distance::type< Kernel, tag::line3D, tag::line3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::line3D, tag::line3D >() { + Distance::type< Kernel, tag::line3D, tag::line3D >::tag.set("Distance cylinder3D cylinder3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); + g(6) = 0; + }; +}; + +}//namespace dcm + +#endif //GCM_DISTANCE3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/dof.hpp b/src/Mod/Assembly/App/opendcm/module3d/dof.hpp new file mode 100644 index 000000000000..dbfc79eb11ec --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/dof.hpp @@ -0,0 +1,133 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_DOF_H +#define GCM_DOF_H + +#include +#include + +namespace dcm { + +enum remaining { + nothing = 0, + line, + plane, + volume +}; + +template +class Dof { + + typedef typename K::Vector3 Vec; + typedef std::pair VecID; + +public: + typedef std::vector ConstraintVector; + typedef std::pair Result; + + Dof() : m_translation(volume), m_rotation(volume) {}; + + int dofTranslational() { + return m_translation; + }; + int dofRotational() { + return m_rotation; + }; + int dof() { + return dofTranslational() + dofRotational(); + }; + + + Result removeTranslationDirection(Vec& v, C constraint) { + + if(m_translation == nothing) { + ConstraintVector cv; + cv.push_back(tp1.second); + cv.push_back(tp2.second); + cv.push_back(tp3.second); + return std::make_pair(false,cv); + } else if(m_translation == volume) { + + m_translation = plane; + tp1 = std::make_pair(v, constraint); + } else if(m_translation == plane) { + + if(K::isSame(tp1.first, v) || K::isOpposite(tp1.first, v)) { + ConstraintVector cv; + cv.push_back(tp1.second); + return std::make_pair(false,cv); + } + m_translation = line; + tp2 = std::make_pair(v, constraint); + } else if(m_translation == line) { + + if(tp1.first.cross(tp2.first).dot(v) < 0.001) { + ConstraintVector cv; + cv.push_back(tp1.second); + cv.push_back(tp2.second); + return std::make_pair(false,cv); + } + m_translation = nothing; + tp3 = std::make_pair(v, constraint); + } + + return std::make_pair(true, ConstraintVector()); + }; + + Result allowOnlyRotationDirection(Vec& v, C constraint) { + + if(m_rotation == nothing) { + ConstraintVector cv; + cv.push_back(rp1.second); + cv.push_back(rp2.second); + return std::make_pair(false, cv); + } else if(m_rotation == volume) { + + m_rotation = line; + rp1 = std::make_pair(v, constraint); + } else if(m_rotation == plane) { + + return std::make_pair(false, ConstraintVector()); //error as every function call removes 2 dof's + } else if(m_rotation == line) { + + if(K::isSame(rp1.first, v) || K::isOpposite(rp1.first, v)) { + ConstraintVector cv; + cv.push_back(rp1.second); + return std::make_pair(false, cv); + } + m_rotation = nothing; + rp2 = std::make_pair(v, constraint); + } + + return std::make_pair(true, ConstraintVector()); + }; + + +private: + int m_translation, m_rotation; + VecID tp1,tp2,tp3; //translation pairs + VecID rp1, rp2; //rotation pairs + + +}; + +} + +#endif //GCM_DOF_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp b/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp new file mode 100644 index 000000000000..9fedadc8e8a5 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp @@ -0,0 +1,160 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_GEOMETRY_3D_H +#define GCM_GEOMETRY_3D_H + +#include + +namespace dcm { +namespace tag { + +struct point3D { + typedef mpl::int_<3> parameters; + typedef mpl::int_<1> rotations; + typedef mpl::int_<1> translations; + typedef weight::point weight; +}; + +struct direction3D { + typedef mpl::int_<3> parameters; + typedef mpl::int_<1> rotations; + typedef mpl::int_<0> translations; + typedef weight::direction weight; +}; + +struct line3D { + typedef mpl::int_<6> parameters; + typedef mpl::int_<2> rotations; + typedef mpl::int_<1> translations; + typedef weight::line weight; +}; + +struct plane3D { + typedef mpl::int_<6> parameters; + typedef mpl::int_<2> rotations; + typedef mpl::int_<1> translations; + typedef weight::plane weight; +}; + +struct cylinder3D { + typedef mpl::int_<7> parameters; + typedef mpl::int_<2> rotations; + typedef mpl::int_<1> translations; + typedef weight::cylinder weight; +}; +} + +namespace modell { + + struct XYZ { + /*Modell XYZ: + * 0 = X; + * 1 = Y; + * 2 = Z; + */ + template + void extract(Type& t, Vector& v) { + Accessor a; + v(0) = a.template get(t); + v(1) = a.template get(t); + v(2) = a.template get(t); + } + + template + void inject(Type& t, Vector& v) { + Accessor a; + a.template set(v(0), t); + a.template set(v(1), t); + a.template set(v(2), t); + }; + }; + + struct XYZ2 { + /*Modell XYZ2: two xyz parts after each other + * 0 = X; + * 1 = Y; + * 2 = Z; + * 3 = X dir; + * 4 = Y dir; + * 5 = Z dir; + */ + template + void extract(Type& t, Vector& v) { + Accessor a; + v(0) = a.template get(t); + v(1) = a.template get(t); + v(2) = a.template get(t); + v(3) = a.template get(t); + v(4) = a.template get(t); + v(5) = a.template get(t); + } + + template + void inject(Type& t, Vector& v) { + Accessor a; + a.template set(v(0), t); + a.template set(v(1), t); + a.template set(v(2), t); + a.template set(v(3), t); + a.template set(v(4), t); + a.template set(v(5), t); + }; + }; + + struct XYZ2P { + /*Modell XYZ2P: two xyz parts after each other and one parameter + * 0 = X; + * 1 = Y; + * 2 = Z; + * 3 = X dir; + * 4 = Y dir; + * 5 = Z dir; + * 6 = Parameter + */ + template + void extract(Type& t, Vector& v) { + Accessor a; + v(0) = a.template get(t); + v(1) = a.template get(t); + v(2) = a.template get(t); + v(3) = a.template get(t); + v(4) = a.template get(t); + v(5) = a.template get(t); + v(6) = a.template get(t); + } + + template + void inject(Type& t, Vector& v) { + Accessor a; + a.template set(v(0), t); + a.template set(v(1), t); + a.template set(v(2), t); + a.template set(v(3), t); + a.template set(v(4), t); + a.template set(v(5), t); + a.template set(v(6), t); + }; + }; + +} + +} + +#endif //GCM_GEOMETRY_3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp new file mode 100644 index 000000000000..73623f39f4d6 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -0,0 +1,546 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_MODULE_3D_H +#define GCM_MODULE_3D_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "opendcm/core.hpp" +#include "opendcm/core/object.hpp" +#include "opendcm/core/clustergraph.hpp" +#include "opendcm/core/sheduler.hpp" +#include "opendcm/core/traits.hpp" +#include "opendcm/core/geometry.hpp" +#include "geometry.hpp" +#include "distance.hpp" +#include "parallel.hpp" +#include "angle.hpp" +#include "solver.hpp" +#include "defines.hpp" +#include "clustermath.hpp" + +namespace mpl = boost::mpl; + +namespace dcm { + +namespace details { + +template +struct distance { + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type type; + BOOST_MPL_ASSERT((mpl::not_< boost::is_same::type > >)); +}; +} +}//dcm + +namespace dcm { + +template +struct Module3D { + + template + struct type : details::m3d { + struct Constraint3D; + struct Geometry3D; + struct vertex_prop; + struct inheriter_base; + + typedef boost::shared_ptr Geom; + typedef boost::shared_ptr Cons; + + typedef mpl::map1< mpl::pair > > ConsSignal; + + typedef ID Identifier; + + typedef details::MES MES; + typedef details::SystemSolver SystemSolver; + + template + class Geometry3D_id : public detail::Geometry { + + typedef detail::Geometry Base; + +#ifdef USE_LOGGING + attrs::mutable_constant< std::string > log_id; +#endif + public: + template + Geometry3D_id(T geometry, Sys& system); + + template + void set(T geometry, Identifier id); + //somehow the base class set funtion is not found + template + void set(T geometry); + + Identifier& getIdentifier(); + void setIdentifier(Identifier id); + }; + + struct Geometry3D : public mpl::if_, + detail::Geometry, Geometry3D_id >::type { + + typedef vertex_prop vertex_propertie; + + template + Geometry3D(T geometry, Sys& system); + + //allow accessing the internals by module3d classes but not by users + friend struct details::ClusterMath; + friend struct details::ClusterMath::map_downstream; + friend struct details::SystemSolver; + friend struct details::SystemSolver::Rescaler; + friend class detail::Constraint; + }; + + template + class Constraint3D_id : public detail::Constraint { + + typedef detail::Constraint base; + public: + Constraint3D_id(Sys& system, Geom f, Geom s); + + Identifier& getIdentifier(); + void setIdentifier(Identifier id); + }; + + struct Constraint3D : public mpl::if_, + detail::Constraint, + Constraint3D_id >::type { + + Constraint3D(Sys& system, Geom first, Geom second); + + friend struct details::SystemSolver; + friend struct details::SystemSolver::Rescaler; + friend struct details::MES; + friend struct inheriter_base; + }; + + struct inheriter_base { + + inheriter_base(); + + template + Geom createGeometry3D(T geom); + void removeGeometry3D(Geom g); + + template + Cons createConstraint3D(Geom first, Geom second, T1 constraint1); + void removeConstraint3D(Cons c); + + protected: + Sys* m_this; + void apply_edge_remove(GlobalEdge e); + }; + + struct inheriter_id : public inheriter_base { + + protected: + using inheriter_base::m_this; + + public: + template + Geom createGeometry3D(T geom, Identifier id); + template + Cons createConstraint3D(Identifier id, Geom first, Geom second, T constraint1); + + void removeGeometry3D(Identifier id); + void removeConstraint3D(Identifier id); + + bool hasGeometry3D(Identifier id); + Geom getGeometry3D(Identifier id); + bool hasConstraint3D(Identifier id); + Cons getConstraint3D(Identifier id); + }; + + struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; + + struct math_prop { + typedef cluster_property kind; + typedef details::ClusterMath type; + }; + struct fix_prop { + typedef cluster_property kind; + typedef bool type; + }; + struct vertex_prop { + typedef Geometry3D kind; + typedef GlobalVertex type; + }; + struct edge_prop { + typedef Constraint3D kind; + typedef GlobalEdge type; + }; + + typedef mpl::vector4 properties; + typedef mpl::vector objects; + + static void system_init(Sys& sys) { + sys.m_sheduler.addProcessJob(new SystemSolver()); + }; + static void system_copy(const Sys& from, Sys& into) { + //nothing to to as all objects and properties are copyed with the clustergraph + }; + }; +}; + +namespace details { +//allow direct access to the stored geometry in a Geometry3D, copyed from boost variant get +template +struct get_visitor { +private: + + typedef typename boost::add_pointer::type pointer; + typedef typename boost::add_reference::type reference; + +public: + + typedef pointer result_type; + +public: + pointer operator()(reference operand) const { + return boost::addressof(operand); + } + + template + pointer operator()(const U&) const { + return static_cast(0); + } +}; +} + +template +typename boost::add_reference::type get(G geom) { + + typedef typename boost::add_pointer::type T_ptr; + details::get_visitor v; + T_ptr result = geom->apply(v); + + //if (!result) + //TODO:throw bad_get(); + return *result; +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + + +template +template +template +template +Module3D::type::Geometry3D_id::Geometry3D_id(T geometry, Sys& system) + : detail::Geometry(geometry, system) +#ifdef USE_LOGGING + , log_id("No ID") +#endif +{ + +#ifdef USE_LOGGING + Base::log.add_attribute("ID", log_id); +#endif +}; + +template +template +template +template +void Module3D::type::Geometry3D_id::set(T geometry, Identifier id) { + this->template setProperty >(id); + Base::set(geometry); +}; + +template +template +template +template +void Module3D::type::Geometry3D_id::set(T geometry) { + Base::set(geometry); +}; + +template +template +template +typename Module3D::template type::Identifier& +Module3D::type::Geometry3D_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +template +void Module3D::type::Geometry3D_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +#ifdef USE_LOGGING + std::stringstream str; + str<template getProperty >(); + log_id.set(str.str()); + BOOST_LOG(Base::log)<<"Identifyer set: "< +template +template +Module3D::type::Geometry3D::Geometry3D(T geometry, Sys& system) + : mpl::if_, + detail::Geometry, + Geometry3D_id >::type(geometry, system) { + +}; + +template +template +template +Module3D::type::Constraint3D_id::Constraint3D_id(Sys& system, Geom f, Geom s) + : detail::Constraint(system, f, s) { + +}; + +template +template +template +typename Module3D::template type::Identifier& +Module3D::type::Constraint3D_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +template +void Module3D::type::Constraint3D_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +}; + +template +template +Module3D::type::Constraint3D::Constraint3D(Sys& system, Geom first, Geom second) + : mpl::if_, + detail::Constraint, + Constraint3D_id >::type(system, first, second) { + +}; + +template +template +Module3D::type::inheriter_base::inheriter_base() { + m_this = ((Sys*) this); +}; + +template +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_base::createGeometry3D(T geom) { + + Geom g(new Geometry3D(geom, * ((Sys*) this))); + fusion::vector res = m_this->m_cluster->addVertex(); + m_this->m_cluster->template setObject (fusion::at_c<0> (res), g); + g->template setProperty(fusion::at_c<1>(res)); + m_this->push_back(g); + return g; +}; + +template +template +void Module3D::type::inheriter_base::removeGeometry3D(Geom g) { + + GlobalVertex v = g->template getProperty(); + + //check if this vertex holds a constraint + Cons c = m_this->m_cluster->template getObject(v); + if(c) + c->template emitSignal(c); + + //emit remove geometry signal bevore actually deleting it, in case anyone want to access the + //graph before + g->template emitSignal(g); + + //remove the vertex from graph and emit all edges that get removed with the functor + boost::function functor = boost::bind(&inheriter_base::apply_edge_remove, this, _1); + m_this->m_cluster->removeVertex(v, functor); + m_this->erase(g); +}; + +template +template +template +typename Module3D::template type::Cons +Module3D::type::inheriter_base::createConstraint3D(Geom first, Geom second, T1 constraint1) { + + //build a constraint vector + typedef mpl::vector<> cvec; + typedef typename mpl::if_< mpl::is_sequence, + typename mpl::fold< T1, cvec, mpl::push_back >::type, + mpl::vector1 >::type cvec1; + + //make a fusion sequence to hold the objects (as they hold the options) + typedef typename fusion::result_of::as_vector::type covec; + //set the objects + covec cv; + fusion::at_c<0>(cv) = constraint1; + + //now create the constraint + Cons c(new Constraint3D(*m_this, first, second)); + //set the type and values + c->template initialize(cv); + + //add it to the clustergraph + fusion::vector res; + res = m_this->m_cluster->addEdge(first->template getProperty(), + second->template getProperty()); + if(!fusion::at_c<2>(res)) { + Cons rc; + return rc; //TODO: throw + }; + m_this->m_cluster->template setObject (fusion::at_c<1> (res), c); + //add the coresbondig edge to the constraint + c->template setProperty(fusion::at_c<1>(res)); + //store the constraint in general object vector of main system + m_this->push_back(c); + + return c; +}; + +template +template +void Module3D::type::inheriter_base::removeConstraint3D(Cons c) { + + GlobalEdge e = c->template getProperty(); + c->template emitSignal(c); + m_this->m_cluster->removeEdge(e); + m_this->erase(c); +}; + +template +template +void Module3D::type::inheriter_base::apply_edge_remove(GlobalEdge e) { + Cons c = m_this->m_cluster->template getObject(e); + c->template emitSignal(c); + m_this->erase(c); +}; + +template +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_id::createGeometry3D(T geom, Identifier id) { + Geom g = inheriter_base::createGeometry3D(geom); + g->setIdentifier(id); + return g; +}; + +template +template +void Module3D::type::inheriter_id::removeGeometry3D(Identifier id) { + + if(hasGeometry3D(id)) + inheriter_base::removeGeometry3D(getGeometry3D(id)); +}; + +template +template +template +typename Module3D::template type::Cons +Module3D::type::inheriter_id::createConstraint3D(Identifier id, Geom first, Geom second, T constraint1) { + + Cons c = inheriter_base::createConstraint3D(first, second, constraint1); + c->setIdentifier(id); + return c; +}; + +template +template +void Module3D::type::inheriter_id::removeConstraint3D(Identifier id) { + + if(hasConstraint3D(id)) + removeConstraint3D(getConstraint3D(id)); +}; + + +template +template +bool Module3D::type::inheriter_id::hasGeometry3D(Identifier id) { + if(getGeometry3D(id)) return true; + return false; +}; + +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_id::getGeometry3D(Identifier id) { + std::vector< Geom >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + }; + return Geom(); +}; + +template +template +bool Module3D::type::inheriter_id::hasConstraint3D(Identifier id) { + if(getConstraint3D(id)) return true; + return false; +}; + +template +template +typename Module3D::template type::Cons +Module3D::type::inheriter_id::getConstraint3D(Identifier id) { + std::vector< Cons >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + }; + return Cons(); +}; + +}//dcm + +#endif //GCM_GEOMETRY3D_H + + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp new file mode 100644 index 000000000000..440fa103298a --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -0,0 +1,215 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_PARALLEL_H +#define GCM_PARALLEL_H + +#include + +#include "geometry.hpp" +#include + +using boost::math::isnormal; + +namespace dcm { + +//the calculations( same as we always calculate directions we can outsource the work to this functions) +namespace parallel_detail { + +template +inline typename Kernel::number_type calc(T d1, + T d2, + Direction dir) { + + switch(dir) { + case Same: + return (d1-d2).norm(); + case Opposite: + return (d1+d2).norm(); + case Both: + if(d1.dot(d2) >= 0) { + return (d1-d2).norm(); + } + return (d1+d2).norm(); + default: + assert(false); + } + return 0; +}; + + +template +inline typename Kernel::number_type calcGradFirst(T d1, + T d2, + T dd1, + Direction dir) { + + typename Kernel::number_type res; + switch(dir) { + case Same: + res = ((d1-d2).dot(dd1) / (d1-d2).norm()); + break; + case Opposite: + res= ((d1+d2).dot(dd1) / (d1+d2).norm()); + break; + case Both: + if(d1.dot(d2) >= 0) { + res = (((d1-d2).dot(dd1) / (d1-d2).norm())); + break; + } + res = (((d1+d2).dot(dd1) / (d1+d2).norm())); + break; + } + if((isnormal)(res)) return res; + return 0; +}; + +template +inline typename Kernel::number_type calcGradSecond(T d1, + T d2, + T dd2, + Direction dir) { + + typename Kernel::number_type res; + switch(dir) { + case Same: + res = ((d1-d2).dot(-dd2) / (d1-d2).norm()); + break; + case Opposite: + res = ((d1+d2).dot(dd2) / (d1+d2).norm()); + break; + case Both: + if(d1.dot(d2) >= 0) { + res = (((d1-d2).dot(-dd2) / (d1-d2).norm())); + break; + } + res = (((d1+d2).dot(dd2) / (d1+d2).norm())); + break; + } + if((isnormal)(res)) return res; + return 0; +}; + +template +inline void calcGradFirstComp(T d1, + T d2, + T grad, + Direction dir) { + + switch(dir) { + case Same: + grad = (d1-d2) / (d1-d2).norm(); + return; + case Opposite: + grad = (d1+d2) / (d1+d2).norm(); + return; + case Both: + assert(false); + } +}; + +template +inline void calcGradSecondComp(T d1, + T d2, + T grad, + Direction dir) { + + switch(dir) { + case Same: + grad = (d2-d1) / (d1-d2).norm(); + return; + case Opposite: + grad = (d2+d1) / (d1+d2).norm(); + return; + case Both: + assert(false); + } +}; + +} + +template< typename Kernel > +struct Parallel::type< Kernel, tag::line3D, tag::line3D > : public dcm::PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + Direction value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return parallel_detail::calc(param1.template tail<3>(), param2.template tail<3>(), value); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return parallel_detail::calcGradFirst(param1.template tail<3>(), param2.template tail<3>(), dparam1.template tail<3>(), value); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return parallel_detail::calcGradSecond(param1.template tail<3>(), param2.template tail<3>(), dparam2.template tail<3>(), value); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradFirstComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>(), value); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradSecondComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>(), value); + }; + }; + +template< typename Kernel > +struct Parallel::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::PseudoScale{ + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + Direction value; + + Scalar calculate(Vector& param1, Vector& param2) { + return parallel_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), value); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return parallel_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), + dparam1.template segment<3>(3), value); + + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return parallel_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), + dparam2.template segment<3>(3), value); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), + gradient.template segment<3>(3), value); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + parallel_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), + gradient.template segment<3>(3), value); + }; + }; + +template< typename Kernel > +struct Parallel::type< Kernel, tag::line3D, tag::plane3D > : public Parallel::type {}; + +template< typename Kernel > +struct Parallel::type< Kernel, tag::plane3D, tag::plane3D > : public Parallel::type {}; + +} + +#endif //GCM_ANGLE diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp new file mode 100644 index 000000000000..9502154b3c1e --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -0,0 +1,367 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_SOLVER_3D_H +#define GCM_SOLVER_3D_H + +#include + +#include "defines.hpp" +#include "clustermath.hpp" +#include "opendcm/core/sheduler.hpp" +#include "opendcm/core/traits.hpp" + +namespace dcm { +namespace details { + +template +struct MES : public system_traits::Kernel::MappedEquationSystem { + + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::Constraint3D Constraint3D; + typedef boost::shared_ptr Cons; + typedef typename module3d::math_prop math_prop; + typedef typename module3d::fix_prop fix_prop; + typedef typename Kernel::number_type Scalar; + typedef typename system_traits::Kernel::MappedEquationSystem Base; + + boost::shared_ptr m_cluster; + + MES(boost::shared_ptr cl, int par, int eqn); + virtual void recalculate(); +}; + +template +struct SystemSolver : public Job { + + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::Kernel Kernel; + typedef typename Kernel::number_type Scalar; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::Constraint3D Constraint3D; + typedef boost::shared_ptr Cons; + typedef typename module3d::math_prop math_prop; + typedef typename module3d::fix_prop fix_prop; + typedef typename module3d::vertex_prop vertex_prop; + + typedef MES Mes; + +#ifdef USE_LOGGING + src::logger log; +#endif + struct Rescaler { + + boost::shared_ptr cluster; + Mes& mes; + int rescales; + + Rescaler(boost::shared_ptr c, Mes& m); + + void operator()(); + + Scalar scaleClusters(); + void collectPseudoPoints(boost::shared_ptr parent, + LocalVertex cluster, + std::vector >& vec); + }; + + SystemSolver(); + virtual void execute(Sys& sys); + void solveCluster(boost::shared_ptr cluster, Sys& sys); +}; + + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + + +template +MES::MES(boost::shared_ptr cl, int par, int eqn) : Base(par, eqn), m_cluster(cl) { + +}; + +template +void MES::recalculate() { + + //first calculate all clusters + typedef typename Cluster::cluster_iterator citer; + std::pair cit = m_cluster->clusters(); + for(; cit.first != cit.second; cit.first++) { + + if(!(*cit.first).second->template getClusterProperty()) + (*cit.first).second->template getClusterProperty().recalculate(); + + }; + + //with everything updated just nicely we can compute the constraints + typedef typename Cluster::template object_iterator oiter; + typedef typename boost::graph_traits::edge_iterator eiter; + std::pair eit = boost::edges(*m_cluster); + for(; eit.first != eit.second; eit.first++) { + //as always: every local edge can hold multiple global ones, so iterate over all constraints + //hold by the individual edge + std::pair< oiter, oiter > oit = m_cluster->template getObjects(*eit.first); + for(; oit.first != oit.second; oit.first++) { + if(*oit.first) + (*oit.first)->calculate(Base::Scaling); + } + } +}; + +template +SystemSolver::Rescaler::Rescaler(boost::shared_ptr c, Mes& m) : cluster(c), mes(m), rescales(0) { + +}; + +template +void SystemSolver::Rescaler::operator()() { + mes.Scaling = scaleClusters(); + rescales++; +}; + +template +typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() { + + typedef typename Cluster::cluster_iterator citer; + std::pair cit = cluster->clusters(); + //get the maximal scale + Scalar sc = 0; + for(cit = cluster->clusters(); cit.first != cit.second; cit.first++) { + //fixed cluster are irrelevant for scaling + if((*cit.first).second->template getClusterProperty()) continue; + + //get the biggest scale factor + details::ClusterMath& math = (*cit.first).second->template getClusterProperty(); + + //math.m_pseudo.clear(); + //collectPseudoPoints(cluster, (*cit.first).first, math.m_pseudo); + + const Scalar s = math.calculateClusterScale(); + sc = (s>sc) ? s : sc; + } + //if no scaling-value returned we can use 1 + sc = (Kernel::isSame(sc,0)) ? 1. : sc; + + typedef typename boost::graph_traits::vertex_iterator iter; + std::pair it = boost::vertices(*cluster); + for(; it.first != it.second; it.first++) { + + if(cluster->isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + c->template getClusterProperty().applyClusterScale(sc, + c->template getClusterProperty()); + } else { + Geom g = cluster->template getObject(*it.first); + g->scale(sc*SKALEFAKTOR); + } + } + return 1./(sc*SKALEFAKTOR); +}; + +template +void SystemSolver::Rescaler::collectPseudoPoints( + boost::shared_ptr::Cluster> parent, + LocalVertex cluster, + std::vector::Kernel::Vector3, + Eigen::aligned_allocator::Kernel::Vector3> >& vec) { + + std::vector > vec2; + typedef typename Cluster::template object_iterator c_iter; + typedef typename boost::graph_traits::out_edge_iterator e_iter; + std::pair it = boost::out_edges(cluster, *parent); + for(; it.first != it.second; it.first++) { + + std::pair< c_iter, c_iter > cit = parent->template getObjects(*it.first); + for(; cit.first != cit.second; cit.first++) { + Cons c = *(cit.first); + + if(!c) + continue; + + //get the first global vertex and see if we have it in the wanted cluster or not + GlobalVertex v = c->first->template getProperty(); + std::pair res = parent->getLocalVertex(v); + if(!res.second) + return; //means the geometry is in non of the clusters which is not allowed + + if(res.first == cluster) + c->collectPseudoPoints(vec, vec2); + else + c->collectPseudoPoints(vec2, vec); + } + } +}; + +template +SystemSolver::SystemSolver() { + Job::priority = 1000; +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("SystemSolver3D")); +#endif +}; + +template +void SystemSolver::execute(Sys& sys) { + solveCluster(sys.m_cluster, sys); +}; + +template +void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sys) { + + //set out and solve all relevant subclusters + typedef typename Cluster::cluster_iterator citer; + std::pair cit = cluster->clusters(); + for(; cit.first != cit.second; cit.first++) { + + boost::shared_ptr c = (*cit.first).second; + if(c->template getClusterProperty() && + c->template getClusterProperty() == details::cluster3D) + solveCluster(c, sys); + } + + int params=0, constraints=0; + typename Kernel::number_type scale = 1; + + //get the ammount of parameters and constraint equations we need + typedef typename boost::graph_traits::vertex_iterator iter; + std::pair it = boost::vertices(*cluster); + for(; it.first != it.second; it.first++) { + + //when cluster and not fixed it has trans and rot parameter + if(cluster->isCluster(*it.first)) { + if(!cluster->template getSubclusterProperty(*it.first)) { + params += 6; + } + } else { + params += cluster->template getObject(*it.first)->m_parameterCount; + }; + } + + //count the equations in the constraints + typedef typename Cluster::template object_iterator ocit; + typedef typename boost::graph_traits::edge_iterator e_iter; + std::pair e_it = boost::edges(*cluster); + for(; e_it.first != e_it.second; e_it.first++) { + std::pair< ocit, ocit > it = cluster->template getObjects(*e_it.first); + for(; it.first != it.second; it.first++) + constraints += (*it.first)->equationCount(); + }; + + + //initialise the system with now known size + //std::cout<<"constraints: "<isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + details::ClusterMath& cm = c->template getClusterProperty(); + //only get maps and propagate downstream if not fixed + if(!c->template getClusterProperty()) { + //set norm Quaternion as map to the parameter vector + int offset = mes.setParameterMap(cm.getNormQuaternionMap()); + //set translation as map to the parameter vector + mes.setParameterMap(cm.getTranslationMap()); + //write initail values to the parameter maps + //remember the parameter offset as all downstream geometry must use this offset + cm.setParameterOffset(offset); + //wirte initial values + cm.initMaps(); + } else cm.initFixMaps(); + + //map all geometrie within that cluster to it's rotation matrix + //for collecting all geometries which need updates + cm.clearGeometry(); + cm.mapClusterDownstreamGeometry(c); + + } else { + Geom g = cluster->template getObject(*it.first); + int offset = mes.setParameterMap(g->m_parameterCount, g->getParameterMap()); + g->m_offset = offset; + //init the parametermap with initial values + g->initMap(); + } + } + + //and now the constraints to set the residual and gradient maps + typedef typename Cluster::template object_iterator oiter; + e_it = boost::edges(*cluster); + for(; e_it.first != e_it.second; e_it.first++) { + + //as always: every local edge can hold multiple global ones, so iterate over all constraints + //hold by the individual edge + std::pair< oiter, oiter > oit = cluster->template getObjects(*e_it.first); + for(; oit.first != oit.second; oit.first++) { + + //set the maps + Cons c = *oit.first; + if(c) c->setMaps(mes); + //TODO: else throw (as every global edge was counted as one equation) + } + } + + int stop = 0; + Rescaler re(cluster, mes); + re(); + stop = Kernel::solve(mes, re); +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Numbers of rescale: "<isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + if(!cluster->template getSubclusterProperty(*it.first)) + c->template getClusterProperty().finishCalculation(); + else + c->template getClusterProperty().finishFixCalculation(); + + std::vector& vec = c->template getClusterProperty().getGeometry(); + for(typename std::vector::iterator vit = vec.begin(); vit != vec.end(); vit++) + (*vit)->finishCalculation(); + + } else { + Geom g = cluster->template getObject(*it.first); + g->scale(mes.Scaling); + g->finishCalculation(); + } + } + //we have solved this cluster + cluster->template setClusterProperty(false); +}; + +}//details +}//dcm + +#endif //DCM_SOLVER_3D_HPP diff --git a/src/Mod/Assembly/App/opendcm/module3d/state.hpp b/src/Mod/Assembly/App/opendcm/module3d/state.hpp new file mode 100644 index 000000000000..458d03b33347 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/state.hpp @@ -0,0 +1,95 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULE3D_STATE_HPP +#define DCM_MODULE3D_STATE_HPP + +#include "module.hpp" +#include "opendcm/moduleState/traits.hpp" +#include +#include + +namespace karma = boost::spirit::karma; +namespace ascii = boost::spirit::karma::ascii; +namespace phx = boost::phoenix; + +namespace dcm { + +namespace details { + +struct geom_visitor : public boost::static_visitor { + + template + int operator()(T& i) const { + return geometry_traits::tag::weight::value; + }; +}; + +template +int getWeight(boost::shared_ptr ptr) { + return boost::apply_visitor(geom_visitor(), ptr->m_geometry); +}; + +template +void getStdVector(typename Kernel::Vector& eigen, std::vector& vec) { + vec.resize(eigen.size()); + for(int i=0; i +struct parser_generate< typename Module3D::type::Geometry3D, System> + : public mpl::true_{}; + +template +struct parser_generator< typename Module3D::type::Geometry3D, System, iterator > { + + typedef typename Sys::Kernel Kernel; + typedef typename typename Module3D::type::Geometry3D Geometry; + typedef karma::rule() > generator; + static void init(generator& r) { + r = karma::lit("Geometry3D\n") + << ascii::string[karma::_1 = phx::bind(&details::getWeight, karma::_val)] + << "\n" + << (karma::double_ % " ")[phx::bind(&details::getStdVector, )] + }; +}; + +template +struct parser_parse< typename Module3D::type::Geometry3D, System> + : public mpl::true_{}; + +template +struct parser_parser< typename Module3D::type::Geometry3D, System, iterator > { + + typedef typename Module3D::type::Geometry3D object_type; + + typedef qi::rule(System*), qi::space_type> parser; + static void init(parser& r) { + r = qi::lexeme[qi::lit("object 1 prop")[ qi::_val = + phx::construct >( phx::new_(*qi::_r1))]] >> ("HaHAHAHAHA"); + }; +}; + +} + + +#endif //DCM_MODULE3D_STATE_HPP \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp b/src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp new file mode 100644 index 000000000000..bba370053701 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulePart/geometry.hpp @@ -0,0 +1,92 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_GEOMETRY_PART_H +#define GCM_GEOMETRY_PART_H + +#include +#include + +namespace dcm { +namespace tag { + +struct part {}; + +} + +namespace modell { + + struct quaternion_wxyz_vec3 { + /*Modell XYZ: + * 0 = w; + * 1 = x; + * 2 = y; + * 3 = z; + */ + template + void extract(Type& t, typename Kernel::Transform3D& trans) { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::Transform3D::Rotation Rotation; + typedef typename Kernel::Transform3D::Translation Translation; + + Accessor a; + Rotation r; + r.w() = a.template get(t); + r.x() = a.template get(t); + r.y() = a.template get(t); + r.z() = a.template get(t); + + Translation tr;; + tr.vector()(0) = a.template get(t); + tr.vector()(1) = a.template get(t); + tr.vector()(2) = a.template get(t); + + trans = r; + trans *= tr; + } + + template + void inject(Type& t, typename Kernel::Transform3D& trans) { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::Transform3D::Rotation Rotation; + typedef typename Kernel::Transform3D::Translation Translation; + + Accessor a; + + const Rotation& r = trans.rotation(); + a.template set(r.w(), t); + a.template set(r.x(), t); + a.template set(r.y(), t); + a.template set(r.z(), t); + + const Translation& tr = trans.translation(); + a.template set(tr.vector()(0), t); + a.template set(tr.vector()(1), t); + a.template set(tr.vector()(2), t); + + a.finalize(t); + }; + }; +} + +} + +#endif //GCM_GEOMETRY_PART_H diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp new file mode 100644 index 000000000000..c52b74bcb786 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -0,0 +1,558 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_MODULE_PART_H +#define GCM_MODULE_PART_H + +#include "opendcm/core.hpp" +#include "opendcm/core/traits.hpp" +#include "opendcm/core/clustergraph.hpp" +#include "opendcm/core/property.hpp" +#include "opendcm/module3d.hpp" + +#include +#include + +namespace mpl = boost::mpl; + +namespace dcm { + +enum { clusterPart = 110}; + +enum CoordinateFrame {Local, Global}; + +template +struct ModulePart { + + template + struct type { + + + struct Part; + struct PrepareCluster; + struct EvaljuateCluster; + typedef boost::shared_ptr Partptr; + typedef mpl::map2< mpl::pair >, + mpl::pair > > PartSignal; + + typedef ID Identifier; + + class Part_base : public Object { + protected: + +#ifdef USE_LOGGING + src::logger log; +#endif + + //check if we have module3d in this system + typedef typename system_traits::template getModule::type module3d; + BOOST_MPL_ASSERT((mpl::not_ >)); + + //define what we need + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + + typedef typename boost::make_variant_over< Typelist >::type Variant; + typedef Object base; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::Cluster Cluster; + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::Transform3D Transform; + + struct cloner : boost::static_visitor { + + Variant variant; + cloner(Variant& v) : variant(v) {}; + + template + void operator()(T& t) { + variant = geometry_clone_traits()(t); + }; + }; + + //visitor to write the calculated value into the variant + struct apply_visitor : public boost::static_visitor { + + apply_visitor(Transform& t) : m_transform(t) {}; + + template + void operator()(T& t) const { + (typename geometry_traits::modell()).template inject::accessor >(t, m_transform); + } + Transform& m_transform; + }; + + public: + using Object::m_system; + + template + Part_base(T geometry, Sys& system, boost::shared_ptr cluster); + + template + typename Visitor::result_type apply(Visitor& vis); + + template + Geom addGeometry3D(T geom, CoordinateFrame frame = Global); + + template + void set(T geometry); + + virtual boost::shared_ptr clone(Sys& newSys); + + public: + Variant m_geometry; + Transform m_transform; + boost::shared_ptr m_cluster; + + void finishCalculation(); + void fix(bool fix_value); + }; + + struct Part_id : public Part_base { + + template + Part_id(T geometry, Sys& system, boost::shared_ptr cluster); + + template + typename Part_base::Geom addGeometry3D(T geom, Identifier id, CoordinateFrame frame = Global); + + template + void set(T geometry, Identifier id); + + bool hasGeometry3D(Identifier id); + typename Part_base::Geom getGeometry3D(Identifier id); + + Identifier& getIdentifier(); + void setIdentifier(Identifier id); + }; + + struct Part : public mpl::if_, Part_base, Part_id>::type { + + typedef typename mpl::if_, Part_base, Part_id>::type base; + + template + Part(T geometry, Sys& system, boost::shared_ptr cluster); + + friend struct PrepareCluster; + friend struct EvaljuateCluster; + }; + + + struct inheriter_base { + + inheriter_base(); + + template + Partptr createPart(T geometry); + void removePart(Partptr p); + + template + void setTransformation(T geom) { + + typedef typename system_traits::template getModule::type module3d; + details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); + + (typename geometry_traits::modell()).template extract::accessor >(geom, cm.getTransform()); + }; + + template + T getTransformation() { + + T geom; + getTransformation(geom); + return geom; + }; + template + void getTransformation(T& geom) { + + typedef typename system_traits::template getModule::type module3d; + details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); + + (typename geometry_traits::modell()).template inject::accessor >(geom, cm.getTransform()); + }; + + protected: + Sys* m_this; + + //function object to emit remove signal too al geometry which is deleted by part deletion + struct remover { + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef boost::shared_ptr Geom; + typedef typename module3d::Constraint3D Constraint3D; + typedef boost::shared_ptr Cons; + + Sys& system; + remover(Sys& s); + //see if we have a geometry or a constraint and emit the remove signal + void operator()(GlobalVertex v); + //we delete all global edges connecting to this part + void operator()(GlobalEdge e); + void operator()(boost::shared_ptr g) {}; + }; + }; + + struct inheriter_id : public inheriter_base { + + template + Partptr createPart(T geometry, Identifier id); + bool hasPart(Identifier id); + Partptr getPart(Identifier id); + }; + + struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; + + typedef mpl::vector0<> properties; + typedef mpl::vector1 objects; + + struct PrepareCluster : public Job { + + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::template getModule::type module3d; + + PrepareCluster(); + virtual void execute(Sys& sys); + }; + + struct EvaljuateCluster : public Job { + + typedef typename system_traits::Cluster Cluster; + typedef typename system_traits::Kernel Kernel; + typedef typename system_traits::template getModule::type module3d; + + EvaljuateCluster(); + virtual void execute(Sys& sys); + }; + + static void system_init(Sys& sys) { + sys.m_sheduler.addPreprocessJob(new PrepareCluster()); + sys.m_sheduler.addPostprocessJob(new EvaljuateCluster()); + }; + static void system_copy(const Sys& from, Sys& into) {}; + }; +}; + +template +template +template +ModulePart::type::Part_base::Part_base(T geometry, Sys& system, boost::shared_ptr cluster) + : Object(system), m_geometry(geometry), m_cluster(cluster) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Part3D")); +#endif + + (typename geometry_traits::modell()).template extract::accessor >(geometry, m_transform); + + cluster->template setClusterProperty(false); + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init: "< +template +template +typename Visitor::result_type ModulePart::type::Part_base::apply(Visitor& vis) { + return boost::apply_visitor(vis, m_geometry); +}; + +template +template +template +typename ModulePart::template type::Part_base::Geom +ModulePart::type::Part_base::addGeometry3D(T geom, CoordinateFrame frame) { + Geom g(new Geometry3D(geom, *m_system)); + if(frame == Local) + g->transform(m_transform); + + fusion::vector res = m_cluster->addVertex(); + m_cluster->template setObject (fusion::at_c<0> (res), g); + g->template setProperty(fusion::at_c<1>(res)); + m_system->template objectVector().push_back(g); + + return g; +}; + +template +template +template +void ModulePart::type::Part_base::set(T geometry) { + Part_base::m_geometry = geometry; + (typename geometry_traits::modell()).template extract::accessor >(geometry, Part_base::m_transform); +}; + +template +template +boost::shared_ptr::template type::Part> +ModulePart::type::Part_base::clone(Sys& newSys) { + + //we need to reset the cluster pointer to the new system cluster + LocalVertex lv = Object::m_system->m_cluster->getClusterVertex(m_cluster); + GlobalVertex gv = Object::m_system->m_cluster->getGlobalVertex(lv); + + boost::shared_ptr np = Object::clone(newSys); + //there may be pointer inside the variant + cloner clone_fnc(np->m_geometry); + boost::apply_visitor(clone_fnc, m_geometry); + + fusion::vector, bool> res = newSys.m_cluster->getLocalVertexGraph(gv); + if(!fusion::at_c<2>(res)) { + //todo: throw + return np; + } + np->m_cluster = fusion::at_c<1>(res)->getVertexCluster(fusion::at_c<0>(res)); + + return np; +}; + +template +template +void ModulePart::type::Part_base::finishCalculation() { + + m_transform.normalize(); + apply_visitor vis(m_transform); + apply(vis); + +#ifdef USE_LOGGING + BOOST_LOG(log) << "New Value: "<(((Part*)this)->shared_from_this()); +}; + +template +template +void ModulePart::type::Part_base::fix(bool fix_value) { + m_cluster->template setClusterProperty(fix_value); +}; + +template +template +template +ModulePart::type::Part_id::Part_id(T geometry, Sys& system, boost::shared_ptr cluster) + : Part_base(geometry, system, cluster) { + +}; + +template +template +template +typename ModulePart::template type::Part_base::Geom +ModulePart::type::Part_id::addGeometry3D(T geom, Identifier id, CoordinateFrame frame) { + + typename Part_base::Geom g = Part_base::addGeometry3D(geom, frame); + g->setIdentifier(id); + return g; +}; + +template +template +template +void ModulePart::type::Part_id::set(T geometry, Identifier id) { + Part_base::set(geometry); + setIdentifier(id); +}; + +template +template +bool ModulePart::type::Part_id::hasGeometry3D(Identifier id) { + typename Part_base::Geom g = Part_base::m_system->getGeometry3D(id); + if(!g) return false; + + //get the global vertex and check if it is a child of the part cluster + GlobalVertex v = g->template getProperty(); + return Part_base::m_cluster->getLocalVertex(v).second; +}; + +template +template +typename ModulePart::template type::Part_base::Geom +ModulePart::type::Part_id::getGeometry3D(Identifier id) { + return Part_base::m_system->getGeometry3D(id); +}; + +template +template +typename ModulePart::template type::Identifier& +ModulePart::type::Part_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +void ModulePart::type::Part_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +}; + +template +template +template +ModulePart::type::Part::Part(T geometry, Sys& system, boost::shared_ptr cluster) + : mpl::if_, + Part_base, Part_id>::type(geometry, system, cluster) { + +}; + +template +template +ModulePart::type::inheriter_base::inheriter_base() { + m_this = ((Sys*) this); +}; + +template +template +template +typename ModulePart::template type::Partptr +ModulePart::type::inheriter_base::createPart(T geometry) { + + typedef typename system_traits::Cluster Cluster; + std::pair, LocalVertex> res = m_this->m_cluster->createCluster(); + Partptr p(new Part(geometry, * ((Sys*) this), res.first)); + + m_this->m_cluster->template setObject (res.second, p); + m_this->push_back(p); + + res.first->template setClusterProperty(clusterPart); + return p; +}; + +template +template +void ModulePart::type::inheriter_base::removePart(Partptr p) { + + remover r(*m_this); + m_this->m_cluster->removeCluster(p->m_cluster, r); + p->template emitSignal(p); + m_this->erase(p); +}; + +template +template +ModulePart::type::inheriter_base::remover::remover(Sys& s) : system(s) { + +}; + +template +template +void ModulePart::type::inheriter_base::remover::operator()(GlobalVertex v) { + Geom g = system.m_cluster->template getObject(v); + if(g) { + g->template emitSignal(g); + system.erase(g); + } + Cons c = system.m_cluster->template getObject(v); + if(c) { + c->template emitSignal(c); + system.erase(c); + } +}; + +template +template +void ModulePart::type::inheriter_base::remover::operator()(GlobalEdge e) { + Cons c = system.m_cluster->template getObject(e); + if(c) { + c->template emitSignal(c); + system.erase(c); + } +}; + +template +template +template +typename ModulePart::template type::Partptr +ModulePart::type::inheriter_id::createPart(T geometry, Identifier id) { + Partptr p = inheriter_base::createPart(geometry); + p->setIdentifier(id); + return p; +}; + +template +template +bool ModulePart::type::inheriter_id::hasPart(Identifier id) { + if(getPart(id)) return true; + return false; +}; + +template +template +typename ModulePart::template type::Partptr +ModulePart::type::inheriter_id::getPart(Identifier id) { + std::vector< Partptr >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + }; + return Partptr(); +}; + +template +template +ModulePart::type::PrepareCluster::PrepareCluster() { + Job::priority = 1000; +}; + +template +template +void ModulePart::type::PrepareCluster::execute(Sys& sys) { + //get all parts and set their values to the cluster's + typedef typename std::vector::iterator iter; + for(iter it = sys.template begin(); it != sys.template end(); it++) { + + details::ClusterMath& cm = (*it)->m_cluster->template getClusterProperty(); + cm.getTransform() = (*it)->m_transform; + }; +}; + +template +template +ModulePart::type::EvaljuateCluster::EvaljuateCluster() { + Job::priority = 1000; +}; + +template +template +void ModulePart::type::EvaljuateCluster::execute(Sys& sys) { + //get all parts and set their values to the cluster's + typedef typename std::vector::iterator iter; + for(iter it = sys.template begin(); it != sys.template end(); it++) { + + details::ClusterMath& cm = (*it)->m_cluster->template getClusterProperty(); + (*it)->m_transform = cm.getTransform(); + (*it)->finishCalculation(); + }; +}; + +} + +#endif //GCM_MODULEPART_H + + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/defines.hpp b/src/Mod/Assembly/App/opendcm/moduleState/defines.hpp new file mode 100644 index 000000000000..d77c5cfda7f7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/defines.hpp @@ -0,0 +1,36 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_DEFINES_STATE_H +#define DCM_DEFINES_STATE_H + +#include "opendcm/core/property.hpp" +#include "opendcm/core/clustergraph.hpp" + +namespace dcm { +namespace details { + +struct cluster_vertex_prop { + typedef GlobalVertex type; + typedef cluster_property kind; +}; +} +} + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp new file mode 100644 index 000000000000..7182c5c4ca1a --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp @@ -0,0 +1,72 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_GENERATOR_H +#define DCM_EDGE_GENERATOR_H + +#include "property_generator.hpp" +#include "object_generator.hpp" +#include "extractor.hpp" + +#include +#include +#include + +#include + +namespace karma = boost::spirit::karma; +namespace phx = boost::phoenix; + +namespace dcm { +namespace details { + +template +struct edge_generator : karma::grammar >()> { + + edge_generator(); + + karma::rule >()> edge_range; + karma::rule()> edge; + karma::rule&()> globaledge_range; + karma::rule globaledge; + details::edge_prop_gen edge_prop; + details::obj_gen objects; + Extractor ex; +}; + +template +struct vertex_generator : karma::grammar()> { + + vertex_generator(); + + karma::rule()> vertex_range; + karma::rule vertex; + details::vertex_prop_gen vertex_prop; + details::obj_gen objects; + Extractor ex; +}; + +}//details +}//dcm + +#ifndef USE_EXTERNAL + #include "edge_vertex_generator_imp.hpp" +#endif + +#endif \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp new file mode 100644 index 000000000000..40d6fa78edd7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp @@ -0,0 +1,57 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_GENERATOR_IMP_H +#define DCM_EDGE_GENERATOR_IMP_H + +#include "edge_vertex_generator.hpp" + +namespace dcm { +namespace details { + +template +edge_generator::edge_generator() : edge_generator::base_type(edge_range) { + + globaledge = karma::int_[phx::bind(&Extractor::getGlobalEdgeID, ex, karma::_val, karma::_1)] + << " source=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeSource, ex, karma::_val, karma::_1)] + << " target=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeTarget, ex, karma::_val, karma::_1)] << '>' + << "+" << objects[karma::_1 = phx::at_c<0>(karma::_val)] << "-\n" ; + + + globaledge_range = *(karma::lit("")); + + edge = karma::lit("source=")<(karma::_val)] << " target="<(karma::_val)] << ">+" + << edge_prop[karma::_1 = phx::at_c<0>(phx::at_c<0>(karma::_val))] + << karma::eol << globaledge_range[karma::_1 = phx::at_c<1>(phx::at_c<0>(karma::_val))] << '-' << karma::eol; + + edge_range = (karma::lit("")) % karma::eol; +}; + +template +vertex_generator::vertex_generator() : vertex_generator::base_type(vertex_range) { + + vertex = karma::int_ << ">+" << vertex_prop << objects << "-\n"; + + vertex_range = '\n' << (karma::lit("")) % karma::eol; +}; + +}//details +}//dcm + +#endif \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp new file mode 100644 index 000000000000..d4172fb3afca --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp @@ -0,0 +1,71 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_VERTEX_PARSER_H +#define DCM_EDGE_VERTEX_PARSER_H + +#include +#include "opendcm/core/clustergraph.hpp" +#include "extractor.hpp" + +namespace qi = boost::spirit::qi; +namespace fusion = boost::fusion; + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +namespace details { + +template +struct edge_parser : qi::grammar< IIterator, fusion::vector(typename Sys::Cluster*, Sys*), + qi::space_type > { + + edge_parser(); + details::obj_par objects; + Injector in; + + qi::rule(typename Sys::Cluster*, Sys*), qi::space_type> edge; + qi::rule global_edge; + details::edge_prop_par edge_prop; + + }; + +template +struct vertex_parser : qi::grammar< IIterator, fusion::vector(typename Sys::Cluster*, Sys*), + qi::space_type> { + + vertex_parser(); + + details::obj_par objects; + Injector in; + + qi::rule(typename Sys::Cluster*, Sys*), qi::space_type> vertex; + details::vertex_prop_par prop; + + }; + +} +} + +//#ifndef USE_EXTERNAL +//#include "edge_vertex_parser_imp.hpp" +//#endif + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp new file mode 100644 index 000000000000..8b43333a099d --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp @@ -0,0 +1,55 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EDGE_PARSER_IMP_H +#define DCM_EDGE_PARSER_IMP_H + +#include "edge_vertex_parser.hpp" + +namespace dcm { +namespace details { + +template +edge_parser::edge_parser() : edge_parser::base_type(edge) { + + global_edge = qi::lit("> qi::lit("id=") >> qi::int_[phx::bind(&GlobalEdge::ID, phx::at_c<1>(qi::_val)) = qi::_1] + >> qi::lit("source=") >> qi::int_[phx::bind(&GlobalEdge::source, phx::at_c<1>(qi::_val)) = qi::_1] + >> qi::lit("target=") >> qi::int_[phx::bind(&GlobalEdge::target, phx::at_c<1>(qi::_val)) = qi::_1] >> '>' + >> objects(qi::_r1)[phx::at_c<0>(qi::_val) = qi::_1] >> ""; + + edge = (qi::lit("> "source=" >> qi::int_ >> "target=" >> qi::int_ >> '>')[qi::_val = phx::bind((&Sys::Cluster::addEdgeGlobal), qi::_r1, qi::_1, qi::_2)] + >> edge_prop[phx::bind(&Injector::setEdgeProperties, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> *global_edge(qi::_r2) + >> (""); +}; + +template +vertex_parser::vertex_parser() : vertex_parser::base_type(vertex) { + + vertex = qi::lit("::addVertex, in, qi::_r1, qi::_val)] >> qi::lit("id=") + >> qi::int_[phx::at_c<1>(qi::_val) = phx::bind(&Sys::Cluster::setGlobalVertex, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> '>' >> prop[phx::bind(&Injector::setVertexProperties, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> objects(qi::_r2)[phx::bind(&Injector::setVertexObjects, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> (""); +}; + +}//details +}//dcm + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp new file mode 100644 index 000000000000..7d2e4ed7c781 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp @@ -0,0 +1,119 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EXTRACTOR_H +#define DCM_EXTRACTOR_H + +#include "defines.hpp" +#include +#include + +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +template +struct Extractor { + + typedef typename boost::graph_traits::vertex_iterator viter; + typedef typename boost::graph_traits::edge_iterator eiter; + + void getVertexRange(typename Sys::Cluster& cluster, std::vector& range) { + std::pair res = boost::vertices(cluster); + for(; res.first != res.second; res.first++) + range.push_back(cluster[*res.first]); + }; + void getEdgeRange(typename Sys::Cluster& cluster, + std::vector >& range) { + + std::pair res = boost::edges(cluster); + for(; res.first != res.second; res.first++) + range.push_back(fusion::make_vector(cluster[*res.first], + cluster.getGlobalVertex(boost::source(*res.first, cluster)), + cluster.getGlobalVertex(boost::target(*res.first, cluster)))); + + }; + void getGlobalEdgeSource(typename Sys::Cluster::edge_bundle_single b, int& source) { + source = fusion::at_c<1>(b).source; + }; + void getGlobalEdgeTarget(typename Sys::Cluster::edge_bundle_single b, int& target) { + target = fusion::at_c<1>(b).target; + }; + void getGlobalEdgeID(typename Sys::Cluster::edge_bundle_single b, int& id) { + id = fusion::at_c<1>(b).ID; + }; + void setVertexID(typename Sys::Cluster* cluster, LocalVertex v, long& l) { + if(v) + l = cluster->getGlobalVertex(v); + else + l = 0; + }; + void getClusterRange(typename Sys::Cluster& cluster, std::vector >& range) { + + typedef typename Sys::Cluster::const_cluster_iterator iter; + + for(iter it = cluster.m_clusters.begin(); it != cluster.m_clusters.end(); it++) { + range.push_back( std::make_pair( cluster.getGlobalVertex((*it).first), (*it).second.get() )); + }; + }; +}; + +template +struct Injector { + + void setClusterProperties(typename Sys::Cluster* cluster, + typename details::pts::type& prop) { + cluster->m_cluster_bundle = prop; + }; + void setVertexProperties(typename Sys::Cluster* cluster, LocalVertex v, + typename details::pts::type& prop) { + fusion::at_c<1>(cluster->operator[](v)) = prop; + }; + void setVertexObjects(typename Sys::Cluster* cluster, LocalVertex v, + typename details::sps::type& obj) { + fusion::at_c<2>(cluster->operator[](v)) = obj; + }; + + void setEdgeProperties(typename Sys::Cluster* cluster, LocalEdge e, + typename details::pts::type& prop) { + fusion::at_c<0>(cluster->operator[](e)) = prop; + }; + void setVertexProperty(typename Sys::Cluster* cluster, int value) { + cluster->template setClusterProperty(value); + }; + void addCluster(typename Sys::Cluster* cluster, typename Sys::Cluster* addcl) { + LocalVertex v = cluster->getLocalVertex(addcl->template getClusterProperty()).first; + cluster->m_clusters[v] = boost::shared_ptr(addcl); + }; + void addVertex(typename Sys::Cluster* cluster, fusion::vector& vec) { + vec = cluster->addVertex(); + }; +}; + + + +}//namespace dcm + +#endif //DCM_GENERATOR_H + + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp new file mode 100644 index 000000000000..ab77c556c951 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp @@ -0,0 +1,82 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_GENERATOR_H +#define DCM_GENERATOR_H + +#include "property_generator.hpp" +#include "edge_vertex_generator.hpp" +#include "extractor.hpp" + +#include + +#include "traits.hpp" +#include "traits_impl.hpp" +#include "indent.hpp" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace karma = boost::spirit::karma; +namespace phx = boost::phoenix; +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +template +struct generator : karma::grammar { + + typedef typename Sys::Cluster graph; + typedef typename graph::cluster_bundle graph_bundle; + typedef typename boost::graph_traits::vertex_iterator viter; + typedef typename boost::graph_traits::edge_iterator eiter; + + generator(); + + karma::rule start; + + karma::rule()> cluster_pair; + karma::rule cluster; + details::cluster_prop_gen cluster_prop; + + details::vertex_generator vertex_range; + details::edge_generator edge_range; + + Extractor ex; +}; + +}//namespace dcm + +#ifndef USE_EXTERNAL +#include "generator_imp.hpp" +#endif + +#endif //DCM_GENERATOR_H + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp new file mode 100644 index 000000000000..f258c065b640 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp @@ -0,0 +1,72 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_GENERATOR_IMP_H +#define DCM_GENERATOR_IMP_H + +#include "generator.hpp" +#include "opendcm/core/clustergraph.hpp" +//#include "karma_trans.hpp" + +#include +#include +#include + + +BOOST_FUSION_ADAPT_TPL_STRUCT( + (T1)(T2)(T3)(T4), + (dcm::ClusterGraph) (T1)(T2)(T3)(T4), + (int, test) + (typename dcm::details::pts::type, m_cluster_bundle)) + + +namespace boost { namespace spirit { namespace traits +{ + template + struct transform_attribute* const, dcm::ClusterGraph&, karma::domain> + { + typedef dcm::ClusterGraph& type; + static type pre(dcm::ClusterGraph* const& val) { + return *val; + } + }; +}}} + +namespace dcm { + +template +generator::generator() : generator::base_type(start) { + + cluster %= karma::omit[karma::int_] << cluster_prop << -vertex_range[phx::bind(&Extractor::getVertexRange, ex, karma::_val, karma::_1)] + << -karma::buffer["\n" << edge_range[phx::bind(&Extractor::getEdgeRange, ex, karma::_val, karma::_1)]] + << -karma::buffer["\n" << (cluster_pair % karma::eol)[phx::bind(&Extractor::getClusterRange, ex, karma::_val, karma::_1)]] << "-\n" + << ""; + + cluster_pair %= karma::lit("+" + << karma::attr_cast(cluster); + + start %= karma::lit("+") << cluster; +}; + +}//namespace dcm + +#endif //DCM_GENERATOR_H + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/indent.hpp b/src/Mod/Assembly/App/opendcm/moduleState/indent.hpp new file mode 100644 index 000000000000..6d731bca92cc --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/indent.hpp @@ -0,0 +1,63 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_INDENT_H +#define DCM_INDENT_H + +#include +#include +#include + +class indent_filter : public boost::iostreams::output_filter { +public: + explicit indent_filter() : indent(0) {}; + + template + bool put(Sink& dest, int c) { + + if(c == '+') { + indent++; + return true; + } else if(c == '-') { + indent--; + return true; + } else if(c == '\n') { + bool ret = boost::iostreams::put(dest, c); + for(int i=0; (i + void close(Source&) { + indent = 0; + } +private: + int indent; +}; + +#endif //DCM_INDENT_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp b/src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp new file mode 100644 index 000000000000..1bff3f084069 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/karma_trans.hpp @@ -0,0 +1,155 @@ +/*////////////////////////////////////////////////////////////////////////////// + Copyright (c) 2011 Jamboree + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +//////////////////////////////////////////////////////////////////////////////*/ +#ifndef BOOST_SPIRIT_REPOSITORY_KARMA_TRANS +#define BOOST_SPIRIT_REPOSITORY_KARMA_TRANS + + +#if defined(_MSC_VER) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace boost { namespace spirit { namespace repository +{ + namespace tag + { + struct trans {}; + } + + namespace karma + { + // enables trans(f)[...] + template + inline + spirit::stateful_tag_type trans(F f) + { + return spirit::stateful_tag_type(f); + } + + // enables trans(f)[...] + template + inline + spirit::stateful_tag_type trans(F f) + { + return spirit::stateful_tag_type(f); + } + } +}}} + + +namespace boost { namespace spirit +{ + /////////////////////////////////////////////////////////////////////////// + // Enablers + /////////////////////////////////////////////////////////////////////////// + // enables trans(f)[...] + template + struct use_directive > + : mpl::true_ {}; +}} // namespace boost::spirit + + +namespace boost { namespace spirit { namespace repository {namespace karma +{ + template + struct trans_directive + : spirit::karma::unary_generator > + { + typedef Subject subject_type; + + template + struct attribute + : mpl::eval_if + < + is_same + , traits::attribute_of + , mpl::identity + > + {}; + + trans_directive(Subject const& subject, F f) + : subject(subject), f(f) + {} + + template + < + typename OutputIterator, typename Context + , typename Delimiter, typename Attribute + > + bool generate + ( + OutputIterator& sink, Context& ctx, Delimiter const& d + , Attribute const& attr) const + { + return subject.generate(sink, ctx, d, f(attr)); + } + + template + info what(Context& context) const + { + return info("trans", subject.what(context)); + } + + Subject subject; + F f; + }; +}}}} // namespace boost::spirit::repository::karma + + +namespace boost { namespace spirit { namespace karma +{ + /////////////////////////////////////////////////////////////////////////// + // Generator generators: make_xxx function (objects) + /////////////////////////////////////////////////////////////////////////// + template + struct make_directive, Subject, Modifiers> + { + typedef repository::karma::trans_directive result_type; + + template + result_type operator()( + StatefulTag const& tag, Subject const& subject, unused_type) const + { + return result_type(subject, tag.data_); + } + }; +}}} // namespace boost::spirit::karma + + +namespace boost { namespace spirit { namespace traits +{ + /////////////////////////////////////////////////////////////////////////// + template + struct has_semantic_action > + : unary_has_semantic_action {}; + + /////////////////////////////////////////////////////////////////////////// + template + struct handles_container + < + repository::karma::trans_directive + , Attribute, Context, Iterator + > + : mpl::false_ {}; // FIXME +}}} // namespace boost::spirit::traits + + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/module.hpp b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp new file mode 100644 index 000000000000..c3a3a4d13685 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp @@ -0,0 +1,98 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULE_STATE_H +#define DCM_MODULE_STATE_H + +#include + +#include "indent.hpp" +#include "generator.hpp" +#include "parser.hpp" +#include "defines.hpp" + +#include +#include + +namespace qi = boost::spirit::qi; + +namespace dcm { + +struct ModuleState { + + template + struct type { + + typedef Unspecified_Identifier Identifier; + + struct inheriter { + + inheriter() { + m_this = (Sys*) this; + }; + + Sys* m_this; + + void saveState(std::ostream& stream) { + + boost::iostreams::filtering_ostream indent_stream; + indent_stream.push(indent_filter()); + indent_stream.push(stream); + + std::ostream_iterator out(indent_stream); + generator gen; + + karma::generate(out, gen, *m_this->m_cluster); + }; + + void loadState(std::istream& stream) { + + //disable skipping of whitespace + stream.unsetf(std::ios::skipws); + + // wrap istream into iterator + boost::spirit::istream_iterator begin(stream); + boost::spirit::istream_iterator end; + + // use iterator to parse file data + parser par; + m_this->clear(); + typename Sys::Cluster* cl_ptr = m_this->m_cluster.get(); + qi::phrase_parse(begin, end, par(m_this), qi::space, cl_ptr); + }; + }; + + + //add only a property to the cluster as we need it to store the clusers global vertex + typedef mpl::vector1 properties; + typedef mpl::vector0<> objects; + + //nothing to do on startup + static void system_init(Sys& sys) {}; + }; +}; + +} + +#endif //DCM_MODULE_STATE_H + + + + + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp new file mode 100644 index 000000000000..85a50bb99ad6 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp @@ -0,0 +1,72 @@ +#ifndef DCM_OBJECT_GENERATOR_H +#define DCM_OBJECT_GENERATOR_H + +#include "property_generator.hpp" + +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + + +namespace details { + + //grammar for a single object + template + struct obj_grammar : public karma::grammar()> { + typename Gen::generator subrule; + karma::rule()> start; + details::prop_gen prop; + + obj_grammar(); + static void getProperties(boost::shared_ptr ptr, typename details::pts::type& seq); + }; + + //when objects should not be generated we need to get a empy rule, as obj_rule_init + //trys always to access the rules attribute and when the parser_generator trait is not + //specialitzed it's impossible to have the attribute type right in the unspecialized trait + template + struct obj_generator_fold : mpl::fold< seq, state, + mpl::if_< parser_generate, + mpl::push_back > >, + mpl::push_back > > {}; + + //currently max. 10 objects are supported + template + struct obj_gen : public karma::grammar::type()> { + + typedef typename Sys::objects ObjectList; + + //create a vector with the appropriate rules for all objects. Do this with the rule init struct, as it gives + //automatic initialisation of the rules when the objects are created + typedef typename obj_generator_fold >::type init_rules_vector; + //push back a empty rule so that we know where to go when nothing is to do + typedef typename mpl::push_back::type rules_vector; + + //create the fusion sequence of our rules + typedef typename fusion::result_of::as_vector::type rules_sequnce; + + //this struct returns the right accessvalue for the sequences. If we access a value bigger than the property vector size + //we use the last rule, as we made sure this is an empty one + template + struct index : public mpl::if_< mpl::less, mpl::size >, + mpl::int_, typename mpl::size::prior >::type {}; + //this struct tells us if we should execute the generator + template + struct valid : public mpl::less< mpl::int_, mpl::size > {}; + + rules_sequnce rules; + karma::rule::type()> obj; + + obj_gen(); + }; +} //namespace details +}//dcm + +#ifndef USE_EXTERNAL + #include "object_generator_imp.hpp" +#endif + +#endif //DCM_OBJECT_GENERATOR_H \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp new file mode 100644 index 000000000000..1114f19e88b8 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp @@ -0,0 +1,57 @@ +#ifndef DCM_OBJECT_GENERATOR_IMP_H +#define DCM_OBJECT_GENERATOR_IMP_H + + +#include "traits_impl.hpp" +#include "object_generator.hpp" +#include "property_generator_imp.hpp" + +using namespace boost::spirit::karma; +namespace karma = boost::spirit::karma; +namespace phx = boost::phoenix; +namespace fusion = boost::fusion; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + + +namespace details { + +template +obj_grammar::obj_grammar() : obj_grammar::base_type(start) { + Gen::init(subrule); + start = lit("\n") << '+' << eol << subrule + << prop[phx::bind(&obj_grammar::getProperties, _val, karma::_1)] + << '-' << eol << lit(""); +}; + +template +void obj_grammar::getProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { + + if(ptr) seq = ptr->m_properties; + else { + //TODO: throw + }; +}; + +template +obj_gen::obj_gen() : obj_gen::base_type(obj) { + + obj = -(eps(valid<0>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<1>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<2>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<3>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<4>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<5>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<6>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<7>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<8>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]) + << -(eps(valid<9>::value) << eps(phx::at_c::value>(_val)) << fusion::at >(rules)[karma::_1 = phx::at_c::value>(_val)]); + +}; + +} //namespace details +}//dcm + +#endif //DCM_OBJECT_GENERATOR_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp new file mode 100644 index 000000000000..ab4525865b09 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp @@ -0,0 +1,98 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_OBJECT_PARSER_H +#define DCM_OBJECT_PARSER_H + +#include "property_parser.hpp" + +namespace dcm { +namespace details { + +template +struct empty_obj_parser : public qi::grammar(Sys*), qi::space_type> { + qi::rule(Sys*), qi::space_type> start; + empty_obj_parser(): empty_obj_parser::base_type(start) { + //start = qi::eps(false); +}; +}; + +//grammar for a single object +template +struct obj_parser : public qi::grammar(Sys*), qi::space_type> { + typename Par::parser subrule; + qi::rule(Sys*), qi::space_type> start; + prop_par prop; + + obj_parser(); + + static void setProperties(boost::shared_ptr ptr, typename details::pts::type& seq); +}; + +//when objects should not be generated we need to get a empy rule, as obj_rule_init +//trys always to access the rules attribute and when the parser_generator trait is not +//specialitzed it's impossible to have the attribute type right in the unspecialized trait +template +struct obj_parser_fold : mpl::fold< seq, state, + mpl::if_< parser_parse, + mpl::push_back > >, + mpl::push_back > > > {}; + +//currently max. 10 objects are supported +template +struct obj_par : public qi::grammar::type(Sys*), + qi::space_type> { + + typedef typename Sys::objects ObjectList; + + //create a vector with the appropriate rules for all objects. Do this with the rule init struct, as it gives + //automatic initialisation of the rules when the objects are created + typedef typename obj_parser_fold >::type init_rules_vector; + //push back a empty rule so that we know where to go when nothing is to do + typedef typename mpl::push_back::type, Sys> >::type rules_vector; + + //create the fusion sequence of our rules + typedef typename fusion::result_of::as_vector::type rules_sequnce; + + //this struct returns the right accessvalue for the sequences. If we access a value bigger than the property vector size + //we use the last rule, as we made sure this is an empty one + template + struct index : public mpl::if_< mpl::less, mpl::size >, + mpl::int_, typename mpl::size::prior >::type {}; + //this struct tells us if we should execute the generator + template + struct valid : public mpl::less< mpl::int_, mpl::size > {}; + + rules_sequnce rules; + qi::rule::type(Sys*), qi::space_type> obj; + + obj_par(); + }; + +}//details +}//DCM + +#ifndef USE_EXTERNAL + #include "property_parser_imp.hpp" +#endif + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp new file mode 100644 index 000000000000..4ee6027612d7 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp @@ -0,0 +1,63 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_OBJECT_PARSER_IMP_H +#define DCM_OBJECT_PARSER_IMP_H + +#include "object_parser.hpp" +#include "property_parser_imp.hpp" + +namespace dcm { +namespace details { + +template +obj_parser::obj_parser(): obj_parser::base_type(start) { + Par::init(subrule); + start = qi::lit("") >> subrule(qi::_r1)[qi::_val = qi::_1] + >> qi::eps(qi::_val)[ phx::bind(&Sys::template push_back, qi::_r1, qi::_val)] + >> prop[phx::bind(&obj_parser::setProperties, qi::_val, qi::_1)] + >> qi::lit(""); +}; + +template +void obj_parser::setProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { + if(ptr) ptr->m_properties = seq; +}; + +template +obj_par::obj_par(): obj_par::base_type(obj) { + + obj = -(qi::eps(valid<0>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<1>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<2>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<3>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<4>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<5>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<6>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<7>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<8>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) + >> -(qi::eps(valid<9>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]); + +}; + +}//details +}//DCM + + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp new file mode 100644 index 000000000000..1ff58c444e55 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp @@ -0,0 +1,82 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PARSER_H +#define DCM_PARSER_H + +#include + +#include +#include +#include +#include + +#include "opendcm/core/clustergraph.hpp" + +#include "property_parser.hpp" +#include "object_parser.hpp" +#include "edge_vertex_parser.hpp" +#include "extractor.hpp" + +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; +namespace phx = boost::phoenix; + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +struct sp : qi::grammar { + + qi::rule start; + sp() : sp::base_type(start) { + start %= +qi::char_; +}; +static void print(std::string s) { + std::cout<<"parsed string:"< +struct parser : qi::grammar, qi::space_type> { + + typedef typename Sys::Cluster graph; + + parser(); + + qi::rule, qi::space_type> cluster; + details::cluster_prop_par cluster_prop; + + details::obj_par objects; + + details::vertex_parser vertex; + details::edge_parser edge; + + sp str; + Injector in; +}; + +} + +#ifndef USE_EXTERNAL +#include "parser_imp.hpp" +#endif + +#endif //DCM_PARSER_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp new file mode 100644 index 000000000000..6b9f42b81298 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp @@ -0,0 +1,71 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PARSER_IMP_H +#define DCM_PARSER_IMP_H + +#include + +#include "opendcm/core/system.hpp" + +#include +#include +#include + +BOOST_FUSION_ADAPT_TPL_STRUCT( + (T1)(T2)(T3)(T4), + (dcm::ClusterGraph) (T1)(T2)(T3)(T4), + (typename dcm::details::pts::type, m_cluster_bundle)) + +#include "parser.hpp" + + +namespace boost { namespace spirit { namespace traits +{ + template + struct transform_attribute*, dcm::ClusterGraph, qi::domain> + { + typedef dcm::ClusterGraph& type; + static type pre(dcm::ClusterGraph* const& val) { + return *val; + } + static void post(dcm::ClusterGraph* const& val, dcm::ClusterGraph const& attr) {} + static void fail(dcm::ClusterGraph* const&) {} + }; +}}} + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +template +parser::parser() : parser::base_type(cluster) { + + cluster %= qi::lit("" + >> -(qi::eps( qi::_a > 0 )[qi::_val = phx::new_()]) + >> qi::eps[phx::bind(&Injector::setVertexProperty, in, qi::_val, qi::_a)] + >> qi::attr_cast(cluster_prop >> qi::eps) + >> qi::omit[*vertex(qi::_val, qi::_r1)] + >> qi::omit[*edge(qi::_val, qi::_r1)] + >> qi::omit[*(cluster(qi::_r1)[phx::bind(&Injector::addCluster, in, qi::_val, qi::_1)])] + >> "";// >> str[&sp::print]; +}; + +} +#endif //DCM_PARSER_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp new file mode 100644 index 000000000000..5637679a6d15 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp @@ -0,0 +1,102 @@ +#ifndef DCM_PROPERTY_GENERATOR_H +#define DCM_PROPERTY_GENERATOR_H + +#include +#include + +#include +#include +#include +#include + +#include "traits.hpp" + +namespace karma = boost::spirit::karma; +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +namespace details { + +//a grammar that does nothing exept failing +struct empty_grammar : public karma::grammar { + karma::rule start; + empty_grammar(): empty_grammar::base_type(start) { + start = karma::eps(true); + }; + empty_grammar(const empty_grammar& other) : empty_grammar::base_type(start) {}; +}; + +template +struct skip_grammar : public karma::grammar { + karma::rule start; + skip_grammar() : skip_grammar::base_type(start) { + start = karma::eps(true); + }; + skip_grammar(const skip_grammar& other) : skip_grammar::base_type(start) {}; +}; + +//grammar for a single property +template +struct prop_grammar : public karma::grammar { + typename Gen::generator subrule; + karma::rule start; + prop_grammar(); + prop_grammar(const prop_grammar& other) : prop_grammar::base_type(start) {}; +}; + +template +struct prop_generator_fold : mpl::fold< seq, state, + mpl::if_< parser_generate, + mpl::push_back > >, + mpl::push_back > > > {}; + +//grammar for a fusion sequence of properties. currently max. 10 properties are supported +template +struct prop_gen : karma::grammar::type&()> { + + //create a vector with the appropriate rules for all properties. + typedef typename prop_generator_fold >::type init_rules_sequence; + //allow max 10 types as the following code expect this + BOOST_MPL_ASSERT((mpl::less_equal< mpl::size, mpl::int_<10> >)); + //we want to process 10 elements, so create a vector with (10-prop.size()) empty rules + //and append it to our rules vector + typedef mpl::range_c, mpl::size >::value > range; + typedef typename mpl::fold< range, + init_rules_sequence, + mpl::push_back >::type rules_sequence; + + typename fusion::result_of::as_vector::type rules; + karma::rule::type&()> prop; + + prop_gen(); +}; + +//special prop classes for better externalisaton, therefore the outside constructor to avoid auto inline +template +struct cluster_prop_gen : public prop_gen { + cluster_prop_gen(); +}; + +template +struct vertex_prop_gen : public prop_gen { + vertex_prop_gen(); +}; + +template +struct edge_prop_gen : public prop_gen { + edge_prop_gen(); +}; + +}//details +}//dcm + +#ifndef USE_EXTERNAL +#include "property_generator_imp.hpp" +#endif + +#endif //DCM_PROPERTY_GENERATOR_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp new file mode 100644 index 000000000000..38fa4ed74989 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_generator_imp.hpp @@ -0,0 +1,43 @@ +#ifndef DCM_PROPERTY_GENERATOR_IMP_H +#define DCM_PROPERTY_GENERATOR_IMP_H + +#include "property_generator.hpp" +#include "traits_impl.hpp" + +namespace dcm { + +typedef std::ostream_iterator Iterator; + +namespace details { + +//grammar for a single property +template +prop_grammar::prop_grammar() : prop_grammar::base_type(start) { + + Gen::init(subrule); + start = karma::lit("\n") << '+' << karma::eol << subrule + << '-' << karma::eol << karma::lit(""); +}; + +template +prop_gen::prop_gen() : prop_gen::base_type(prop) { + + prop = fusion::at_c<0>(rules) << fusion::at_c<1>(rules) << fusion::at_c<2>(rules) + << fusion::at_c<3>(rules) << fusion::at_c<4>(rules) << fusion::at_c<5>(rules) + << fusion::at_c<6>(rules) << fusion::at_c<7>(rules) << fusion::at_c<8>(rules) + << fusion::at_c<9>(rules); +}; + +template +cluster_prop_gen::cluster_prop_gen() : prop_gen() {}; + +template +vertex_prop_gen::vertex_prop_gen() : prop_gen() {}; + +template +edge_prop_gen::edge_prop_gen() : prop_gen() {}; + +}//details +}//dcm + +#endif //DCM_PROPERTY_GENERATOR_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp new file mode 100644 index 000000000000..6e404bfa87e1 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp @@ -0,0 +1,120 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PROPERTY_PARSER_H +#define DCM_PROPERTY_PARSER_H + +#include +#include +#include +#include + +#include +#include + +namespace fusion = boost::fusion; +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; +namespace phx = boost::phoenix; +namespace mpl = boost::mpl; + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +namespace details { + +struct empty_parser : public qi::grammar { + qi::rule start; + empty_parser(): empty_parser::base_type(start) { + start = qi::eps(true); + }; + empty_parser(const empty_parser& other) : empty_parser::base_type(start) {}; +}; + +template +struct skip_parser : public qi::grammar { + qi::rule start; + skip_parser() : skip_parser::base_type(start) { + start = qi::eps(true); + }; + skip_parser(const skip_parser& other) : skip_parser::base_type(start) {}; +}; + +template +struct prop_parser : qi::grammar { + + typename Par::parser subrule; + qi::rule start; + prop_parser(); + prop_parser(const prop_parser& other) : prop_parser::base_type(start) {}; +}; + +template +struct prop_parser_fold : mpl::fold< seq, state, + mpl::if_< dcm::parser_parse, + mpl::push_back > >, + mpl::push_back > > > {}; + +//grammar for a fusion sequence of properties. currently max. 10 properties are supported +template +struct prop_par : qi::grammar::type(), qi::space_type> { + + //create a vector with the appropriate rules for all properties. + typedef typename prop_parser_fold >::type init_rules_sequence; + //allow max 10 types as the following code expect this + BOOST_MPL_ASSERT((mpl::less_equal< mpl::size, mpl::int_<10> >)); + //we want to process 10 elements, so create a vector with (10-prop.size()) empty rules + //and append it to our rules vector + typedef mpl::range_c, mpl::size >::value > range; + typedef typename mpl::fold< range, + init_rules_sequence, + mpl::push_back >::type rules_sequence; + + typename fusion::result_of::as_vector::type rules; + qi::rule::type(), qi::space_type> prop; + + prop_par(); +}; + + //special prop classes for better externalisaton, therefore the outside constructor to avoid auto inline + template + struct cluster_prop_par : public prop_par { + cluster_prop_par(); + }; + + template + struct vertex_prop_par : public prop_par { + vertex_prop_par(); + }; + + template + struct edge_prop_par : public prop_par { + edge_prop_par(); + }; + +} //DCM +} //details + +#ifndef USE_EXTERNAL + #include "property_parser_imp.hpp" +#endif + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp new file mode 100644 index 000000000000..4fa920c8d64c --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp @@ -0,0 +1,60 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PROPERTY_PARSER_IMP_H +#define DCM_PROPERTY_PARSER_IMP_H + +#include "property_parser.hpp" + + +namespace dcm { + +typedef boost::spirit::istream_iterator IIterator; + +namespace details { + +template +prop_parser::prop_parser() : prop_parser::base_type(start) { + Par::init(subrule); + start %= qi::lit("") >> subrule >> qi::lit(""); +}; + + +template +prop_par::prop_par() : prop_par::base_type(prop) { + + prop %= fusion::at_c<0>(rules) >> fusion::at_c<1>(rules) >> fusion::at_c<2>(rules) + >> fusion::at_c<3>(rules) >> fusion::at_c<4>(rules) >> fusion::at_c<5>(rules) + >> fusion::at_c<6>(rules) >> fusion::at_c<7>(rules) >> fusion::at_c<8>(rules) + >> fusion::at_c<9>(rules); +}; + +template +cluster_prop_par::cluster_prop_par() : prop_par() {}; + +template +vertex_prop_par::vertex_prop_par() : prop_par() {}; + +template +edge_prop_par::edge_prop_par() : prop_par() {}; + +} //DCM +} //details + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp b/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp new file mode 100644 index 000000000000..94c4a9b4afd8 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp @@ -0,0 +1,53 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_PARSER_TRAITS_H +#define DCM_PARSER_TRAITS_H + +#include +#include + +namespace dcm { + +template +struct parser_generate : public boost::mpl::false_ {}; + +template +struct parser_generator { + typedef int generator; + + static void init(generator& r) { + assert(false); + }; +}; + +template +struct parser_parse : public boost::mpl::false_ {}; + +template +struct parser_parser { + typedef int parser; + + static void init(parser& r) { + assert(false); + }; +}; + +} +#endif //DCM_PARSER_TRAITS_H diff --git a/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp b/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp new file mode 100644 index 000000000000..bb49a7eb9439 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp @@ -0,0 +1,160 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +//move the traits specializations outside of the traits definition to avoid the spirit header parsing every +//time this module is included and just parse it in externalisation mode when the generator is build + +#ifndef DCM_PARSER_TRAITS_IMPL_H +#define DCM_PARSER_TRAITS_IMPL_H + +#include "traits.hpp" +#include "defines.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace karma = boost::spirit::karma; +namespace qi = boost::spirit::qi; + +namespace boost { +namespace spirit { +namespace traits { +template <> +struct create_generator { + + typedef BOOST_TYPEOF(karma::eps(false)) type; + static type call() { + return karma::eps(false); + } +}; +} +} +} + +namespace dcm { + + template +struct parser_generate : public mpl::true_ {}; + +template +struct parser_generator { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("clustertype\n") << karma::int_ <<""; + }; +}; + +template +struct parser_generate : public mpl::true_ {}; + +template +struct parser_generator { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("clusterchanged\n") << karma::bool_ <<""; + }; +}; + +template +struct parser_generate, System> + : public mpl::not_ > {}; + +template +struct parser_generator, System, iterator> { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("id\n") << karma::auto_ <<""; + }; +}; + + template +struct parser_parse : public mpl::true_ {}; + +template +struct parser_parser { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("clustertype") >> ("") >> qi::int_ >>""; + }; +}; + +template +struct parser_parse : public mpl::true_ {}; + +template +struct parser_parser { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("clusterchanged") >> ("") >> qi::bool_ >>""; + }; +}; + +template +struct parser_parse, System> + : public mpl::not_ > {}; + +template +struct parser_parser, System, iterator> { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("id") >> ("") >> qi::auto_ >>""; + }; +}; +/* +template +struct parser_generate + : public mpl::true_ {}; + +template +struct parser_generator { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("id\n") << karma::int_ <<""; + }; +}; + +template +struct parser_parse : public mpl::true_ {}; + +template +struct parser_parser { + typedef qi::rule parser; + + static void init(parser& r) { + r = qi::lit("id") >> ("") >> qi::int_ >>""; + }; +};*/ + +} //namespace dcm + +#endif //DCM_PARSER_TRAITS_IMPL_H \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/modulepart.hpp b/src/Mod/Assembly/App/opendcm/modulepart.hpp new file mode 100644 index 000000000000..b121ea2e322d --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulepart.hpp @@ -0,0 +1,29 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULEPART_H +#define DCM_MODULEPART_H + +#define DCM_USE_MODULEPART + +#include "modulePart/geometry.hpp" +#include "modulePart/module.hpp" + +#endif //DCM_MODULEPART_H + diff --git a/src/Mod/Assembly/App/opendcm/modulestate.hpp b/src/Mod/Assembly/App/opendcm/modulestate.hpp new file mode 100644 index 000000000000..3b5ef5f07499 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/modulestate.hpp @@ -0,0 +1,29 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULEPARSER_H +#define DCM_MODULEPARSER_H + +#define DCM_USE_MODULESTATE + +#include "moduleState/module.hpp" +#include "moduleState/traits.hpp" + +#endif //DCM_MODULEPARSER_H + From b1d7dbe2f04f4f040b2992a420aa90463dcf2121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 29 Apr 2013 23:08:37 +0200 Subject: [PATCH 048/664] add missing files --- src/Mod/Assembly/App/ConstraintAxisPy.xml | 17 ++++++++++++ src/Mod/Assembly/App/ConstraintAxisPyImp.cpp | 29 ++++++++++++++++++++ src/Mod/Assembly/App/ConstraintPy.xml | 17 ++++++++++++ src/Mod/Assembly/App/ConstraintPyImp.cpp | 29 ++++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 src/Mod/Assembly/App/ConstraintAxisPy.xml create mode 100644 src/Mod/Assembly/App/ConstraintAxisPyImp.cpp create mode 100644 src/Mod/Assembly/App/ConstraintPy.xml create mode 100644 src/Mod/Assembly/App/ConstraintPyImp.cpp diff --git a/src/Mod/Assembly/App/ConstraintAxisPy.xml b/src/Mod/Assembly/App/ConstraintAxisPy.xml new file mode 100644 index 000000000000..d54b6080f4c2 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAxisPy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all objects in Assembly + + + diff --git a/src/Mod/Assembly/App/ConstraintAxisPyImp.cpp b/src/Mod/Assembly/App/ConstraintAxisPyImp.cpp new file mode 100644 index 000000000000..a9a0d06bd089 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAxisPyImp.cpp @@ -0,0 +1,29 @@ + +#include "PreCompiled.h" + +#include "Mod/Assembly/App/Constraint.h" + +// inclusion of the generated files (generated out of ItemAssemblyPy.xml) +#include "ConstraintAxisPy.h" +#include "ConstraintAxisPy.cpp" + +using namespace Assembly; + +// returns a string which represents the object e.g. when printed in python +std::string ConstraintAxisPy::representation(void) const +{ + return std::string(""); +} + + +PyObject *ConstraintAxisPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ConstraintAxisPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + diff --git a/src/Mod/Assembly/App/ConstraintPy.xml b/src/Mod/Assembly/App/ConstraintPy.xml new file mode 100644 index 000000000000..4995027614d7 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintPy.xml @@ -0,0 +1,17 @@ + + + + + + Base class of all objects in Assembly + + + diff --git a/src/Mod/Assembly/App/ConstraintPyImp.cpp b/src/Mod/Assembly/App/ConstraintPyImp.cpp new file mode 100644 index 000000000000..e763ea29aedf --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintPyImp.cpp @@ -0,0 +1,29 @@ + +#include "PreCompiled.h" + +#include "Mod/Assembly/App/Constraint.h" + +// inclusion of the generated files (generated out of ItemAssemblyPy.xml) +#include "ConstraintPy.h" +#include "ConstraintPy.cpp" + +using namespace Assembly; + +// returns a string which represents the object e.g. when printed in python +std::string ConstraintPy::representation(void) const +{ + return std::string(""); +} + + +PyObject *ConstraintPy::getCustomAttributes(const char* /*attr*/) const +{ + return 0; +} + +int ConstraintPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} + + From bf447d3a7ca581199d435cc4e8ebbaff7f85af10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Wed, 1 May 2013 19:25:23 +0200 Subject: [PATCH 049/664] add solver.hpp --- src/Mod/Assembly/App/ConstraintGroup.cpp | 6 +- src/Mod/Assembly/App/Solver.h | 335 +++++++++++++++++ .../Assembly/App/opendcm/core/constraint.hpp | 11 +- .../Assembly/App/opendcm/core/equations.hpp | 127 +++++-- .../App/opendcm/module3d/distance.hpp | 353 +++++++++++++++--- .../Assembly/App/opendcm/module3d/module.hpp | 61 +-- .../App/opendcm/module3d/parallel.hpp | 305 ++++++++++----- 7 files changed, 983 insertions(+), 215 deletions(-) create mode 100644 src/Mod/Assembly/App/Solver.h diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp index 71fe93f0abf1..2241be58e029 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.cpp +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -66,7 +66,7 @@ void ConstraintGroup::addConstraint(Constraint* c) //let's retrieve the solver if not already done ItemAssembly* assembly = NULL; - if(!m_solver) { + if(!m_solver || !assembly) { typedef std::vector::iterator iter; std::vector vec = getInList(); @@ -86,6 +86,10 @@ void ConstraintGroup::addConstraint(Constraint* c) Base::Console().Message("ConstraintGroup: Unable to retrieve assembly solver\n"); return; }; + if(!assembly) { + Base::Console().Message("ConstraintGroup: Unable to retrieve assembly\n"); + return; + }; //init the constraint c->init(m_solver); diff --git a/src/Mod/Assembly/App/Solver.h b/src/Mod/Assembly/App/Solver.h new file mode 100644 index 000000000000..5948b716752f --- /dev/null +++ b/src/Mod/Assembly/App/Solver.h @@ -0,0 +1,335 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 SOLVER_H +#define SOLVER_H + +#include + +#include +#include +#include +#include +#include + +#include "opendcm/core.hpp" +#include "opendcm/module3d.hpp" +#include "opendcm/modulepart.hpp" + +struct gp_pnt_accessor { + + template + Scalar get(T& t) { + switch(ID) { + case 0: + return t.X(); + case 1: + return t.Y(); + case 2: + return t.Z(); + default: + return 0; + }; + }; + template + void set(Scalar value, T& t) { + switch(ID) { + case 0: + t.SetX(value); + break; + case 1: + t.SetY(value); + break; + case 2: + t.SetZ(value); + break; + }; + }; +}; + +struct gp_lin_accessor { + + template + Scalar get(T& t) { + switch(ID) { + case 0: + return t.Location().X(); + case 1: + return t.Location().Y(); + case 2: + return t.Location().Z(); + case 3: + return t.Direction().X(); + case 4: + return t.Direction().Y(); + case 5: + return t.Direction().Z(); + default: + return 0; + }; + }; + template + void set(Scalar value, T& t) { + gp_Pnt p = t.Location(); + gp_Dir d = t.Direction(); + switch(ID) { + case 0: + p.SetX(value); + break; + case 1: + p.SetY(value); + break; + case 2: + p.SetZ(value); + case 3: + d.SetX(value); + break; + case 4: + d.SetY(value); + break; + case 5: + d.SetZ(value); + break; + }; + t.SetLocation(p); + t.SetDirection(d); + }; +}; + +struct gp_pln_accessor { + + template + Scalar get(T& t) { + switch(ID) { + case 0: + return t.Axis().Location().X(); + case 1: + return t.Axis().Location().Y(); + case 2: + return t.Axis().Location().Z(); + case 3: + return t.Axis().Direction().X(); + case 4: + return t.Axis().Direction().Y(); + case 5: + return t.Axis().Direction().Z(); + default: + return 0; + }; + }; + template + void set(Scalar value, T& t) { + gp_Pnt p = t.Axis().Location(); + gp_Dir d = t.Axis().Direction(); + switch(ID) { + case 0: + p.SetX(value); + break; + case 1: + p.SetY(value); + break; + case 2: + p.SetZ(value); + case 3: + d.SetX(value); + break; + case 4: + d.SetY(value); + break; + case 5: + d.SetZ(value); + break; + }; + t.SetAxis(gp_Ax1(p,d)); + }; +}; + +struct gp_cylinder_accessor { + + template + Scalar get(T& t) { + switch(ID) { + case 0: + return t.Axis().Location().X(); + case 1: + return t.Axis().Location().Y(); + case 2: + return t.Axis().Location().Z(); + case 3: + return t.Axis().Direction().X(); + case 4: + return t.Axis().Direction().Y(); + case 5: + return t.Axis().Direction().Z(); + case 6: + return t.Radius(); + default: + return 0; + }; + }; + template + void set(Scalar value, T& t) { + gp_Pnt p = t.Axis().Location(); + gp_Dir d = t.Axis().Direction(); + switch(ID) { + case 0: + p.SetX(value); + break; + case 1: + p.SetY(value); + break; + case 2: + p.SetZ(value); + case 3: + d.SetX(value); + break; + case 4: + d.SetY(value); + break; + case 5: + d.SetZ(value); + break; + case 6: + t.SetRadius(value); + }; + t.SetAxis(gp_Ax1(p,d)); + }; +}; + +struct placement_accessor { + + double q0, q1, q2, q3; + Base::Vector3d vec; + + template + Scalar get(T& t) { + t.getRotation().getValue(q0,q1,q2,q3); + switch(ID) { + case 0: + return q3; + case 1: + return q0; + case 2: + return q1; + case 3: + return q2; + case 4: + return t.getPosition()[0]; + case 5: + return t.getPosition()[1]; + case 6: + return t.getPosition()[2]; + default: + return 0; + }; + }; + template + void set(Scalar value, T& t) { + switch(ID) { + case 0: + q3 = value; + break; + case 1: + q0 = value; + break; + case 2: + q1 = value; + break; + case 3: + q2 = value; + break; + case 4: + vec[0] = value; + break; + case 5: + vec[1] = value; + break; + case 6: + vec[2] = value; + break; + }; + }; + + template + void finalize(T& t) { + //need to do it at once as setting every value step by step would always normalize the rotation and + //therefor give a false value + Base::Rotation rot(q0,q1,q2,q3); + t.setRotation(rot); + t.setPosition(vec); + }; +}; + +//geometry_traits for opencascade +namespace dcm { +template<> +struct geometry_traits { + typedef tag::point3D tag; + typedef modell::XYZ modell; + typedef gp_pnt_accessor accessor; +}; +template<> +struct geometry_traits { + typedef tag::line3D tag; + typedef modell::XYZ2 modell; + typedef gp_lin_accessor accessor; +}; +template<> +struct geometry_traits { + typedef tag::plane3D tag; + typedef modell::XYZ2 modell; + typedef gp_pln_accessor accessor; +}; +template<> +struct geometry_traits { + typedef tag::cylinder3D tag; + typedef modell::XYZ2P modell; + typedef gp_cylinder_accessor accessor; +}; +template<> +struct geometry_traits { + typedef tag::part tag; + typedef modell::quaternion_wxyz_vec3 modell; + typedef placement_accessor accessor; +}; +template<> +struct geometry_traits { + typedef tag::point3D tag; + typedef modell::XYZ modell; + typedef orderd_bracket_accessor accessor; +}; +} + + +//our constraint solving system +typedef dcm::Kernel Kernel; +typedef dcm::Module3D< mpl::vector5< gp_Pnt, gp_Lin, gp_Pln, gp_Cylinder, SbVec3f>, std::string > Module3D; +typedef dcm::ModulePart< mpl::vector1< Base::Placement >, std::string > ModulePart; +typedef dcm::System Solver; + +typedef typename ModulePart::type::Part Part3D; +typedef typename Module3D::type::Geometry3D Geometry3D; +typedef typename Module3D::type::Constraint3D Constraint3D; + + +#endif //SOLVER_H \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index c2f74117fda3..6cb91602df55 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -73,7 +73,7 @@ class Constraint : public Object { protected: template - void initialize(typename fusion::result_of::as_vector::type& obj); + void initialize(ConstraintVector& obj); int equationCount(); @@ -125,7 +125,7 @@ class Constraint : public Object { mpl::push_back > >::type eq_set_vector; typedef typename fusion::result_of::as_vector::type EquationSets; - typedef typename fusion::result_of::as_vector::type Objects; + typedef ConstraintVector Objects; template struct has_option { @@ -135,7 +135,7 @@ class Constraint : public Object { typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; BOOST_MPL_ASSERT((mpl::not_::type > >)); - typedef typename mpl::at::type option_type; + typedef typename fusion::result_of::at::type option_type; typedef mpl::not_ > type; }; @@ -205,7 +205,7 @@ class Constraint : public Object { template< typename ConstraintVector > struct creator : public boost::static_visitor { - typedef typename fusion::result_of::as_vector::type Objects; + typedef ConstraintVector Objects; Objects& objects; creator(Objects& obj); @@ -272,7 +272,7 @@ boost::shared_ptr Constraint::clo template template -void Constraint::initialize(typename fusion::result_of::as_vector::type& obj) { +void Constraint::initialize(ConstraintVector& obj) { //first create the new placeholder creator c(obj); @@ -491,6 +491,7 @@ template template void Constraint::creator::operator()(const T1&, const T2&) { + typedef tag_order< typename geometry_traits::tag, typename geometry_traits::tag > order; //transform the constraints into eqautions with the now known types diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 0e391f48e811..4e078bf55d7f 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -22,6 +22,20 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fusion = boost::fusion; + +#include "kernel.hpp" + namespace dcm { struct no_option {}; @@ -44,18 +58,79 @@ struct PseudoScale { void setScale(typename Kernel::number_type scale) {}; }; -struct Distance { +//type to allow a metaprogramming check for a Equation +struct EQ {}; + +template +struct pushed_seq; + +template +struct op_seq : public seq { + + template + typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T val) { + + typedef typename pushed_seq::type Sequence; + typedef typename fusion::result_of::begin::type Begin; + typedef typename fusion::result_of::end::type End; + typedef typename fusion::result_of::prior::type EndOld; + + //create the new sequence + Sequence vec; + + //copy the old values into the new sequence + Begin b(vec); + EndOld eo(vec); + + fusion::iterator_range range(b, eo); + fusion::copy(*this, range); - typedef double option_type; + //insert this object at the end of the sequence + fusion::back(vec) = val; + + //and return our new extendet sequence + return vec; + }; +}; + +template +struct pushed_seq { + typedef typename boost::mpl::if_, Seq, fusion::vector1 >::type S; + typedef typename fusion::result_of::as_vector< typename boost::mpl::push_back::type >::type vec; + typedef op_seq type; +}; + +template +struct Equation : public EQ { + + typedef Option option_type; option_type value; - Distance() : value(0) {}; + Equation(option_type val = option_type()) : value(val) {}; - Distance& operator=(const option_type val) { + Derived& operator()(const option_type val) { value = val; - return *this; + return *(static_cast(this)); + }; + Derived& operator=(const option_type val) { + return operator()(val); }; + template + typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T val) { + + typename pushed_seq::type vec; + fusion::at_c<0>(vec) = val; + fusion::at_c<1>(vec) = *(static_cast(this)); + return vec; + }; +}; + +struct Distance : public Equation { + + using Equation::operator=; + Distance() : Equation(0) {}; + template< typename Kernel, typename Tag1, typename Tag2 > struct type { @@ -73,15 +148,15 @@ struct Distance { }; Scalar calculate(Vector& param1, Vector& param2) { assert(false); - return 0; + return 0; }; Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { assert(false); - return 0; + return 0; }; Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { assert(false); - return 0; + return 0; }; void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { assert(false); @@ -93,19 +168,12 @@ struct Distance { }; //the possible directions -enum Direction { Same, Opposite, Both }; - -struct Parallel { - - typedef Direction option_type; - option_type value; +enum Direction { equal, opposite, parallel, perpendicular }; - Parallel() : value(Both) {}; +struct Orientation : public Equation { - Parallel& operator=(const option_type val) { - value = val; - return *this; - }; + using Equation::operator=; + Orientation() : Equation(parallel) {}; template< typename Kernel, typename Tag1, typename Tag2 > struct type : public PseudoScale { @@ -118,15 +186,15 @@ struct Parallel { //template definition Scalar calculate(Vector& param1, Vector& param2) { assert(false); - return 0; + return 0; }; Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { assert(false); - return 0; + return 0; }; Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { assert(false); - return 0; + return 0; }; void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { assert(false); @@ -137,17 +205,10 @@ struct Parallel { }; }; -struct Angle { - - typedef double option_type; - option_type value; - - Angle() : value(0) {}; +struct Angle : public Equation { - Angle& operator=(const option_type val) { - value = val; - return *this; - }; + using Equation::operator=; + Angle() : Equation(0) {}; template< typename Kernel, typename Tag1, typename Tag2 > struct type : public PseudoScale { @@ -180,7 +241,7 @@ struct Angle { //every compiled file including this header would define these as global and the linker would find //multiple definitions of the same objects static Distance distance; -static Parallel parallel; +static Orientation orientation; static Angle angle; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp index b36d30ad01dd..88fe8ab3ef3e 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -56,6 +56,108 @@ struct Distance::type< Kernel, tag::point3D, tag::point3D > { }; }; +template +struct Distance::type< Kernel, tag::point3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef typename Kernel::Vector3 Vector3; + typedef std::vector > Vec; + + Scalar value, sc_value; + Vector3 diff, n, dist; + +#ifdef USE_LOGGING + src::logger log; + attrs::mutable_constant< std::string > tag; + + type() : tag("Distance point3D line3D") { + log.add_attribute("Tag", tag); + }; +#endif + + //template definition + void calculatePseudo(typename Kernel::Vector& point, Vec& v1, typename Kernel::Vector& line, Vec& v2) { + Vector3 pp = line.head(3) + (line.head(3)-point.head(3)).norm()*line.template segment<3>(3); +#ifdef USE_LOGGING + if(!boost::math::isnormal(pp.norm())) + BOOST_LOG(log) << "Unnormal pseudopoint detected"; +#endif + v2.push_back(pp); + }; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + Scalar calculate(Vector& point, Vector& line) { + //diff = point1 - point2 + n = line.template segment<3>(3); + diff = line.template head<3>() - point.template head<3>(); + dist = diff - diff.dot(n)*n; + const Scalar res = dist.norm() - sc_value; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal residual detected: "<(); + const Vector3 d_dist = d_diff - d_diff.dot(n)*n; + const Scalar res = dist.dot(d_dist)/dist.norm(); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal first cluster gradient detected: "<(); + const Vector3 d_n = dline.template segment<3>(3); + const Vector3 d_dist = d_diff - ((d_diff.dot(n)+diff.dot(d_n))*n + diff.dot(n)*d_n); + const Scalar res = dist.dot(d_dist)/dist.norm(); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal second cluster gradient detected: "<(3) = -(mult*diff + diff.dot(n)*dist)/dist.norm(); + }; +}; + template struct Distance::type< Kernel, tag::point3D, tag::plane3D > { typedef typename Kernel::number_type Scalar; @@ -139,60 +241,82 @@ struct Distance::type< Kernel, tag::point3D, tag::plane3D > { }; }; - template -struct Distance::type< Kernel, tag::plane3D, tag::plane3D > : public Distance::type< Kernel, tag::point3D, tag::plane3D > { +struct Distance::type< Kernel, tag::point3D, tag::cylinder3D > : public Distance::type< Kernel, tag::point3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; #ifdef USE_LOGGING - type() : Distance::type< Kernel, tag::point3D, tag::plane3D >() { - Distance::type< Kernel, tag::point3D, tag::plane3D >::tag.set("Distance plane3D plane3D"); + type() { + Distance::type< Kernel, tag::point3D, tag::line3D >::tag.set("Distance point3D cylinder3D"); }; #endif - typedef typename Kernel::VectorMap Vector; - void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { - Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); - g.segment(3,3).setZero(); + Scalar calculate(Vector& param1, Vector& param2) { + //(p1-p2)°n / |n| - distance + const Scalar res = Distance::type< Kernel, tag::point3D, tag::line3D >::calculate(param1, param2); + return res - param2(6); + }; + + void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::line3D >::calculateGradientSecondComplete(p1,p2,g); + g(6) = -1; }; }; +//TODO: this won't work for parallel lines. switch to point-line distance when lines are parallel template -struct Distance::type< Kernel, tag::point3D, tag::line3D > { +struct Distance::type< Kernel, tag::line3D, tag::line3D > { typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; typedef typename Kernel::Vector3 Vector3; typedef std::vector > Vec; - Scalar value, sc_value; - Vector3 diff, n, dist; + Scalar value, sc_value, cdn; + Vector3 c, n1, n2, nxn; #ifdef USE_LOGGING src::logger log; attrs::mutable_constant< std::string > tag; - type() : tag("Distance point3D line3D") { + type() : tag("Distance line3D line3D") { log.add_attribute("Tag", tag); }; #endif //template definition - void calculatePseudo(typename Kernel::Vector& point, Vec& v1, typename Kernel::Vector& line, Vec& v2) { - Vector3 pp = line.head(3) + (line.head(3)-point.head(3)).norm()*line.segment(3,3); + void calculatePseudo(typename Kernel::Vector& line1, Vec& v1, typename Kernel::Vector& line2, Vec& v2) { + + //add the line points of shortest distance as pseudopoints + const Vector3 c = line2.template head<3>() - line1.template head<3>(); + const Vector3 n1 = line1.template segment<3>(3); + const Vector3 n2 = line2.template segment<3>(3); + const Vector3 nxn = n1.cross(n2); + const Vector3 r = c.cross(nxn)/nxn.squaredNorm(); + Vector3 pp1 = line1.template head<3>() + r.dot(n2)*n1; + Vector3 pp2 = line2.template head<3>() + r.dot(n1)*n2; + #ifdef USE_LOGGING - if(!boost::math::isnormal(pp.norm())) + if(!boost::math::isfinite(pp1.norm()) || !boost::math::isfinite(pp2.norm())) BOOST_LOG(log) << "Unnormal pseudopoint detected"; #endif - v2.push_back(pp); + + v1.push_back(pp1); + v2.push_back(pp2); + }; void setScale(Scalar scale) { sc_value = value*scale; }; - Scalar calculate(Vector& point, Vector& line) { + Scalar calculate(Vector& line1, Vector& line2) { //diff = point1 - point2 - n = line.template segment<3>(3); - diff = line.template head<3>() - point.template head<3>(); - dist = diff - diff.dot(n)*n; - const Scalar res = dist.norm() - sc_value; + n1 = line1.template segment<3>(3); + n2 = line2.template segment<3>(3); + nxn = n1.cross(n2); + c = line2.template head<3>() - line1.template head<3>(); + cdn = c.dot(nxn); + const Scalar res = std::abs(cdn) / nxn.norm(); #ifdef USE_LOGGING if(!boost::math::isfinite(res)) BOOST_LOG(log) << "Unnormal residual detected: "< { return res; }; - Scalar calculateGradientFirst(Vector& point, Vector& line, Vector& dpoint) { - if(dist.norm() == 0) + Scalar calculateGradientFirst(Vector& line1, Vector& line2, Vector& dline1) { + if(nxn.norm() == 0) return 1.; - const Vector3 d_diff = -dpoint.template head<3>(); - const Vector3 d_dist = d_diff - d_diff.dot(n)*n; - const Scalar res = dist.dot(d_dist)/dist.norm(); + const Vector3 nxn_diff = dline1.template segment<3>(3).cross(n2); + Scalar diff = (-dline1.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn.norm(); + diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn.norm(); + + //absoulute value requires diffrent differentation for diffrent results + if(cdn <= 0) diff *= -1; + + diff /= std::pow(nxn.norm(),2); + #ifdef USE_LOGGING - if(!boost::math::isfinite(res)) - BOOST_LOG(log) << "Unnormal first cluster gradient detected: "<(); - const Vector3 d_n = dline.template segment<3>(3); - const Vector3 d_dist = d_diff - ((d_diff.dot(n)+diff.dot(d_n))*n + diff.dot(n)*d_n); - const Scalar res = dist.dot(d_dist)/dist.norm(); + const Vector3 nxn_diff = n1.cross(dline2.template segment<3>(3)); + Scalar diff = (dline2.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn.norm(); + diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn.norm(); + + //absoulute value requires diffrent differentation for diffrent results + if(cdn <= 0) diff *= -1; + + diff /= std::pow(nxn.norm(),2); + #ifdef USE_LOGGING - if(!boost::math::isfinite(res)) - BOOST_LOG(log) << "Unnormal second cluster gradient detected: "<= 0) { + gradient.template head<3>() = -nxn/nxn.norm(); + gradient.template segment<3>(3) = (c.cross(-n2)*nxn.norm()-c.dot(nxn)*n2.cross(nxn)/nxn.norm())/std::pow(nxn.norm(),2); + } else { + gradient.template head<3>() = nxn/nxn.norm(); + gradient.template segment<3>(3) = (-c.cross(-n2)*nxn.norm()+c.dot(nxn)*n2.cross(nxn)/nxn.norm())/std::pow(nxn.norm(),2); + } }; - void calculateGradientSecondComplete(Vector& point, Vector& line, Vector& gradient) { - if(dist.norm() == 0) { - gradient.head(6).setOnes(); + void calculateGradientSecondComplete(Vector& line1, Vector& line2, Vector& gradient) { + if(nxn.norm() == 0) { + gradient.head(3).setOnes(); return; } - const Vector3 res = (-n*n.transpose())*dist + dist; - gradient.head(3) = res/dist.norm(); + if(cdn >= 0) { + gradient.template head<3>() = nxn/nxn.norm(); + gradient.template segment<3>(3) = (c.cross(n1)*nxn.norm()-c.dot(nxn)*((-n1).cross(nxn))/nxn.norm())/std::pow(nxn.norm(),2); + } else { + gradient.template head<3>() = -nxn/nxn.norm(); + gradient.template segment<3>(3) = (-c.cross(n1)*nxn.norm()+c.dot(nxn)*((-n1).cross(nxn))/nxn.norm())/std::pow(nxn.norm(),2); + } + }; +}; - const Scalar mult = n.transpose()*dist; - gradient.template segment<3>(3) = -(mult*diff + diff.dot(n)*dist)/dist.norm(); +//only defined when line and plane are parallel, therefore it's the same as the point-plane distance +template +struct Distance::type< Kernel, tag::line3D, tag::plane3D > : public Distance::type< Kernel, tag::point3D, tag::plane3D > { + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::point3D, tag::plane3D >() { + Distance::type< Kernel, tag::point3D, tag::plane3D >::tag.set("Distance line3D plane3D"); + }; +#endif + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); + g.segment(3,3).setZero(); + }; +}; + +template +struct Distance::type< Kernel, tag::line3D, tag::cylinder3D > : public Distance::type< Kernel, tag::line3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::line3D, tag::line3D >() { + Distance::type< Kernel, tag::line3D, tag::line3D >::tag.set("Distance line3D cylinder3D"); + }; +#endif + + Scalar calculate(Vector& param1, Vector& param2) { + //(p1-p2)°n / |n| - distance + const Scalar res = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2); + return res - param2(6); + }; + + void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientSecondComplete(p1,p2,g); + g(6) = -1; }; }; +//only defined when planes are parallel, therefore it's the same as the point-plane distance template -struct Distance::type< Kernel, tag::line3D, tag::line3D > : public Distance::type< Kernel, tag::point3D, tag::line3D > { +struct Distance::type< Kernel, tag::plane3D, tag::plane3D > : public Distance::type< Kernel, tag::point3D, tag::plane3D > { #ifdef USE_LOGGING - type() : Distance::type< Kernel, tag::point3D, tag::line3D >() { - Distance::type< Kernel, tag::point3D, tag::line3D >::tag.set("Distance line3D line3D"); + type() : Distance::type< Kernel, tag::point3D, tag::plane3D >() { + Distance::type< Kernel, tag::point3D, tag::plane3D >::tag.set("Distance plane3D plane3D"); }; #endif typedef typename Kernel::VectorMap Vector; void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { - Distance::type< Kernel, tag::point3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); + g.segment(3,3).setZero(); + }; +}; + +//only defined when plane and cylinder are parallel, therefore it's the same as the point-plane distance +template +struct Distance::type< Kernel, tag::plane3D, tag::cylinder3D > : public Distance::type< Kernel, tag::point3D, tag::plane3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + +#ifdef USE_LOGGING + type() : Distance::type< Kernel, tag::point3D, tag::plane3D >() { + Distance::type< Kernel, tag::point3D, tag::plane3D >::tag.set("Distance plane3D cylinder3D"); + }; +#endif + + Scalar calculate(Vector& param1, Vector& param2) { + //(p1-p2)°n / |n| - distance + const Scalar res = Distance::type< Kernel, tag::point3D, tag::plane3D >::calculate(param2, param1); + return res - param2(6); + }; + + Scalar calculateGradientFirst(Vector& p1, Vector& p2, Vector& dp1) { + return Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientSecond(p2,p1,dp1); + }; + + Scalar calculateGradientSecond(Vector& p1, Vector& p2, Vector& dp2) { + return Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirst(p2,p1,dp2); + }; + + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientSecondComplete(p2,p1,g); + }; + + void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p2,p1,g); g.segment(3,3).setZero(); + g(6) = -1; }; }; template struct Distance::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Distance::type< Kernel, tag::line3D, tag::line3D > { + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + #ifdef USE_LOGGING type() : Distance::type< Kernel, tag::line3D, tag::line3D >() { Distance::type< Kernel, tag::line3D, tag::line3D >::tag.set("Distance cylinder3D cylinder3D"); }; #endif - typedef typename Kernel::VectorMap Vector; + + Scalar calculate(Vector& param1, Vector& param2) { + //(p1-p2)°n / |n| - distance + const Scalar res = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2); + return res - param1(6) - param2(6); + }; + void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); - g(6) = 0; + g(6) = -1; + }; + + void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientSecondComplete(p1,p2,g); + g(6) = -1; }; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index 73623f39f4d6..f274fac1fdfa 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -77,8 +77,8 @@ struct Module3D { struct Constraint3D; struct Geometry3D; struct vertex_prop; - struct inheriter_base; - + struct inheriter_base; + typedef boost::shared_ptr Geom; typedef boost::shared_ptr Cons; @@ -121,12 +121,12 @@ struct Module3D { //allow accessing the internals by module3d classes but not by users friend struct details::ClusterMath; - friend struct details::ClusterMath::map_downstream; + friend struct details::ClusterMath::map_downstream; friend struct details::SystemSolver; - friend struct details::SystemSolver::Rescaler; - friend class detail::Constraint; + friend struct details::SystemSolver::Rescaler; + friend class detail::Constraint; }; - + template class Constraint3D_id : public detail::Constraint { @@ -145,13 +145,36 @@ struct Module3D { Constraint3D(Sys& system, Geom first, Geom second); friend struct details::SystemSolver; - friend struct details::SystemSolver::Rescaler; + friend struct details::SystemSolver::Rescaler; friend struct details::MES; friend struct inheriter_base; }; struct inheriter_base { + //build a constraint vector + template + struct fusion_vec { + typedef typename mpl::if_< mpl::is_sequence, + T, fusion::vector >::type type; + }; + + struct set_constraint_option { + + template + typename boost::enable_if, typename fusion_vec::type >::type + operator()(T& val) { + return val; + }; + template + typename boost::disable_if, typename fusion_vec::type >::type + operator()(T& val) { + typename fusion_vec::type vec; + fusion::at_c<0>(vec) = val; + return vec; + }; + }; + inheriter_base(); template @@ -178,9 +201,9 @@ struct Module3D { template Cons createConstraint3D(Identifier id, Geom first, Geom second, T constraint1); - void removeGeometry3D(Identifier id); + void removeGeometry3D(Identifier id); void removeConstraint3D(Identifier id); - + bool hasGeometry3D(Identifier id); Geom getGeometry3D(Identifier id); bool hasConstraint3D(Identifier id); @@ -406,27 +429,21 @@ template typename Module3D::template type::Cons Module3D::type::inheriter_base::createConstraint3D(Geom first, Geom second, T1 constraint1) { - //build a constraint vector - typedef mpl::vector<> cvec; - typedef typename mpl::if_< mpl::is_sequence, - typename mpl::fold< T1, cvec, mpl::push_back >::type, - mpl::vector1 >::type cvec1; + //get the fusion vector type + typedef typename fusion_vec::type covec; - //make a fusion sequence to hold the objects (as they hold the options) - typedef typename fusion::result_of::as_vector::type covec; //set the objects - covec cv; - fusion::at_c<0>(cv) = constraint1; + covec cv = set_constraint_option()( constraint1 ); //now create the constraint Cons c(new Constraint3D(*m_this, first, second)); //set the type and values - c->template initialize(cv); + c->template initialize(cv); //add it to the clustergraph fusion::vector res; res = m_this->m_cluster->addEdge(first->template getProperty(), - second->template getProperty()); + second->template getProperty()); if(!fusion::at_c<2>(res)) { Cons rc; return rc; //TODO: throw @@ -473,7 +490,7 @@ template void Module3D::type::inheriter_id::removeGeometry3D(Identifier id) { if(hasGeometry3D(id)) - inheriter_base::removeGeometry3D(getGeometry3D(id)); + inheriter_base::removeGeometry3D(getGeometry3D(id)); }; template @@ -492,7 +509,7 @@ template void Module3D::type::inheriter_id::removeConstraint3D(Identifier id) { if(hasConstraint3D(id)) - removeConstraint3D(getConstraint3D(id)); + removeConstraint3D(getConstraint3D(id)); }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp index 440fa103298a..9aad3e8f59a6 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -25,12 +25,12 @@ #include "geometry.hpp" #include -using boost::math::isnormal; +using boost::math::isfinite; namespace dcm { //the calculations( same as we always calculate directions we can outsource the work to this functions) -namespace parallel_detail { +namespace orientation_detail { template inline typename Kernel::number_type calc(T d1, @@ -38,19 +38,18 @@ inline typename Kernel::number_type calc(T d1, Direction dir) { switch(dir) { - case Same: + case equal: return (d1-d2).norm(); - case Opposite: + case opposite: return (d1+d2).norm(); - case Both: - if(d1.dot(d2) >= 0) { - return (d1-d2).norm(); - } - return (d1+d2).norm(); - default: - assert(false); + case parallel: + return d1.dot(d2) - d1.norm()*d2.norm(); + case perpendicular: + return d1.dot(d2); + default: + assert(false); } - return 0; + return 0; }; @@ -62,21 +61,21 @@ inline typename Kernel::number_type calcGradFirst(T d1, typename Kernel::number_type res; switch(dir) { - case Same: + case equal: res = ((d1-d2).dot(dd1) / (d1-d2).norm()); break; - case Opposite: + case opposite: res= ((d1+d2).dot(dd1) / (d1+d2).norm()); break; - case Both: - if(d1.dot(d2) >= 0) { - res = (((d1-d2).dot(dd1) / (d1-d2).norm())); - break; - } - res = (((d1+d2).dot(dd1) / (d1+d2).norm())); + case parallel: + res = dd1.dot(d2) - d1.dot(dd1)/d1.norm()*d2.norm(); + break; + case perpendicular: + res = dd1.dot(d2); break; } - if((isnormal)(res)) return res; + if(isfinite(res)) return res; + return 0; }; @@ -88,21 +87,20 @@ inline typename Kernel::number_type calcGradSecond(T d1, typename Kernel::number_type res; switch(dir) { - case Same: + case equal: res = ((d1-d2).dot(-dd2) / (d1-d2).norm()); break; - case Opposite: + case opposite: res = ((d1+d2).dot(dd2) / (d1+d2).norm()); break; - case Both: - if(d1.dot(d2) >= 0) { - res = (((d1-d2).dot(-dd2) / (d1-d2).norm())); - break; - } - res = (((d1+d2).dot(dd2) / (d1+d2).norm())); + case parallel: + res = d1.dot(dd2) - d2.dot(dd2)/d2.norm()*d1.norm(); + break; + case perpendicular: + res = d1.dot(dd2); break; } - if((isnormal)(res)) return res; + if((isfinite)(res)) return res; return 0; }; @@ -113,14 +111,18 @@ inline void calcGradFirstComp(T d1, Direction dir) { switch(dir) { - case Same: + case equal: grad = (d1-d2) / (d1-d2).norm(); return; - case Opposite: + case opposite: grad = (d1+d2) / (d1+d2).norm(); return; - case Both: - assert(false); + case parallel: + grad = d2 - d1/d1.norm()*d2.norm(); + return; + case perpendicular: + grad = d2; + return; } }; @@ -131,85 +133,198 @@ inline void calcGradSecondComp(T d1, Direction dir) { switch(dir) { - case Same: + case equal: grad = (d2-d1) / (d1-d2).norm(); return; - case Opposite: + case opposite: grad = (d2+d1) / (d1+d2).norm(); return; - case Both: - assert(false); + case parallel: + grad = d1 - d2/d2.norm()*d1.norm(); + return; + case perpendicular: + grad = d1; + return; } }; } template< typename Kernel > -struct Parallel::type< Kernel, tag::line3D, tag::line3D > : public dcm::PseudoScale { - - typedef typename Kernel::number_type Scalar; - typedef typename Kernel::VectorMap Vector; - - Direction value; - - //template definition - Scalar calculate(Vector& param1, Vector& param2) { - return parallel_detail::calc(param1.template tail<3>(), param2.template tail<3>(), value); - }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { - return parallel_detail::calcGradFirst(param1.template tail<3>(), param2.template tail<3>(), dparam1.template tail<3>(), value); - }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { - return parallel_detail::calcGradSecond(param1.template tail<3>(), param2.template tail<3>(), dparam2.template tail<3>(), value); - }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { - gradient.template head<3>().setZero(); - parallel_detail::calcGradFirstComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>(), value); - }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { - gradient.template head<3>().setZero(); - parallel_detail::calcGradSecondComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>(), value); - }; +struct Orientation::type< Kernel, tag::direction3D, tag::direction3D > : public dcm::PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return orientation_detail::calc(param1, param2, value); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return orientation_detail::calcGradFirst(param1, param2, dparam1, value); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return orientation_detail::calcGradSecond(param1, param2, dparam2, value); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradFirstComp(param1, param2, gradient, value); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradSecondComp(param1, param2, gradient, value); + }; +}; + +template< typename Kernel > +struct Orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return orientation_detail::calc(param1.template segment<3>(3), + param2.template segment<3>(3), + value); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return orientation_detail::calcGradFirst(param1.template segment<3>(3), + param2.template segment<3>(3), + dparam1.template segment<3>(3), + value); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return orientation_detail::calcGradSecond(param1.template segment<3>(3), + param2.template segment<3>(3), + dparam2.template segment<3>(3), + value); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradFirstComp(param1.template segment<3>(3), + param2.template segment<3>(3), + gradient.template segment<3>(3), + value); }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradSecondComp(param1.template segment<3>(3), + param2.template segment<3>(3), + gradient.template segment<3>(3), + value); + }; +}; template< typename Kernel > -struct Parallel::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::PseudoScale{ - - typedef typename Kernel::number_type Scalar; - typedef typename Kernel::VectorMap Vector; - - Direction value; - - Scalar calculate(Vector& param1, Vector& param2) { - return parallel_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), value); - }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { - return parallel_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), - dparam1.template segment<3>(3), value); - - }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { - return parallel_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), - dparam2.template segment<3>(3), value); - }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { - gradient.template head<3>().setZero(); - parallel_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), - gradient.template segment<3>(3), value); - }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { - gradient.template head<3>().setZero(); - parallel_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), - gradient.template segment<3>(3), value); - }; +struct Orientation::type< Kernel, tag::line3D, tag::plane3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + option_type getValue() { + if(value==parallel) + return perpendicular; + if(value==perpendicular) + return parallel; + return value; }; + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return orientation_detail::calc(param1.template segment<3>(3), + param2.template segment<3>(3), + getValue()); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return orientation_detail::calcGradFirst(param1.template segment<3>(3), + param2.template segment<3>(3), + dparam1.template segment<3>(3), + getValue()); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return orientation_detail::calcGradSecond(param1.template segment<3>(3), + param2.template segment<3>(3), + dparam2.template segment<3>(3), + getValue()); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradFirstComp(param1.template segment<3>(3), + param2.template segment<3>(3), + gradient.template segment<3>(3), + getValue()); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradSecondComp(param1.template segment<3>(3), + param2.template segment<3>(3), + gradient.template segment<3>(3), + getValue()); + }; +}; + template< typename Kernel > -struct Parallel::type< Kernel, tag::line3D, tag::plane3D > : public Parallel::type {}; +struct Orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > {}; template< typename Kernel > -struct Parallel::type< Kernel, tag::plane3D, tag::plane3D > : public Parallel::type {}; +struct Orientation::type< Kernel, tag::plane3D, tag::plane3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > {}; + +template< typename Kernel > +struct Orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public Orientation::type { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + using Orientation::type::value; + + //template definition + Scalar calculate(Vector& param1, Vector& param2) { + return Orientation::type::calculate(param1, param2); + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return Orientation::type::calculateGradientFirst(param1, param2, dparam1); + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return Orientation::type::calculateGradientSecond(param1, param2, dparam2); + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + Orientation::type::calculateGradientFirstComplete(param1, param2, gradient); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + Orientation::type::calculateGradientSecondComplete(param1, param2, gradient); + gradient(6)=0; + }; +}; + +template< typename Kernel > +struct Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > { + + typedef typename Kernel::VectorMap Vector; + + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradFirstComp(param1.template segment<3>(3), + param2.template segment<3>(3), + gradient.template segment<3>(3), + Orientation::type< Kernel, tag::line3D, tag::line3D >::value); + gradient(6) = 0; + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.template head<3>().setZero(); + orientation_detail::calcGradSecondComp(param1.template segment<3>(3), + param2.template segment<3>(3), + gradient.template segment<3>(3), + Orientation::type< Kernel, tag::line3D, tag::line3D >::value); + gradient(6) = 0; + }; +}; } -#endif //GCM_ANGLE +#endif From 35a9f1c693eb04497ac49867ddfeba85ffedc2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 5 May 2013 17:40:57 +0200 Subject: [PATCH 050/664] remove gui dependencies in app --- src/Mod/Assembly/App/CMakeLists.txt | 9 - src/Mod/Assembly/App/Constraint.cpp | 10 + src/Mod/Assembly/App/Constraint.h | 1 + src/Mod/Assembly/App/ConstraintFix.h | 2 +- src/Mod/Assembly/App/ConstraintGroup.cpp | 2 + src/Mod/Assembly/App/Solver.h | 10 +- src/Mod/Assembly/Gui/CommandConstraints.cpp | 47 ++ src/Mod/Assembly/Gui/Resources/Assembly.qrc | 1 + .../icons/Assembly_ConstraintLock.svg | 442 ++++++++++++++++++ src/Mod/Assembly/Gui/Workbench.cpp | 1 + 10 files changed, 506 insertions(+), 19 deletions(-) create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintLock.svg diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 2c44c9c2f5f1..5a67cc0284b9 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -4,10 +4,6 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions( -DUSE_LOGGING ) -endif (CMAKE_BUILD_TYPE STREQUAL "Debug") - include_directories( ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src @@ -28,11 +24,6 @@ set(Assembly_LIBS ${OCC_LIBRARIES} Part FreeCADApp - boost_log - rt - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} ) generate_from_xml(ItemPy) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp index 62f1265cb05a..bbfeef4fcf6b 100644 --- a/src/Mod/Assembly/App/Constraint.cpp +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -46,6 +46,7 @@ #include #include "Constraint.h" +#include "ConstraintPy.h" #include "Item.h" #include "ItemPart.h" @@ -109,5 +110,14 @@ void Constraint::init(boost::shared_ptr< Solver > solver) { }; } +PyObject *Constraint::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ConstraintPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h index 00562fb51f6f..9dd8064c71fb 100644 --- a/src/Mod/Assembly/App/Constraint.h +++ b/src/Mod/Assembly/App/Constraint.h @@ -59,6 +59,7 @@ class AssemblyExport Constraint : public App::DocumentObject const char* getViewProviderName(void) const { return "Gui::ViewProviderDocumentObject"; } + PyObject *getPyObject(void); /** @brief initialize the constraint in the assembly solver */ diff --git a/src/Mod/Assembly/App/ConstraintFix.h b/src/Mod/Assembly/App/ConstraintFix.h index c2b28035b133..ae7ca4357348 100644 --- a/src/Mod/Assembly/App/ConstraintFix.h +++ b/src/Mod/Assembly/App/ConstraintFix.h @@ -45,7 +45,7 @@ class AssemblyExport ConstraintFix : public Assembly::Constraint short mustExecute() const; /// returns the type name of the view provider //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraintFix"; + // return "AssemblyGui::ViewProviderConstraintFix"; //} //@} }; diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp index 2241be58e029..24beb6901786 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.cpp +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -58,6 +58,8 @@ PyObject *ConstraintGroup::getPyObject(void) void ConstraintGroup::addConstraint(Constraint* c) { + Base::Console().Message("add constraint to group\n"); + //add the constraint to our list const std::vector< App::DocumentObject * > &vals = this->Constraints.getValues(); std::vector< App::DocumentObject * > newVals(vals); diff --git a/src/Mod/Assembly/App/Solver.h b/src/Mod/Assembly/App/Solver.h index 5948b716752f..83ea19bcaa1c 100644 --- a/src/Mod/Assembly/App/Solver.h +++ b/src/Mod/Assembly/App/Solver.h @@ -30,7 +30,6 @@ #include #include #include -#include #include "opendcm/core.hpp" #include "opendcm/module3d.hpp" @@ -312,18 +311,11 @@ struct geometry_traits { typedef modell::quaternion_wxyz_vec3 modell; typedef placement_accessor accessor; }; -template<> -struct geometry_traits { - typedef tag::point3D tag; - typedef modell::XYZ modell; - typedef orderd_bracket_accessor accessor; -}; } - //our constraint solving system typedef dcm::Kernel Kernel; -typedef dcm::Module3D< mpl::vector5< gp_Pnt, gp_Lin, gp_Pln, gp_Cylinder, SbVec3f>, std::string > Module3D; +typedef dcm::Module3D< mpl::vector4< gp_Pnt, gp_Lin, gp_Pln, gp_Cylinder>, std::string > Module3D; typedef dcm::ModulePart< mpl::vector1< Base::Placement >, std::string > ModulePart; typedef dcm::System Solver; diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index 349950c56db0..e46651e4f5f4 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -143,9 +143,56 @@ void CmdAssemblyConstraintAxle::activated(int iMsg) } +/******************************************************************************************/ + +DEF_STD_CMD(CmdAssemblyConstraintFix); + +CmdAssemblyConstraintFix::CmdAssemblyConstraintFix() + :Command("Assembly_ConstraintFix") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint Fix..."); + sToolTipText = QT_TR_NOOP("Fixes a part in it's rotation and translation"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Assembly_ConstraintLock"; +} + + +void CmdAssemblyConstraintFix::activated(int iMsg) +{ + Assembly::ItemAssembly *Asm=0; + Assembly::ConstraintGroup *ConstGrp=0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm,&ConstGrp)) + return; + + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 1) { + Base::Console().Message("you must select one part\n"); + return; + }; + + Assembly::ItemPart* part = Asm->getContainingPart(objs[0].getObject()); + if(!part) { + Base::Console().Message("The selected object need to belong to the active assembly\n"); + return; + }; + + openCommand("Insert Constraint Fix"); + std::string ConstrName = getUniqueObjectName("Fix"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintFix','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().%s.addConstraint(App.activeDocument().ActiveObject)",ConstGrp->getNameInDocument()); + +} + void CreateAssemblyConstraintCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.addCommand(new CmdAssemblyConstraintFix()); rcCmdMgr.addCommand(new CmdAssemblyConstraintAxle()); } diff --git a/src/Mod/Assembly/Gui/Resources/Assembly.qrc b/src/Mod/Assembly/Gui/Resources/Assembly.qrc index df4638f442c5..d670d89566f4 100644 --- a/src/Mod/Assembly/Gui/Resources/Assembly.qrc +++ b/src/Mod/Assembly/Gui/Resources/Assembly.qrc @@ -1,6 +1,7 @@ icons/actions/Axle_constraint.svg + icons/Assembly_ConstraintLock.svg translations/Assembly_af.qm translations/Assembly_de.qm translations/Assembly_fi.qm diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintLock.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintLock.svg new file mode 100644 index 000000000000..b97df38c1dcc --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintLock.svg @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index 2831e0a6c84f..6d042316d18c 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -52,6 +52,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand(QT_TR_NOOP("Assembly")); + //*part << "Assembly_ConstraintFix"; *part << "Assembly_ConstraintAxle"; *part << "Separator"; *part << "Assembly_AddNewPart"; From 1e8a304036e5679534572cccd05580691e56fecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 5 May 2013 18:49:46 +0200 Subject: [PATCH 051/664] remove typename outside templates --- src/Mod/Assembly/App/Solver.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mod/Assembly/App/Solver.h b/src/Mod/Assembly/App/Solver.h index 83ea19bcaa1c..fc74051bcb5f 100644 --- a/src/Mod/Assembly/App/Solver.h +++ b/src/Mod/Assembly/App/Solver.h @@ -319,9 +319,9 @@ typedef dcm::Module3D< mpl::vector4< gp_Pnt, gp_Lin, gp_Pln, gp_Cylinder>, std:: typedef dcm::ModulePart< mpl::vector1< Base::Placement >, std::string > ModulePart; typedef dcm::System Solver; -typedef typename ModulePart::type::Part Part3D; -typedef typename Module3D::type::Geometry3D Geometry3D; -typedef typename Module3D::type::Constraint3D Constraint3D; +typedef ModulePart::type::Part Part3D; +typedef Module3D::type::Geometry3D Geometry3D; +typedef Module3D::type::Constraint3D Constraint3D; #endif //SOLVER_H \ No newline at end of file From ca6002444743a0145a3a6c371d8b525671f5b77a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 13 May 2013 16:21:19 +0200 Subject: [PATCH 052/664] add more constraints and rebuild solver system everytime it needs to be executed --- src/Mod/Assembly/App/AppAssembly.cpp | 14 +- src/Mod/Assembly/App/CMakeLists.txt | 17 +- src/Mod/Assembly/App/Constraint.cpp | 66 ++-- src/Mod/Assembly/App/Constraint.h | 5 +- src/Mod/Assembly/App/ConstraintAlignment.cpp | 87 ++++++ src/Mod/Assembly/App/ConstraintAlignment.h | 61 ++++ src/Mod/Assembly/App/ConstraintAngle.cpp | 10 + src/Mod/Assembly/App/ConstraintAngle.h | 8 +- src/Mod/Assembly/App/ConstraintAxisPy.xml | 17 - src/Mod/Assembly/App/ConstraintAxisPyImp.cpp | 29 -- .../Assembly/App/ConstraintCoincidence.cpp | 87 ++++++ src/Mod/Assembly/App/ConstraintCoincidence.h | 60 ++++ src/Mod/Assembly/App/ConstraintDistance.cpp | 83 +++++ src/Mod/Assembly/App/ConstraintDistance.h | 62 ++++ src/Mod/Assembly/App/ConstraintFix.cpp | 38 ++- src/Mod/Assembly/App/ConstraintFix.h | 9 +- src/Mod/Assembly/App/ConstraintGroup.cpp | 59 +--- src/Mod/Assembly/App/ConstraintGroup.h | 6 +- src/Mod/Assembly/App/ConstraintGroupPy.xml | 5 - src/Mod/Assembly/App/ConstraintGroupPyImp.cpp | 14 - .../Assembly/App/ConstraintOrientation.cpp | 93 ++++++ src/Mod/Assembly/App/ConstraintOrientation.h | 60 ++++ src/Mod/Assembly/App/ConstraintPyImp.cpp | 2 +- src/Mod/Assembly/App/ItemAssembly.cpp | 89 ++++-- src/Mod/Assembly/App/ItemAssembly.h | 8 +- src/Mod/Assembly/App/ItemAssemblyPy.xml | 10 - src/Mod/Assembly/App/ItemAssemblyPyImp.cpp | 35 --- src/Mod/Assembly/App/ItemPart.cpp | 19 +- src/Mod/Assembly/App/Solver.h | 1 - src/Mod/Assembly/App/opendcm/core.hpp | 5 + .../App/opendcm/core/clustergraph.hpp | 34 +- .../Assembly/App/opendcm/core/equations.hpp | 83 ++++- .../Assembly/App/opendcm/core/geometry.hpp | 12 +- src/Mod/Assembly/App/opendcm/core/system.hpp | 2 +- .../App/opendcm/core/transformation.hpp | 3 + src/Mod/Assembly/App/opendcm/externalize.hpp | 5 + src/Mod/Assembly/App/opendcm/module3d.hpp | 6 + .../Assembly/App/opendcm/module3d/angle.hpp | 124 ++++---- .../App/opendcm/module3d/clustermath.hpp | 3 + .../Assembly/App/opendcm/module3d/module.hpp | 20 +- .../App/opendcm/module3d/parallel.hpp | 67 ++-- .../App/opendcm/modulePart/module.hpp | 48 +-- src/Mod/Assembly/App/opendcm/modulepart.hpp | 5 + src/Mod/Assembly/App/opendcm/modulestate.hpp | 5 + src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 12 + src/Mod/Assembly/Gui/CMakeLists.txt | 21 +- src/Mod/Assembly/Gui/Command.cpp | 4 +- src/Mod/Assembly/Gui/CommandConstraints.cpp | 294 +++++++++++++++++- src/Mod/Assembly/Gui/Resources/Assembly.qrc | 6 +- .../icons/Assembly_ConstraintAngle.svg | 276 ++++++++++++++++ .../Gui/ViewProviderConstraintAlignment.cpp | 34 ++ .../Gui/ViewProviderConstraintAlignment.h | 42 +++ .../Gui/ViewProviderConstraintAngle.cpp | 34 ++ .../Gui/ViewProviderConstraintAngle.h | 42 +++ .../Gui/ViewProviderConstraintCoincidence.cpp | 34 ++ .../Gui/ViewProviderConstraintCoincidence.h | 42 +++ .../Gui/ViewProviderConstraintDistance.cpp | 34 ++ .../Gui/ViewProviderConstraintDistance.h | 42 +++ .../Gui/ViewProviderConstraintGroup.cpp | 4 +- .../Gui/ViewProviderConstraintOrientation.cpp | 34 ++ .../Gui/ViewProviderConstraintOrientation.h | 42 +++ src/Mod/Assembly/Gui/Workbench.cpp | 15 +- 62 files changed, 2068 insertions(+), 420 deletions(-) create mode 100644 src/Mod/Assembly/App/ConstraintAlignment.cpp create mode 100644 src/Mod/Assembly/App/ConstraintAlignment.h delete mode 100644 src/Mod/Assembly/App/ConstraintAxisPy.xml delete mode 100644 src/Mod/Assembly/App/ConstraintAxisPyImp.cpp create mode 100644 src/Mod/Assembly/App/ConstraintCoincidence.cpp create mode 100644 src/Mod/Assembly/App/ConstraintCoincidence.h create mode 100644 src/Mod/Assembly/App/ConstraintDistance.cpp create mode 100644 src/Mod/Assembly/App/ConstraintDistance.h create mode 100644 src/Mod/Assembly/App/ConstraintOrientation.cpp create mode 100644 src/Mod/Assembly/App/ConstraintOrientation.h create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAngle.svg create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index 773af74c3cfb..babebb0fe63d 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -35,11 +35,12 @@ #include "ItemPart.h" #include "ConstraintAngle.h" -#include "ConstraintAxis.h" -#include "ConstraintContact.h" +#include "ConstraintCoincidence.h" #include "ConstraintFix.h" #include "ConstraintGroup.h" -#include "ConstraintOffset.h" +#include "ConstraintAlignment.h" +#include "ConstraintDistance.h" +#include "ConstraintOrientation.h" extern struct PyMethodDef Assembly_methods[]; @@ -80,10 +81,11 @@ void AssemblyExport initAssembly() // constraint hirachy Assembly::Constraint ::init(); Assembly::ConstraintAngle ::init(); - Assembly::ConstraintAxis ::init(); - Assembly::ConstraintContact ::init(); + Assembly::ConstraintDistance::init(); + Assembly::ConstraintCoincidence::init(); Assembly::ConstraintFix ::init(); - Assembly::ConstraintOffset ::init(); + Assembly::ConstraintAlignment ::init(); + Assembly::ConstraintOrientation::init(); Assembly::ConstraintGroup ::init(); } diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 5a67cc0284b9..c8cfb101374c 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -30,7 +30,6 @@ generate_from_xml(ItemPy) generate_from_xml(ItemAssemblyPy) generate_from_xml(ItemPartPy) generate_from_xml(ConstraintPy) -generate_from_xml(ConstraintAxisPy) generate_from_xml(ConstraintGroupPy) SET(Features_SRCS @@ -46,14 +45,16 @@ SET(Features_SRCS ConstraintGroup.h ConstraintAngle.cpp ConstraintAngle.h - ConstraintAxis.cpp - ConstraintAxis.h - ConstraintContact.cpp - ConstraintContact.h + ConstraintDistance.cpp + ConstraintDistance.h + ConstraintCoincidence.cpp + ConstraintCoincidence.h ConstraintFix.cpp ConstraintFix.h - ConstraintOffset.cpp - ConstraintOffset.h + ConstraintAlignment.cpp + ConstraintAlignment.h + ConstraintOrientation.cpp + ConstraintOrientation.h ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) @@ -74,8 +75,6 @@ SET(Python_SRCS ItemPartPyImp.cpp ConstraintPy.xml ConstraintPyImp.cpp - ConstraintAxisPy.xml - ConstraintAxisPyImp.cpp ConstraintGroupPy.xml ConstraintGroupPyImp.cpp ) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp index bbfeef4fcf6b..84772447ea81 100644 --- a/src/Mod/Assembly/App/Constraint.cpp +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -49,6 +49,7 @@ #include "ConstraintPy.h" #include "Item.h" #include "ItemPart.h" +#include "ItemAssembly.h" using namespace Assembly; @@ -74,40 +75,44 @@ short Constraint::mustExecute() const App::DocumentObjectExecReturn *Constraint::execute(void) { - + touch(); return App::DocumentObject::StdReturn; } -void Constraint::init(boost::shared_ptr< Solver > solver) { +boost::shared_ptr Constraint::initLink(ItemAssembly* ass, App::PropertyLinkSub& link) { - //check if we have Assembly::ItemPart's - if( First.getValue()->getTypeId() != ItemPart::getClassTypeId() || - Second.getValue()->getTypeId() != ItemPart::getClassTypeId() ) { - Base::Console().Message("Links are not ItemPart's, the constraint is invalid\n"); - return; + //check if we have Assembly::ItemPart + if( link.getValue()->getTypeId() != ItemPart::getClassTypeId() ) { + Base::Console().Message("Link is not ItemPart, the constraint is invalid\n"); + return boost::shared_ptr(); }; - - //see if the parts are already initialized for the solver - Assembly::ItemPart* part1 = static_cast(First.getValue()); - if(!part1->m_part) { - part1->m_part = solver->createPart(part1->Placement.getValue(), part1->Uid.getValueStr()); - part1->m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, part1, _1)); - } - - Assembly::ItemPart* part2 = static_cast(Second.getValue()); - if(!part2->m_part) { - part2->m_part = solver->createPart(part2->Placement.getValue(), part2->Uid.getValueStr()); - part2->m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, part2, _1)); - } - - //let's get the geometrys - m_first_geom = part1->getGeometry3D(First.getSubValues()[0].c_str()); - m_second_geom = part2->getGeometry3D(Second.getSubValues()[0].c_str()); + + Assembly::ItemPart* part = static_cast(link.getValue()); + if(!part) + return boost::shared_ptr(); - if(!m_first_geom || !m_second_geom) { - Base::Console().Message("Unable to initialize geometry\n"); - return; - }; + //get the relevant solver in which the part needs to be added + Assembly::ItemAssembly* p_ass = ass->getParentAssembly(part); + if(!p_ass) + return boost::shared_ptr(); + + boost::shared_ptr solver = p_ass->m_solver; + if(!solver) + return boost::shared_ptr(); + + if(!solver->hasPart(part->Uid.getValueStr())) { + part->m_part = solver->createPart(part->Placement.getValue(), part->Uid.getValueStr()); + part->m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, part, _1)); + }; + + return part->getGeometry3D(link.getSubValues()[0].c_str()); +} + + +void Constraint::init(ItemAssembly* ass) +{ + m_first_geom = initLink(ass, First); + m_second_geom = initLink(ass, Second); } PyObject *Constraint::getPyObject(void) @@ -120,4 +125,7 @@ PyObject *Constraint::getPyObject(void) } -} \ No newline at end of file +} + + + diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h index 9dd8064c71fb..2be02e75661e 100644 --- a/src/Mod/Assembly/App/Constraint.h +++ b/src/Mod/Assembly/App/Constraint.h @@ -31,6 +31,7 @@ #include #include "Solver.h" +#include "ItemAssembly.h" namespace Assembly @@ -44,6 +45,8 @@ class AssemblyExport Constraint : public App::DocumentObject boost::shared_ptr m_constraint; boost::shared_ptr m_first_geom, m_second_geom; + boost::shared_ptr< Geometry3D > initLink(Assembly::ItemAssembly* ass, App::PropertyLinkSub& link); + public: Constraint(); @@ -63,7 +66,7 @@ class AssemblyExport Constraint : public App::DocumentObject /** @brief initialize the constraint in the assembly solver */ - virtual void init(boost::shared_ptr solver); + virtual void init(ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintAlignment.cpp b/src/Mod/Assembly/App/ConstraintAlignment.cpp new file mode 100644 index 000000000000..f2ad98cd3047 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAlignment.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 + +#include "ConstraintAlignment.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintAlignment, Assembly::Constraint) + +ConstraintAlignment::ConstraintAlignment() +{ + ADD_PROPERTY(Offset,(0)); + ADD_PROPERTY(Orientation, (long(0))); + + std::vector vec; + vec.push_back("Parallel"); + vec.push_back("Equal"); + vec.push_back("Opposite"); + Orientation.setEnumVector(vec); +} + +short ConstraintAlignment::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintAlignment::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +void ConstraintAlignment::init(ItemAssembly* ass) { + + //cant use the base class init as we only need one part + Constraint::init(ass); + + //init the constraint + dcm::Direction dir; + switch(Orientation.getValue()) { + case 0: + dir = dcm::parallel; + break; + case 1: + dir = dcm::equal; + break; + default: + dir = dcm::opposite; + }; + + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::alignment(dir, Offset.getValue())); +}; + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAlignment.h b/src/Mod/Assembly/App/ConstraintAlignment.h new file mode 100644 index 000000000000..7e5dfc23592e --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintAlignment.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 Assembly_ConstraintAlignment_H +#define Assembly_ConstraintAlignment_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintAlignment : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintAlignment); + +public: + ConstraintAlignment(); + + App::PropertyFloat Offset; + App::PropertyEnumeration Orientation; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintAlignment"; + } + //@} + + virtual void init(ItemAssembly* ass); +}; + +} //namespace PartDesign + + +#endif // PART_ConstraintAlignment_H diff --git a/src/Mod/Assembly/App/ConstraintAngle.cpp b/src/Mod/Assembly/App/ConstraintAngle.cpp index 52d38337500f..69fa6479f433 100644 --- a/src/Mod/Assembly/App/ConstraintAngle.cpp +++ b/src/Mod/Assembly/App/ConstraintAngle.cpp @@ -27,6 +27,7 @@ #include +#include #include "ConstraintAngle.h" @@ -56,4 +57,13 @@ App::DocumentObjectExecReturn *ConstraintAngle::execute(void) return App::DocumentObject::StdReturn; } +void ConstraintAngle::init(ItemAssembly* ass) +{ + //init the parts and geometries + Constraint::init(ass); + + //init the constraint + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::angle = Angle.getValue()*M_PI/180.); +} + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAngle.h b/src/Mod/Assembly/App/ConstraintAngle.h index 13b2ae68a188..29bce3e25cf1 100644 --- a/src/Mod/Assembly/App/ConstraintAngle.h +++ b/src/Mod/Assembly/App/ConstraintAngle.h @@ -46,10 +46,12 @@ class AssemblyExport ConstraintAngle : public Assembly::Constraint App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraintAngle"; - //} + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintAngle"; + } //@} + + virtual void init(ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintAxisPy.xml b/src/Mod/Assembly/App/ConstraintAxisPy.xml deleted file mode 100644 index d54b6080f4c2..000000000000 --- a/src/Mod/Assembly/App/ConstraintAxisPy.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Base class of all objects in Assembly - - - diff --git a/src/Mod/Assembly/App/ConstraintAxisPyImp.cpp b/src/Mod/Assembly/App/ConstraintAxisPyImp.cpp deleted file mode 100644 index a9a0d06bd089..000000000000 --- a/src/Mod/Assembly/App/ConstraintAxisPyImp.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -#include "PreCompiled.h" - -#include "Mod/Assembly/App/Constraint.h" - -// inclusion of the generated files (generated out of ItemAssemblyPy.xml) -#include "ConstraintAxisPy.h" -#include "ConstraintAxisPy.cpp" - -using namespace Assembly; - -// returns a string which represents the object e.g. when printed in python -std::string ConstraintAxisPy::representation(void) const -{ - return std::string(""); -} - - -PyObject *ConstraintAxisPy::getCustomAttributes(const char* /*attr*/) const -{ - return 0; -} - -int ConstraintAxisPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) -{ - return 0; -} - - diff --git a/src/Mod/Assembly/App/ConstraintCoincidence.cpp b/src/Mod/Assembly/App/ConstraintCoincidence.cpp new file mode 100644 index 000000000000..f0ec83382ed2 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintCoincidence.cpp @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 + +#include "ConstraintCoincidence.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintCoincidence, Assembly::Constraint) + +ConstraintCoincidence::ConstraintCoincidence() +{ + + ADD_PROPERTY(Orientation, (long(0))); + + std::vector vec; + vec.push_back("Parallel"); + vec.push_back("Equal"); + vec.push_back("Opposite"); + Orientation.setEnumVector(vec); +} + +short ConstraintCoincidence::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintCoincidence::execute(void) +{ + + return App::DocumentObject::StdReturn; +} + +void ConstraintCoincidence::init(ItemAssembly* ass) { + + //cant use the base class init as we only need one part + Constraint::init(ass); + + //init the constraint + dcm::Direction dir; + switch(Orientation.getValue()) { + case 0: + dir = dcm::parallel; + break; + case 1: + dir = dcm::equal; + break; + default: + dir = dcm::opposite; + }; + + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::coincidence = dir); +}; + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintCoincidence.h b/src/Mod/Assembly/App/ConstraintCoincidence.h new file mode 100644 index 000000000000..180d9bd4f36e --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintCoincidence.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_ConstraintCoincidence_H +#define Assembly_ConstraintCoincidence_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintCoincidence : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintCoincidence); + +public: + ConstraintCoincidence(); + + App::PropertyEnumeration Orientation; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintCoincidence"; + } + //@} + + virtual void init(ItemAssembly* ass); +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintCoincidence_H diff --git a/src/Mod/Assembly/App/ConstraintDistance.cpp b/src/Mod/Assembly/App/ConstraintDistance.cpp new file mode 100644 index 000000000000..10ef64745e56 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintDistance.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel + * 2013 Stefan Tröger + * * + * 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 +#include + +#include "ConstraintDistance.h" +#include "ConstraintPy.h" + +#include "ItemPart.h" + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintDistance, Assembly::Constraint) + +ConstraintDistance::ConstraintDistance() +{ + ADD_PROPERTY(Distance,(0)); +} + +PyObject *ConstraintDistance::getPyObject(void) +{ + if (PythonObject.is(Py::_None())){ + // ref counter is set to 1 + PythonObject = Py::Object(new ConstraintPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +short ConstraintDistance::mustExecute() const +{ + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn *ConstraintDistance::execute(void) +{ + Base::Console().Message("Recalculate axis constraint\n"); + touch(); + return App::DocumentObject::StdReturn; +} + +void ConstraintDistance::init(ItemAssembly* ass) +{ + //init the parts and geometries + Constraint::init(ass); + + //init the constraint + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::distance = Distance.getValue()); +} + + +} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintDistance.h b/src/Mod/Assembly/App/ConstraintDistance.h new file mode 100644 index 000000000000..e3f3f22fb217 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintDistance.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_ConstraintAxis_H +#define Assembly_ConstraintAxis_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintDistance : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintAxis); + +public: + ConstraintDistance(); + + App::PropertyFloat Distance; + + PyObject *getPyObject(void); + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintDistance"; + } + //@} + + virtual void init(ItemAssembly* ass); +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintAxis_H diff --git a/src/Mod/Assembly/App/ConstraintFix.cpp b/src/Mod/Assembly/App/ConstraintFix.cpp index 033222172c32..06771fd07742 100644 --- a/src/Mod/Assembly/App/ConstraintFix.cpp +++ b/src/Mod/Assembly/App/ConstraintFix.cpp @@ -26,6 +26,8 @@ #endif #include +#include +#include "ItemPart.h" #include "ConstraintFix.h" @@ -37,23 +39,43 @@ namespace Assembly { PROPERTY_SOURCE(Assembly::ConstraintFix, Assembly::Constraint) -ConstraintFix::ConstraintFix() -{ +ConstraintFix::ConstraintFix() { } -short ConstraintFix::mustExecute() const -{ +ConstraintFix::~ConstraintFix() { + + Assembly::ItemPart* part = static_cast(First.getValue()); + if(part && part->m_part) { + part->m_part->fix(false); + } +} + +short ConstraintFix::mustExecute() const { //if (Sketch.isTouched() || // Length.isTouched()) // return 1; return 0; } -App::DocumentObjectExecReturn *ConstraintFix::execute(void) -{ - +App::DocumentObjectExecReturn* ConstraintFix::execute(void) { + return App::DocumentObject::StdReturn; } -} \ No newline at end of file +void ConstraintFix::init(ItemAssembly* ass) { + + //cant use the base class init as we only need one part + initLink(ass, First); + + //get the part + Assembly::ItemPart* part = static_cast(First.getValue()); + if(!part) + return; + + //init the constraint + part->m_part->fix(true); + +}; + +} diff --git a/src/Mod/Assembly/App/ConstraintFix.h b/src/Mod/Assembly/App/ConstraintFix.h index ae7ca4357348..8e2a4c59c42d 100644 --- a/src/Mod/Assembly/App/ConstraintFix.h +++ b/src/Mod/Assembly/App/ConstraintFix.h @@ -37,6 +37,7 @@ class AssemblyExport ConstraintFix : public Assembly::Constraint public: ConstraintFix(); + ~ConstraintFix(); /** @name methods override feature */ //@{ @@ -44,10 +45,12 @@ class AssemblyExport ConstraintFix : public Assembly::Constraint App::DocumentObjectExecReturn *execute(void); short mustExecute() const; /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "AssemblyGui::ViewProviderConstraintFix"; - //} + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintFix"; + } //@} + + virtual void init(ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp index 24beb6901786..818f9aa37804 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.cpp +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -56,51 +56,6 @@ PyObject *ConstraintGroup::getPyObject(void) return Py::new_reference_to(PythonObject); } -void ConstraintGroup::addConstraint(Constraint* c) -{ - Base::Console().Message("add constraint to group\n"); - - //add the constraint to our list - const std::vector< App::DocumentObject * > &vals = this->Constraints.getValues(); - std::vector< App::DocumentObject * > newVals(vals); - newVals.push_back(c); - this->Constraints.setValues(newVals); - - //let's retrieve the solver if not already done - ItemAssembly* assembly = NULL; - if(!m_solver || !assembly) { - - typedef std::vector::iterator iter; - std::vector vec = getInList(); - - for(iter it = vec.begin(); it!=vec.end(); it++) { - - if( (*it)->getTypeId() == ItemAssembly::getClassTypeId() ) { - assembly = static_cast(*it); - m_solver = assembly->m_solver; - break; - }; - } - }; - - //check if we have been successfull - if(!m_solver) { - Base::Console().Message("ConstraintGroup: Unable to retrieve assembly solver\n"); - return; - }; - if(!assembly) { - Base::Console().Message("ConstraintGroup: Unable to retrieve assembly\n"); - return; - }; - - //init the constraint - c->init(m_solver); - - //solve the system and propagate the change upstream - m_solver->solve(); - assembly->touch(); -} - short ConstraintGroup::mustExecute() const { @@ -114,7 +69,21 @@ App::DocumentObjectExecReturn *ConstraintGroup::execute(void) { Base::Console().Message("Recalculate constraint group\n"); + touch(); return App::DocumentObject::StdReturn; } +void ConstraintGroup::init(ItemAssembly* ass) { + + std::vector obj = Constraints.getValues(); + + std::vector::iterator it; + for (it = obj.begin(); it != obj.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(Assembly::Constraint::getClassTypeId())) { + static_cast(*it)->init(ass); + } + } +} + + } diff --git a/src/Mod/Assembly/App/ConstraintGroup.h b/src/Mod/Assembly/App/ConstraintGroup.h index 167cd3451ad4..8c671ab604dd 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.h +++ b/src/Mod/Assembly/App/ConstraintGroup.h @@ -38,13 +38,9 @@ namespace Assembly class AssemblyExport ConstraintGroup : public App::DocumentObject { PROPERTY_HEADER(Assembly::ConstraintGroup); - -protected: - boost::shared_ptr m_solver; public: ConstraintGroup(); - void addConstraint(Constraint* c); PyObject *getPyObject(void); @@ -60,6 +56,8 @@ class AssemblyExport ConstraintGroup : public App::DocumentObject return "AssemblyGui::ViewProviderConstraintGroup"; } //@} + + void init(ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintGroupPy.xml b/src/Mod/Assembly/App/ConstraintGroupPy.xml index 9691e96682f9..fbc07d2f8291 100644 --- a/src/Mod/Assembly/App/ConstraintGroupPy.xml +++ b/src/Mod/Assembly/App/ConstraintGroupPy.xml @@ -13,11 +13,6 @@ Base class of all objects in Assembly - - - Adds a constraint object to the constraint group - - diff --git a/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp b/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp index 19bd9fd63141..d315c9b64f5f 100644 --- a/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp +++ b/src/Mod/Assembly/App/ConstraintGroupPyImp.cpp @@ -16,20 +16,6 @@ std::string ConstraintGroupPy::representation(void) const return std::string(""); } -PyObject* ConstraintGroupPy::addConstraint(PyObject * args) -{ - PyObject *pcObj; - if (!PyArg_ParseTuple(args, "O", &pcObj)) - return 0; - - if (PyObject_TypeCheck(pcObj, &(Assembly::ConstraintPy::Type))) { - Base::Console().Message("Add constraint\n"); - Assembly::Constraint *c = static_cast(pcObj)->getConstraintPtr(); - this->getConstraintGroupPtr()->addConstraint(c); - } - Py_Return; -} - PyObject *ConstraintGroupPy::getCustomAttributes(const char* /*attr*/) const { return 0; diff --git a/src/Mod/Assembly/App/ConstraintOrientation.cpp b/src/Mod/Assembly/App/ConstraintOrientation.cpp new file mode 100644 index 000000000000..56728dbc9d73 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintOrientation.cpp @@ -0,0 +1,93 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel + * 2013 Stefan Tröger + * * + * 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 +#include + +#include "ConstraintOrientation.h" +#include "ConstraintPy.h" + +#include "ItemPart.h" + + +using namespace Assembly; + +namespace Assembly { + + +PROPERTY_SOURCE(Assembly::ConstraintOrientation, Assembly::Constraint) + +ConstraintOrientation::ConstraintOrientation() { + ADD_PROPERTY(Orientation, (long(0))); + + std::vector vec; + vec.push_back("Parallel"); + vec.push_back("Perpendicular"); + vec.push_back("Equal"); + vec.push_back("Opposite"); + Orientation.setEnumVector(vec); +} + +short ConstraintOrientation::mustExecute() const { + //if (Sketch.isTouched() || + // Length.isTouched()) + // return 1; + return 0; +} + +App::DocumentObjectExecReturn* ConstraintOrientation::execute(void) { + Base::Console().Message("Recalculate orientation constraint\n"); + touch(); + return App::DocumentObject::StdReturn; +} + +void ConstraintOrientation::init(ItemAssembly* ass) { + //init the parts and geometries + Constraint::init(ass); + + //init the constraint + dcm::Direction dir; + switch(Orientation.getValue()) { + case 0: + dir = dcm::parallel; + break; + case 1: + dir = dcm::perpendicular; + break; + case 2: + dir = dcm::equal; + break; + default: + dir = dcm::opposite; + }; + + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::orientation = dir); +} + + +} diff --git a/src/Mod/Assembly/App/ConstraintOrientation.h b/src/Mod/Assembly/App/ConstraintOrientation.h new file mode 100644 index 000000000000..9c356bca9812 --- /dev/null +++ b/src/Mod/Assembly/App/ConstraintOrientation.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (c) 2012 Juergen Riegel * + * * + * 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 Assembly_ConstraintOrientation_H +#define Assembly_ConstraintOrientation_H + +#include +#include "Constraint.h" + + +namespace Assembly +{ + +class AssemblyExport ConstraintOrientation : public Assembly::Constraint +{ + PROPERTY_HEADER(Assembly::ConstraintOrientation); + +public: + ConstraintOrientation(); + + App::PropertyEnumeration Orientation; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "AssemblyGui::ViewProviderConstraintOrientation"; + } + //@} + + virtual void init(ItemAssembly* ass); +}; + +} //namespace Assembly + + +#endif // Assembly_ConstraintAxis_H diff --git a/src/Mod/Assembly/App/ConstraintPyImp.cpp b/src/Mod/Assembly/App/ConstraintPyImp.cpp index e763ea29aedf..7d684c909129 100644 --- a/src/Mod/Assembly/App/ConstraintPyImp.cpp +++ b/src/Mod/Assembly/App/ConstraintPyImp.cpp @@ -12,7 +12,7 @@ using namespace Assembly; // returns a string which represents the object e.g. when printed in python std::string ConstraintPy::representation(void) const { - return std::string(""); + return std::string(""); } diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 0e86369d0f56..dd576924c870 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -32,6 +32,7 @@ #include #include "ItemAssembly.h" +#include "ConstraintGroup.h" #include @@ -42,7 +43,7 @@ namespace Assembly { PROPERTY_SOURCE(Assembly::ItemAssembly, Assembly::Item) -ItemAssembly::ItemAssembly() : m_solver(new Solver) +ItemAssembly::ItemAssembly() { ADD_PROPERTY(Items,(0)); ADD_PROPERTY(Annotations,(0)); @@ -56,6 +57,24 @@ short ItemAssembly::mustExecute() const App::DocumentObjectExecReturn *ItemAssembly::execute(void) { Base::Console().Message("Execute ItemAssembly\n"); + + //create a solver and init all child assemblys with subsolvers + m_solver = boost::shared_ptr(new Solver); + init(boost::shared_ptr()); + + //get the constraint group and init the constraints + typedef std::vector::const_iterator iter; + + const std::vector& vector = Annotations.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if( (*it)->getTypeId() == Assembly::ConstraintGroup::getClassTypeId() ) + static_cast(*it)->init(this); + }; + + //solve the system + m_solver->solve(); + this->touch(); return App::DocumentObject::StdReturn; } @@ -101,37 +120,44 @@ PyObject *ItemAssembly::getPyObject(void) return Py::new_reference_to(PythonObject); } -void ItemAssembly::addPart(ItemPart* part) { +bool ItemAssembly::isParentAssembly(ItemPart* part) { - if(part->m_part) { - //TODO: destroy old part - } - - //add the part to our list - const std::vector< App::DocumentObject * > &vals = this->Items.getValues(); - std::vector< App::DocumentObject * > newVals(vals); - newVals.push_back(part); - this->Items.setValues(newVals); + typedef std::vector::const_iterator iter; - part->m_part = m_solver->createPart(part->Placement.getValue(), part->Uid.getValueStr()); + const std::vector& vector = Items.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if( (*it)->getTypeId() == Assembly::ItemPart::getClassTypeId() ) + if(*it == part) return true; + }; + + return false; } -void ItemAssembly::addComponent(ItemAssembly* assembly) { +ItemAssembly* ItemAssembly::getParentAssembly(ItemPart* part) { - if(assembly->m_solver) { - //TODO: destroy old solver system - } + typedef std::vector::const_iterator iter; - //add the component to our list - const std::vector< App::DocumentObject * > &vals = this->Items.getValues(); - std::vector< App::DocumentObject * > newVals(vals); - newVals.push_back(assembly); - this->Items.setValues(newVals); + const std::vector& vector = Items.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if( (*it)->getTypeId() == Assembly::ItemPart::getClassTypeId() ) { + if(*it == part) + return this; + } + else if ( (*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId() ) { + + Assembly::ItemAssembly* assembly = static_cast(*it)->getParentAssembly(part); + if(assembly) + return assembly; + } + }; - assembly->m_solver = boost::shared_ptr(m_solver->createSubsystem()); - assembly->m_solver->setTransformation(assembly->Placement.getValue()); + return (ItemAssembly*)NULL; } + + ItemPart* ItemAssembly::getContainingPart(App::DocumentObject* obj) { typedef std::vector::const_iterator iter; @@ -154,5 +180,22 @@ ItemPart* ItemAssembly::getContainingPart(App::DocumentObject* obj) { return NULL; } +void ItemAssembly::init(boost::shared_ptr parent) { + + if(parent) + m_solver = boost::shared_ptr(parent->createSubsystem()); + + typedef std::vector::const_iterator iter; + + const std::vector& vector = Items.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if ( (*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId() ) { + + static_cast(*it)->init(m_solver); + } + }; +} + } \ No newline at end of file diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 58036bbff6c4..4014a5ea72c9 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -57,10 +57,12 @@ class AssemblyExport ItemAssembly : public Assembly::Item virtual TopoDS_Shape getShape(void) const; - void addPart(Assembly::ItemPart* part); - void addComponent(Assembly::ItemAssembly* assembly); + //the toplevel assembly is the direct parent of the part + bool isParentAssembly(ItemPart* part); + ItemAssembly* getParentAssembly(ItemPart* part); - Assembly::ItemPart* getContainingPart(App::DocumentObject* obj); + ItemPart* getContainingPart(App::DocumentObject* obj); + void init(boost::shared_ptr parent); boost::shared_ptr m_solver; }; diff --git a/src/Mod/Assembly/App/ItemAssemblyPy.xml b/src/Mod/Assembly/App/ItemAssemblyPy.xml index 7e9ba5727546..e2f560946eae 100644 --- a/src/Mod/Assembly/App/ItemAssemblyPy.xml +++ b/src/Mod/Assembly/App/ItemAssemblyPy.xml @@ -13,15 +13,5 @@ Base class of all objects in Assembly - - - Adds a Assembly::ItemPart object to the assembly - - - - - Adds a Assembly::ItemAssembly object to the assembly - - diff --git a/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp b/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp index 5d7ff419c06e..3a224534d8ff 100644 --- a/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp +++ b/src/Mod/Assembly/App/ItemAssemblyPyImp.cpp @@ -17,41 +17,6 @@ std::string ItemAssemblyPy::representation(void) const } -PyObject* ItemAssemblyPy::addPart(PyObject * args) -{ - PyObject *pcObj; - if (!PyArg_ParseTuple(args, "O", &pcObj)) { - Base::Console().Message("Test 1 fails\n"); - return 0; - } - - if (PyObject_TypeCheck(pcObj, &(Assembly::ItemPartPy::Type))) { - Assembly::ItemPart *c = static_cast(pcObj)->getItemPartPtr(); - getItemAssemblyPtr()->addPart(c); - Base::Console().Message("Add Part\n"); - } - else Base::Console().Message("Test 2 fails\n"); - Py_Return; -} - -PyObject* ItemAssemblyPy::addComponent(PyObject * args) -{ - PyObject *pcObj; - if (!PyArg_ParseTuple(args, "O", &pcObj)) { - Base::Console().Message("Test 1 fails\n"); - return 0; - } - - if (PyObject_TypeCheck(pcObj, &(Assembly::ItemAssemblyPy::Type))) { - Assembly::ItemAssembly *c = static_cast(pcObj)->getItemAssemblyPtr(); - getItemAssemblyPtr()->addComponent(c); - Base::Console().Message("Add Component\n"); - } - else Base::Console().Message("Test 2 fails\n"); - Py_Return; -} - - PyObject *ItemAssemblyPy::getCustomAttributes(const char* /*attr*/) const { return 0; diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index 61a5b9fc0def..f594ea931400 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -143,17 +143,17 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) gp_Dir dir = plane.Axis().Direction(); plane = gp_Pln(plane.Location(), dir.Reversed()); } - geometry = m_part->addGeometry3D(plane, Type, dcm::Global); + geometry = m_part->addGeometry3D(plane, Type, dcm::Local); break; } case GeomAbs_Cylinder: { //Base::Console().Message("cylinder selected\n"); gp_Cylinder cyl = surface.Cylinder(); - geometry = m_part->addGeometry3D(cyl, Type, dcm::Global); + geometry = m_part->addGeometry3D(cyl, Type, dcm::Local); break; } default: - Base::Console().Message("Unsuported Surface Geometrie Type at selection 1\n"); + Base::Console().Message("Unsuported Surface Geometrie Type at selection\n"); return boost::shared_ptr< Geometry3D >(); } @@ -163,24 +163,29 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) switch(curve.GetType()) { case GeomAbs_Line: { gp_Lin line = curve.Line(); - geometry = m_part->addGeometry3D(line, Type, dcm::Global); + geometry = m_part->addGeometry3D(line, Type, dcm::Local); break; } default: - //Base::Console().Message("Unsuported Curve Geometrie Type at selection 1\n"); + Base::Console().Message("Unsuported Curve Geometrie Type at selection \n"); return boost::shared_ptr< Geometry3D >(); } } else if(s.ShapeType() == TopAbs_VERTEX) { TopoDS_Vertex v1 = TopoDS::Vertex(s); gp_Pnt point = BRep_Tool::Pnt(v1); - geometry = m_part->addGeometry3D(point, Type, dcm::Global); + geometry = m_part->addGeometry3D(point, Type, dcm::Local); } else { - Base::Console().Message("Unsuported Topologie Type at selection 1\n"); + Base::Console().Message("Unsuported Topologie Type at selection\n"); return boost::shared_ptr< Geometry3D >(); } }; + + std::stringstream s; + s<m_global; + Base::Console().Message("Added geom: %s, %s\n", Type, s.str().c_str()); + return geometry; } diff --git a/src/Mod/Assembly/App/Solver.h b/src/Mod/Assembly/App/Solver.h index fc74051bcb5f..5ddc4c51ee98 100644 --- a/src/Mod/Assembly/App/Solver.h +++ b/src/Mod/Assembly/App/Solver.h @@ -20,7 +20,6 @@ * * ***************************************************************************/ - #ifndef SOLVER_H #define SOLVER_H diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index 8d03a1d7fe62..c58af05a6097 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -20,6 +20,11 @@ #ifndef DCM_CORE_H #define DCM_CORE_H +#ifdef _WIN32 + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) +#endif + #include "core/geometry.hpp" #include "core/kernel.hpp" #include "core/system.hpp" diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index fac9f172ce60..4fed639dd04d 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -52,6 +52,8 @@ #include #include +#include + namespace mpl = boost::mpl; namespace fusion = boost::fusion; @@ -362,23 +364,23 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, return std::pair, LocalVertex>(m_clusters[v] = boost::shared_ptr(new ClusterGraph(sp_base::shared_from_this())), v); }; - boost::shared_ptr parent() { - return m_parent; + inline boost::shared_ptr parent() { + return boost::shared_ptr(m_parent); }; - const boost::shared_ptr parent() const { - return m_parent; + inline const boost::shared_ptr parent() const { + return boost::shared_ptr(m_parent); }; bool isRoot() const { - return m_parent ? false : true; + return m_parent.expired(); }; boost::shared_ptr root() { - return isRoot() ? sp_base::shared_from_this() : m_parent->root(); + return isRoot() ? sp_base::shared_from_this() : parent()->root(); }; const boost::shared_ptr root() const { - return isRoot() ? sp_base::shared_from_this() : m_parent->root(); + return isRoot() ? sp_base::shared_from_this() : parent()->root(); }; std::pair clusters() { @@ -1303,8 +1305,8 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, LocalVertex nv = boost::add_vertex(vb, *parent()); //regrouping if needed if(isCluster(v)) { - m_parent->m_clusters[nv] = m_clusters[v]; - m_parent->m_clusters[nv]->m_parent = m_parent; + parent()->m_clusters[nv] = m_clusters[v]; + parent()->m_clusters[nv]->m_parent = m_parent; m_clusters.erase(v); } @@ -1312,7 +1314,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) std::vector edge_vec; - LocalVertex this_v = m_parent->getClusterVertex(sp_base::shared_from_this()); + LocalVertex this_v = parent()->getClusterVertex(sp_base::shared_from_this()); std::pair it = boost::out_edges(this_v, *parent()); for(; it.first != it.second; it.first++) { //iterate all global edges and find relevant ones @@ -1323,14 +1325,14 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, GlobalEdge global = global_extractor()(*i); GlobalVertex target; //a bit cumbersome to allow cluster moving - if(m_parent->getContainingVertex(global.source).first == nv) target = global.target; - else if(m_parent->getContainingVertex(global.target).first == nv) target = global.source; + if(parent()->getContainingVertex(global.source).first == nv) target = global.target; + else if(parent()->getContainingVertex(global.target).first == nv) target = global.source; else { i++; continue; } - std::pair res = m_parent->getContainingVertex(target); + std::pair res = parent()->getContainingVertex(target); //get or create the edge between the new vertex and the target LocalEdge e; @@ -1379,7 +1381,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, ClusterMap m_clusters; int test; protected: - boost::shared_ptr m_parent; + boost::weak_ptr m_parent; details::IDpointer m_id; @@ -1509,6 +1511,10 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, }; + +public: + //may hold cluster properties which have Eigen3 objects and therefore need alignment + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; } //namespace solver diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 4e078bf55d7f..d852e9b5665b 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -31,8 +31,12 @@ #include #include #include +#include +#include +#include namespace fusion = boost::fusion; +namespace mpl = boost::mpl; #include "kernel.hpp" @@ -65,8 +69,9 @@ template struct pushed_seq; template -struct op_seq : public seq { - +struct constraint_sequence : public seq { + + //an equation gets added to this equation template typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T val) { @@ -91,13 +96,51 @@ struct op_seq : public seq { //and return our new extendet sequence return vec; }; + + template + void pretty(T type) { + std::cout<<"pretty: "<<__PRETTY_FUNCTION__< + typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type operator &(T val) { + + typedef typename pushed_seq::type Sequence; + typedef typename fusion::result_of::begin::type Begin; + typedef typename fusion::result_of::end::type End; + + typedef typename mpl::distance< typename mpl::begin::type, typename mpl::end::type >::type distanceF; + typedef typename fusion::result_of::advance::type EndF; + + //create the new sequence + Sequence vec; + + //copy the given values into the new sequence + Begin b(vec); + EndF ef(vec); + + fusion::iterator_range range(b, ef); + fusion::copy(val, range); + + //copy the objects value into the new sequence + EndF bb(vec); + End e(vec); + + fusion::iterator_range range2(bb, e); + fusion::copy(*this, range2); + + //and return our new extendet sequence + return vec; + }; }; template struct pushed_seq { - typedef typename boost::mpl::if_, Seq, fusion::vector1 >::type S; - typedef typename fusion::result_of::as_vector< typename boost::mpl::push_back::type >::type vec; - typedef op_seq type; + typedef typename mpl::if_, Seq, fusion::vector1 >::type S1; + typedef typename mpl::if_, T, fusion::vector1 >::type S2; + typedef typename fusion::result_of::as_vector >::type >::type vec; + typedef constraint_sequence type; }; template @@ -116,6 +159,7 @@ struct Equation : public EQ { return operator()(val); }; + //an equation gets added to this equation template typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T val) { @@ -124,6 +168,32 @@ struct Equation : public EQ { fusion::at_c<1>(vec) = *(static_cast(this)); return vec; }; + + //an sequence gets added to this equation (happens only if sequenced equations like coincident are used) + template + typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type operator &(T val) { + + typedef typename pushed_seq::type Sequence; + typedef typename fusion::result_of::begin::type Begin; + typedef typename fusion::result_of::end::type End; + typedef typename fusion::result_of::prior::type EndOld; + + //create the new sequence + Sequence vec; + + //copy the old values into the new sequence + Begin b(vec); + EndOld eo(vec); + + fusion::iterator_range range(b, eo); + fusion::copy(val, range); + + //insert this object at the end of the sequence + fusion::back(vec) = *static_cast(this); + + //and return our new extendet sequence + return vec; + }; }; struct Distance : public Equation { @@ -221,12 +291,15 @@ struct Angle : public Equation { //template definition Scalar calculate(Vector& param1, Vector& param2) { assert(false); + return 0; }; Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { assert(false); + return 0; }; Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { assert(false); + return 0; }; void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { assert(false); diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index 045e68589380..cca0852335e6 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -168,10 +168,10 @@ class Geometry : public Object Dimension; template - Geometry(T geometry, Sys& system); + Geometry(const T& geometry, Sys& system); template - void set(T geometry); + void set(const T& geometry); template typename Visitor::result_type apply(Visitor& vis) { @@ -229,7 +229,7 @@ class Geometry : public Object - void init(T& t); + void init(const T& t); void normalize(); @@ -280,7 +280,7 @@ class Geometry : public Object template -Geometry::Geometry(T geometry, Sys& system) +Geometry::Geometry(const T& geometry, Sys& system) : m_isInCluster(false), m_geometry(geometry), m_parameter(NULL,0,DS(0,0)), m_clusterFixed(false), m_init(false) { @@ -294,7 +294,7 @@ Geometry::Geometry(T geometry, Sys& system template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> template -void Geometry::set(T geometry) { +void Geometry::set(const T& geometry) { m_geometry = geometry; init(geometry); //Base::template emitSignal( ((Derived*)this)->shared_from_this() ); @@ -325,7 +325,7 @@ boost::shared_ptr Geometry::clone template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> template -void Geometry::init(T& t) { +void Geometry::init(const T& t) { m_BaseParameterCount = geometry_traits::tag::parameters::value; m_parameterCount = m_BaseParameterCount; diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp index 16c931cf4d97..c5c9a55233a5 100644 --- a/src/Mod/Assembly/App/opendcm/core/system.hpp +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -201,7 +201,7 @@ class System : public T1::template type< System >::inherit Type1::system_init(*this); Type2::system_init(*this); Type3::system_init(*this); - + }; diff --git a/src/Mod/Assembly/App/opendcm/core/transformation.hpp b/src/Mod/Assembly/App/opendcm/core/transformation.hpp index cec6c0d469b0..91b7057af113 100644 --- a/src/Mod/Assembly/App/opendcm/core/transformation.hpp +++ b/src/Mod/Assembly/App/opendcm/core/transformation.hpp @@ -229,6 +229,9 @@ class Transform { m_rotation.normalize(); return *this; } + +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; template diff --git a/src/Mod/Assembly/App/opendcm/externalize.hpp b/src/Mod/Assembly/App/opendcm/externalize.hpp index 098f1edf5552..7306e7f172e2 100644 --- a/src/Mod/Assembly/App/opendcm/externalize.hpp +++ b/src/Mod/Assembly/App/opendcm/externalize.hpp @@ -20,6 +20,11 @@ #ifndef DCM_EXTERNALIZE_H #define DCM_EXTERNALIZE_H +#ifdef _WIN32 + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) +#endif + #include #include #include diff --git a/src/Mod/Assembly/App/opendcm/module3d.hpp b/src/Mod/Assembly/App/opendcm/module3d.hpp index a62bbb59a02a..db10e08cd4fb 100644 --- a/src/Mod/Assembly/App/opendcm/module3d.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d.hpp @@ -22,10 +22,16 @@ #define DCM_USE_MODULE3D +#ifdef _WIN32 + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) +#endif + #include "module3d/geometry.hpp" #include "module3d/distance.hpp" #include "module3d/parallel.hpp" #include "module3d/angle.hpp" +#include "module3d/coincident.hpp" #include "module3d/module.hpp" #endif //DCM_MODULE3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp index 94d9e9efbeae..4c9d7885020d 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp @@ -21,129 +21,133 @@ #define GCM_ANGLE_HPP #include "geometry.hpp" +#include namespace dcm { - + //the calculations( same as we always calculate directions we can outsource the work to this functions) namespace angle_detail { template -inline typename Kernel::number_type calc(T d1, - T d2, - typename Kernel::number_type angle) { +inline typename Kernel::number_type calc(const T& d1, + const T& d2, + const typename Kernel::number_type& angle) { - return d1.dot(d2) / (d1.norm()*d2.norm()) - angle; + return d1.dot(d2) / (d1.norm()*d2.norm()) - std::cos(angle); }; template -inline typename Kernel::number_type calcGradFirst(T d1, - T d2, - T dd1) { +inline typename Kernel::number_type calcGradFirst(const T& d1, + const T& d2, + const T& dd1) { typename Kernel::number_type norm = d1.norm()*d2.norm(); return dd1.dot(d2)/norm - (d1.dot(d2) * (d1.dot(dd1)/d1.norm())*d2.norm()) / std::pow(norm,2); }; template -inline typename Kernel::number_type calcGradSecond(T d1, - T d2, - T dd2) { +inline typename Kernel::number_type calcGradSecond(const T& d1, + const T& d2, + const T& dd2) { typename Kernel::number_type norm = d1.norm()*d2.norm(); return d1.dot(dd2)/norm - (d1.dot(d2) * (d2.dot(dd2)/d2.norm())*d1.norm()) / std::pow(norm,2); }; template -inline void calcGradFirstComp(T d1, - T d2, - T grad) { +inline void calcGradFirstComp(const T& d1, + const T& d2, + const T& grad) { typename Kernel::number_type norm = d1.norm()*d2.norm(); - grad = d2/norm - (d1.dot(d2)/std::pow(norm,2))*d1/d1.norm(); + const_cast< T& >(grad) = d2/norm - (d1.dot(d2)/std::pow(norm,2))*d1/d1.norm(); }; template -inline void calcGradSecondComp(T d1, - T d2, - T grad) { +inline void calcGradSecondComp(const T& d1, + const T& d2, + const T& grad) { typename Kernel::number_type norm = d1.norm()*d2.norm(); - grad = d1/norm - (d1.dot(d2)/std::pow(norm,2))*d2/d2.norm(); + const_cast< T& >(grad) = d1/norm - (d1.dot(d2)/std::pow(norm,2))*d2/d2.norm(); }; } -/* -template< typename Kernel, typename Tag1, typename Tag2 > -struct Angle3D { + + +template< typename Kernel > +struct Angle::type< Kernel, tag::line3D, tag::line3D > : public dcm::PseudoScale { typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; - Scalar m_angle; - Angle3D(Scalar d = 0.) : m_angle(std::cos(d)) {}; + option_type value; //template definition - void setScale(Scalar scale){ - assert(false); - }; Scalar calculate(Vector& param1, Vector& param2) { - assert(false); + return angle_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), value); }; Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { - assert(false); + return angle_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), dparam1.template segment<3>(3)); }; Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { - assert(false); + return angle_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), dparam2.template segment<3>(3)); }; void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { - assert(false); + gradient.template head<3>().setZero(); + angle_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), gradient.template segment<3>(3)); }; void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { - assert(false); + gradient.template head<3>().setZero(); + angle_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), gradient.template segment<3>(3)); }; }; template< typename Kernel > -struct Angle3D< Kernel, tag::line3D, tag::line3D > { +struct Angle::type< Kernel, tag::line3D, tag::plane3D > : public Angle::type {}; + +template< typename Kernel > +struct Angle::type< Kernel, tag::line3D, tag::cylinder3D > : public Angle::type { - typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; - Scalar m_angle; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + Angle::type::calculateGradientSecondComplete(param1, param2, gradient); + gradient(6)=0; + }; +}; - Angle3D(Scalar d = 0.) : m_angle(std::cos(d)) {}; - - Scalar getEquationScaling(typename Kernel::Vector& local1, typename Kernel::Vector& local2) { - return 1.; - } +template< typename Kernel > +struct Angle::type< Kernel, tag::plane3D, tag::plane3D > : public Angle::type {}; - //template definition - Scalar calculate(Vector& param1, Vector& param2) { - return angle::calc(param1.template tail<3>(), param2.template tail<3>(), m_angle); - }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { - return angle::calcGradFirst(param1.template tail<3>(), param2.template tail<3>(), dparam1.template tail<3>()); - }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { - return angle::calcGradSecond(param1.template tail<3>(), param2.template tail<3>(), dparam2.template tail<3>()); +template< typename Kernel > +struct Angle::type< Kernel, tag::plane3D, tag::cylinder3D > : public Angle::type { + + typedef typename Kernel::VectorMap Vector; + + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + Angle::type::calculateGradientSecondComplete(param1, param2, gradient); + gradient(6)=0; }; +}; + +template< typename Kernel > +struct Angle::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Angle::type { + + typedef typename Kernel::VectorMap Vector; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { - gradient.template head<3>().setZero(); - angle::calcGradFirstComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>()); + Angle::type::calculateGradientFirstComplete(param1, param2, gradient); + gradient(6)=0; }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { - gradient.template head<3>().setZero(); - angle::calcGradSecondComp(param1.template tail<3>(), param2.template tail<3>(), gradient.template tail<3>()); + Angle::type::calculateGradientSecondComplete(param1, param2, gradient); + gradient(6)=0; }; }; -//planes like lines have the direction as segment 3-5, so we can use the same implementations -template< typename Kernel > -struct Angle3D< Kernel, tag::plane3D, tag::plane3D > : public Angle3D {}; -template< typename Kernel > -struct Angle3D< Kernel, tag::line3D, tag::plane3D > : public Angle3D {}; -*/ } -#endif //GCM_ANGLE_HPP \ No newline at end of file +#endif //GCM_ANGLE_HPP diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp index 13cb030ccbd8..d1311fa43d76 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -135,6 +135,9 @@ struct ClusterMath { Scalar calcThreePoints(const typename Kernel::Vector3& p1, const typename Kernel::Vector3& p2, const typename Kernel::Vector3& p3); + +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index f274fac1fdfa..ea6a9c9a1030 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -99,13 +99,13 @@ struct Module3D { #endif public: template - Geometry3D_id(T geometry, Sys& system); + Geometry3D_id(const T& geometry, Sys& system); template - void set(T geometry, Identifier id); + void set(const T& geometry, Identifier id); //somehow the base class set funtion is not found template - void set(T geometry); + void set(const T& geometry); Identifier& getIdentifier(); void setIdentifier(Identifier id); @@ -117,7 +117,7 @@ struct Module3D { typedef vertex_prop vertex_propertie; template - Geometry3D(T geometry, Sys& system); + Geometry3D(const T& geometry, Sys& system); //allow accessing the internals by module3d classes but not by users friend struct details::ClusterMath; @@ -125,6 +125,10 @@ struct Module3D { friend struct details::SystemSolver; friend struct details::SystemSolver::Rescaler; friend class detail::Constraint; + + public: + //the geometry class itself does not hold an aligned eigen object, but maybe the variant + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; template @@ -290,7 +294,7 @@ template template template template -Module3D::type::Geometry3D_id::Geometry3D_id(T geometry, Sys& system) +Module3D::type::Geometry3D_id::Geometry3D_id(const T& geometry, Sys& system) : detail::Geometry(geometry, system) #ifdef USE_LOGGING , log_id("No ID") @@ -306,7 +310,7 @@ template template template template -void Module3D::type::Geometry3D_id::set(T geometry, Identifier id) { +void Module3D::type::Geometry3D_id::set(const T& geometry, Identifier id) { this->template setProperty >(id); Base::set(geometry); }; @@ -315,7 +319,7 @@ template template template template -void Module3D::type::Geometry3D_id::set(T geometry) { +void Module3D::type::Geometry3D_id::set(const T& geometry) { Base::set(geometry); }; @@ -343,7 +347,7 @@ void Module3D::type::Geometry3D_id::setIdentifier(Id template template template -Module3D::type::Geometry3D::Geometry3D(T geometry, Sys& system) +Module3D::type::Geometry3D::Geometry3D(const T& geometry, Sys& system) : mpl::if_, detail::Geometry, Geometry3D_id >::type(geometry, system) { diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp index 9aad3e8f59a6..780dd3f30185 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -33,9 +33,9 @@ namespace dcm { namespace orientation_detail { template -inline typename Kernel::number_type calc(T d1, - T d2, - Direction dir) { +inline typename Kernel::number_type calc(const T& d1, + const T& d2, + const Direction& dir) { switch(dir) { case equal: @@ -54,10 +54,10 @@ inline typename Kernel::number_type calc(T d1, template -inline typename Kernel::number_type calcGradFirst(T d1, - T d2, - T dd1, - Direction dir) { +inline typename Kernel::number_type calcGradFirst(const T& d1, + const T& d2, + const T& dd1, + const Direction& dir) { typename Kernel::number_type res; switch(dir) { @@ -80,10 +80,10 @@ inline typename Kernel::number_type calcGradFirst(T d1, }; template -inline typename Kernel::number_type calcGradSecond(T d1, - T d2, - T dd2, - Direction dir) { +inline typename Kernel::number_type calcGradSecond(const T& d1, + const T& d2, + const T& dd2, + const Direction& dir) { typename Kernel::number_type res; switch(dir) { @@ -105,45 +105,45 @@ inline typename Kernel::number_type calcGradSecond(T d1, }; template -inline void calcGradFirstComp(T d1, - T d2, - T grad, - Direction dir) { +inline void calcGradFirstComp(const T& d1, + const T& d2, + const T& grad, + const Direction& dir) { switch(dir) { case equal: - grad = (d1-d2) / (d1-d2).norm(); + const_cast< T& >(grad) = (d1-d2) / (d1-d2).norm(); return; case opposite: - grad = (d1+d2) / (d1+d2).norm(); + const_cast< T& >(grad) = (d1+d2) / (d1+d2).norm(); return; case parallel: - grad = d2 - d1/d1.norm()*d2.norm(); + const_cast< T& >(grad) = d2 - d1/d1.norm()*d2.norm(); return; case perpendicular: - grad = d2; + const_cast< T& >(grad) = d2; return; } }; template -inline void calcGradSecondComp(T d1, - T d2, - T grad, - Direction dir) { +inline void calcGradSecondComp(const T& d1, + const T& d2, + const T& grad, + const Direction& dir) { switch(dir) { case equal: - grad = (d2-d1) / (d1-d2).norm(); + const_cast< T& >(grad) = (d2-d1) / (d1-d2).norm(); return; case opposite: - grad = (d2+d1) / (d1+d2).norm(); + const_cast< T& >(grad) = (d2+d1) / (d1+d2).norm(); return; case parallel: - grad = d1 - d2/d2.norm()*d1.norm(); + const_cast< T& >(grad) = d1 - d2/d2.norm()*d1.norm(); return; case perpendicular: - grad = d1; + const_cast< T& >(grad) = d1; return; } }; @@ -271,7 +271,16 @@ struct Orientation::type< Kernel, tag::line3D, tag::plane3D > : public Orientati }; template< typename Kernel > -struct Orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > {}; +struct Orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + Orientation::type::calculateGradientSecondComplete(param1, param2, gradient); + gradient(6)=0; + }; +}; template< typename Kernel > struct Orientation::type< Kernel, tag::plane3D, tag::plane3D > : public Orientation::type< Kernel, tag::line3D, tag::line3D > {}; @@ -327,4 +336,4 @@ struct Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public O }; } -#endif +#endif diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp index c52b74bcb786..208cd49cd858 100644 --- a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -103,16 +103,16 @@ struct ModulePart { using Object::m_system; template - Part_base(T geometry, Sys& system, boost::shared_ptr cluster); + Part_base(const T& geometry, Sys& system, boost::shared_ptr cluster); template typename Visitor::result_type apply(Visitor& vis); template - Geom addGeometry3D(T geom, CoordinateFrame frame = Global); + Geom addGeometry3D(const T& geom, CoordinateFrame frame = Global); template - void set(T geometry); + void set(const T& geometry); virtual boost::shared_ptr clone(Sys& newSys); @@ -123,18 +123,22 @@ struct ModulePart { void finishCalculation(); void fix(bool fix_value); + + public: + //we hold a transform and need therefore a aligned new operator + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; struct Part_id : public Part_base { template - Part_id(T geometry, Sys& system, boost::shared_ptr cluster); + Part_id(const T& geometry, Sys& system, boost::shared_ptr cluster); template - typename Part_base::Geom addGeometry3D(T geom, Identifier id, CoordinateFrame frame = Global); + typename Part_base::Geom addGeometry3D(const T& geom, Identifier id, CoordinateFrame frame = Global); template - void set(T geometry, Identifier id); + void set(const T& geometry, Identifier id); bool hasGeometry3D(Identifier id); typename Part_base::Geom getGeometry3D(Identifier id); @@ -148,10 +152,14 @@ struct ModulePart { typedef typename mpl::if_, Part_base, Part_id>::type base; template - Part(T geometry, Sys& system, boost::shared_ptr cluster); + Part(const T& geometry, Sys& system, boost::shared_ptr cluster); friend struct PrepareCluster; friend struct EvaljuateCluster; + + public: + //we hold a transform and need therefore a aligned new operator + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; @@ -160,11 +168,11 @@ struct ModulePart { inheriter_base(); template - Partptr createPart(T geometry); + Partptr createPart(const T& geometry); void removePart(Partptr p); template - void setTransformation(T geom) { + void setTransformation(const T& geom) { typedef typename system_traits::template getModule::type module3d; details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); @@ -215,7 +223,7 @@ struct ModulePart { struct inheriter_id : public inheriter_base { template - Partptr createPart(T geometry, Identifier id); + Partptr createPart(const T& geometry, Identifier id); bool hasPart(Identifier id); Partptr getPart(Identifier id); }; @@ -256,7 +264,7 @@ struct ModulePart { template template template -ModulePart::type::Part_base::Part_base(T geometry, Sys& system, boost::shared_ptr cluster) +ModulePart::type::Part_base::Part_base(const T& geometry, Sys& system, boost::shared_ptr cluster) : Object(system), m_geometry(geometry), m_cluster(cluster) { #ifdef USE_LOGGING @@ -284,7 +292,7 @@ template template template typename ModulePart::template type::Part_base::Geom -ModulePart::type::Part_base::addGeometry3D(T geom, CoordinateFrame frame) { +ModulePart::type::Part_base::addGeometry3D(const T& geom, CoordinateFrame frame) { Geom g(new Geometry3D(geom, *m_system)); if(frame == Local) g->transform(m_transform); @@ -300,7 +308,7 @@ ModulePart::type::Part_base::addGeometry3D(T geom, Coordinate template template template -void ModulePart::type::Part_base::set(T geometry) { +void ModulePart::type::Part_base::set(const T& geometry) { Part_base::m_geometry = geometry; (typename geometry_traits::modell()).template extract::accessor >(geometry, Part_base::m_transform); @@ -355,7 +363,7 @@ void ModulePart::type::Part_base::fix(bool fix_value) { template template template -ModulePart::type::Part_id::Part_id(T geometry, Sys& system, boost::shared_ptr cluster) +ModulePart::type::Part_id::Part_id(const T& geometry, Sys& system, boost::shared_ptr cluster) : Part_base(geometry, system, cluster) { }; @@ -364,7 +372,7 @@ template template template typename ModulePart::template type::Part_base::Geom -ModulePart::type::Part_id::addGeometry3D(T geom, Identifier id, CoordinateFrame frame) { +ModulePart::type::Part_id::addGeometry3D(const T& geom, Identifier id, CoordinateFrame frame) { typename Part_base::Geom g = Part_base::addGeometry3D(geom, frame); g->setIdentifier(id); @@ -374,7 +382,7 @@ ModulePart::type::Part_id::addGeometry3D(T geom, Identifier i template template template -void ModulePart::type::Part_id::set(T geometry, Identifier id) { +void ModulePart::type::Part_id::set(const T& geometry, Identifier id) { Part_base::set(geometry); setIdentifier(id); }; @@ -413,7 +421,7 @@ void ModulePart::type::Part_id::setIdentifier(Identifier id) template template template -ModulePart::type::Part::Part(T geometry, Sys& system, boost::shared_ptr cluster) +ModulePart::type::Part::Part(const T& geometry, Sys& system, boost::shared_ptr cluster) : mpl::if_, Part_base, Part_id>::type(geometry, system, cluster) { @@ -429,13 +437,13 @@ template template template typename ModulePart::template type::Partptr -ModulePart::type::inheriter_base::createPart(T geometry) { +ModulePart::type::inheriter_base::createPart(const T& geometry) { typedef typename system_traits::Cluster Cluster; std::pair, LocalVertex> res = m_this->m_cluster->createCluster(); Partptr p(new Part(geometry, * ((Sys*) this), res.first)); - m_this->m_cluster->template setObject (res.second, p); + m_this->m_cluster->template setObject (res.second, p); m_this->push_back(p); res.first->template setClusterProperty(clusterPart); @@ -487,7 +495,7 @@ template template template typename ModulePart::template type::Partptr -ModulePart::type::inheriter_id::createPart(T geometry, Identifier id) { +ModulePart::type::inheriter_id::createPart(const T& geometry, Identifier id) { Partptr p = inheriter_base::createPart(geometry); p->setIdentifier(id); return p; diff --git a/src/Mod/Assembly/App/opendcm/modulepart.hpp b/src/Mod/Assembly/App/opendcm/modulepart.hpp index b121ea2e322d..d4806fba6705 100644 --- a/src/Mod/Assembly/App/opendcm/modulepart.hpp +++ b/src/Mod/Assembly/App/opendcm/modulepart.hpp @@ -22,6 +22,11 @@ #define DCM_USE_MODULEPART +#ifdef _WIN32 + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) +#endif + #include "modulePart/geometry.hpp" #include "modulePart/module.hpp" diff --git a/src/Mod/Assembly/App/opendcm/modulestate.hpp b/src/Mod/Assembly/App/opendcm/modulestate.hpp index 3b5ef5f07499..ace674acac62 100644 --- a/src/Mod/Assembly/App/opendcm/modulestate.hpp +++ b/src/Mod/Assembly/App/opendcm/modulestate.hpp @@ -22,6 +22,11 @@ #define DCM_USE_MODULESTATE +#ifdef _WIN32 + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) +#endif + #include "moduleState/module.hpp" #include "moduleState/traits.hpp" diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index c0acd9477309..482327b03845 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -36,6 +36,12 @@ #include "ViewProviderPart.h" #include "ViewProviderAssembly.h" #include "ViewProviderConstraintGroup.h" +#include "ViewProviderConstraintFix.h" +#include "ViewProviderConstraintDistance.h" +#include "ViewProviderConstraintAngle.h" +#include "ViewProviderConstraintOrientation.h" +#include "ViewProviderConstraintCoincidence.h" +#include "ViewProviderConstraintAlignment.h" #include @@ -84,6 +90,12 @@ void AssemblyGuiExport initAssemblyGui() AssemblyGui::ViewProviderItemAssembly::init(); AssemblyGui::ViewProviderConstraintGroup::init(); + AssemblyGui::ViewProviderConstraintFix::init(); + AssemblyGui::ViewProviderConstraintDistance::init(); + AssemblyGui::ViewProviderConstraintAngle::init(); + AssemblyGui::ViewProviderConstraintOrientation::init(); + AssemblyGui::ViewProviderConstraintCoincidence::init(); + AssemblyGui::ViewProviderConstraintAlignment::init(); // add resources and reloads the translators loadAssemblyResource(); diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 133be2982fd4..4779c12e2894 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -28,6 +28,10 @@ set(AssemblyGui_LIBS qt4_add_resources(AssemblyGui_SRCS Resources/Assembly.qrc) +set(AssemblyGui_UIC_SRCS + AlignmentDialog.ui +) +qt4_wrap_ui(AssemblyGui_UIC_HDRS ${AssemblyGui_UIC_SRCS}) SET(AssemblyGuiViewProvider_SRCS ViewProvider.cpp @@ -38,14 +42,26 @@ SET(AssemblyGuiViewProvider_SRCS ViewProviderAssembly.h ViewProviderConstraintGroup.cpp ViewProviderConstraintGroup.h + ViewProviderConstraintFix.cpp + ViewProviderConstraintFix.h + ViewProviderConstraintDistance.cpp + ViewProviderConstraintDistance.h + ViewProviderConstraintAngle.cpp + ViewProviderConstraintAngle.h + ViewProviderConstraintOrientation.cpp + ViewProviderConstraintOrientation.h + ViewProviderConstraintCoincidence.cpp + ViewProviderConstraintCoincidence.h + ViewProviderConstraintAlignment.cpp + ViewProviderConstraintAlignment.h ) SOURCE_GROUP("ViewProvider" FILES ${AssemblyGuiViewProvider_SRCS}) -SET(AssemblyGuiModule_SRCS +SET(AssemblyGuiModule_SRCS AppAssemblyGui.cpp AppAssemblyGuiPy.cpp Command.cpp - CommandConstraints.cpp + CommandConstraints.cpp Resources/Assembly.qrc qrc_Assembly.cxx PreCompiled.cpp @@ -60,6 +76,7 @@ SET(AssemblyGui_SRCS ${AssemblyGui_SRCS} ${AssemblyGuiViewProvider_SRCS} ${AssemblyGuiModule_SRCS} + ${AssemblyGui_UIC_HDRS} ) add_library(AssemblyGui SHARED ${AssemblyGui_SRCS}) diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index f655e857d133..4af10a38c584 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -77,7 +77,7 @@ void CmdAssemblyAddNewPart::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemPart','%s')",PartName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); - doCommand(Doc,"App.activeDocument().%s.addPart(App.activeDocument().%s) ",fatherName.c_str(),PartName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),PartName.c_str()); } Command::addModule(App,"PartDesign"); Command::addModule(Gui,"PartDesignGui"); @@ -139,7 +139,7 @@ void CmdAssemblyAddNewComponent::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','%s')",CompName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); - doCommand(Doc,"App.activeDocument().%s.addComponent(App.activeDocument().%s) ",fatherName.c_str(), CompName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Items = App.activeDocument().%s.Items + [App.activeDocument().%s] ",fatherName.c_str(),fatherName.c_str(),CompName.c_str()); } } diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index e46651e4f5f4..198dbff5a949 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +#include #endif #include @@ -31,6 +32,7 @@ #include #include #include +#include "ui_AlignmentDialog.h" #include #include @@ -97,22 +99,22 @@ std::string asSubLinkString(Assembly::ItemPart* part, std::string element) { //=========================================================================== -DEF_STD_CMD(CmdAssemblyConstraintAxle); +DEF_STD_CMD(CmdAssemblyConstraintDistance); -CmdAssemblyConstraintAxle::CmdAssemblyConstraintAxle() - :Command("Assembly_ConstraintAxle") +CmdAssemblyConstraintDistance::CmdAssemblyConstraintDistance() + :Command("Assembly_ConstraintDistance") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); - sMenuText = QT_TR_NOOP("Constraint Axle..."); - sToolTipText = QT_TR_NOOP("set a axle constraint between two objects"); + sMenuText = QT_TR_NOOP("Constraint Distance..."); + sToolTipText = QT_TR_NOOP("Set the distance between two selected entitys"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; - sPixmap = "actions/Axle_constraint"; + sPixmap = "Assembly_ConstraintDistance"; } -void CmdAssemblyConstraintAxle::activated(int iMsg) +void CmdAssemblyConstraintDistance::activated(int iMsg) { Assembly::ItemAssembly *Asm=0; Assembly::ConstraintGroup *ConstGrp=0; @@ -133,13 +135,23 @@ void CmdAssemblyConstraintAxle::activated(int iMsg) Base::Console().Message("The selected objects need to belong to the active assembly\n"); return; }; + + bool ok; + double d = QInputDialog::getDouble(NULL, QObject::tr("Constraint value"), + QObject::tr("Distance:"), 0., -10000., 10000., 2, &ok); + if(!ok) + return; - openCommand("Insert Constraint Axle"); - std::string ConstrName = getUniqueObjectName("Axle"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintAxis','%s')",ConstrName.c_str()); + openCommand("Insert Constraint Distance"); + std::string ConstrName = getUniqueObjectName("Distance"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintDistance','%s')",ConstrName.c_str()); doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().%s.addConstraint(App.activeDocument().ActiveObject)",ConstGrp->getNameInDocument()); + doCommand(Doc,"App.activeDocument().ActiveObject.Distance = %f", d); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + + commitCommand(); + updateActive(); } @@ -153,7 +165,7 @@ CmdAssemblyConstraintFix::CmdAssemblyConstraintFix() sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); sMenuText = QT_TR_NOOP("Constraint Fix..."); - sToolTipText = QT_TR_NOOP("Fixes a part in it's rotation and translation"); + sToolTipText = QT_TR_NOOP("Fix a part in it's rotation and translation"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Assembly_ConstraintLock"; @@ -185,7 +197,257 @@ void CmdAssemblyConstraintFix::activated(int iMsg) std::string ConstrName = getUniqueObjectName("Fix"); doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintFix','%s')",ConstrName.c_str()); doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().%s.addConstraint(App.activeDocument().ActiveObject)",ConstGrp->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + + commitCommand(); + updateActive(); +} + +/******************************************************************************************/ + + +DEF_STD_CMD(CmdAssemblyConstraintAngle); + +CmdAssemblyConstraintAngle::CmdAssemblyConstraintAngle() + :Command("Assembly_ConstraintAngle") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint Angle..."); + sToolTipText = QT_TR_NOOP("Set the angle between two selected entitys"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Assembly_ConstraintAngle"; +} + + +void CmdAssemblyConstraintAngle::activated(int iMsg) +{ + Assembly::ItemAssembly *Asm=0; + Assembly::ConstraintGroup *ConstGrp=0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm,&ConstGrp)) + return; + + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { + Base::Console().Message("you must select two geometries on two diffrent parts\n"); + return; + }; + + Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); + Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); + if(!part1 || !part2) { + Base::Console().Message("The selected objects need to belong to the active assembly\n"); + return; + }; + + bool ok; + double d = QInputDialog::getDouble(NULL, QObject::tr("Constraint value"), + QObject::tr("Angle:"), 0., 0., 360., 2, &ok); + if(!ok) + return; + + openCommand("Insert Constraint Angle"); + std::string ConstrName = getUniqueObjectName("Angle"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintAngle','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Angle = %f", d); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + + commitCommand(); + updateActive(); + +} + + +/******************************************************************************************/ + + +DEF_STD_CMD(CmdAssemblyConstraintOrientation); + +CmdAssemblyConstraintOrientation::CmdAssemblyConstraintOrientation() + :Command("Assembly_ConstraintOrientation") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint Orientation..."); + sToolTipText = QT_TR_NOOP("Set the orientation of two selected entitys in regard to each other"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Assembly_ConstraintOrientation"; +} + + +void CmdAssemblyConstraintOrientation::activated(int iMsg) +{ + Assembly::ItemAssembly *Asm=0; + Assembly::ConstraintGroup *ConstGrp=0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm,&ConstGrp)) + return; + + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { + Base::Console().Message("you must select two geometries on two diffrent parts\n"); + return; + }; + + Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); + Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); + if(!part1 || !part2) { + Base::Console().Message("The selected objects need to belong to the active assembly\n"); + return; + }; + + QStringList items; + items << QObject::tr("Parallel") << QObject::tr("Perpendicular") << QObject::tr("Equal") << QObject::tr("Opposite"); + + bool ok; + QString item = QInputDialog::getItem(NULL, QObject::tr("Constraint value"), + QObject::tr("Orientation:"), items, 0, false, &ok); + if (!ok || item.isEmpty()) + return; + + openCommand("Insert Constraint Orientation"); + std::string ConstrName = getUniqueObjectName("Orientation"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintOrientation','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + + commitCommand(); + updateActive(); + +} + +/******************************************************************************************/ + + +DEF_STD_CMD(CmdAssemblyConstraintCoincidence); + +CmdAssemblyConstraintCoincidence::CmdAssemblyConstraintCoincidence() + :Command("Assembly_ConstraintCoincidence") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint coincidence..."); + sToolTipText = QT_TR_NOOP("Make the selected entitys coincident"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Assembly_ConstraintCoincidence"; +} + + +void CmdAssemblyConstraintCoincidence::activated(int iMsg) +{ + Assembly::ItemAssembly *Asm=0; + Assembly::ConstraintGroup *ConstGrp=0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm,&ConstGrp)) + return; + + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { + Base::Console().Message("you must select two geometries on two diffrent parts\n"); + return; + }; + + Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); + Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); + if(!part1 || !part2) { + Base::Console().Message("The selected objects need to belong to the active assembly\n"); + return; + }; + + QStringList items; + items << QObject::tr("Parallel") << QObject::tr("Equal") << QObject::tr("Opposite"); + + bool ok; + QString item = QInputDialog::getItem(NULL, QObject::tr("Constraint value"), + QObject::tr("Orientation:"), items, 0, false, &ok); + if (!ok || item.isEmpty()) + return; + + openCommand("Insert Constraint Coincidence"); + std::string ConstrName = getUniqueObjectName("Coincidence"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintCoincidence','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + + commitCommand(); + updateActive(); + +} + +/******************************************************************************************/ + + +DEF_STD_CMD(CmdAssemblyConstraintAlignment); + +CmdAssemblyConstraintAlignment::CmdAssemblyConstraintAlignment() + :Command("Assembly_ConstraintAlignment") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint allignment..."); + sToolTipText = QT_TR_NOOP("Align the selected entitys"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Assembly_ConstraintAlignment"; +} + + +void CmdAssemblyConstraintAlignment::activated(int iMsg) +{ + Assembly::ItemAssembly *Asm=0; + Assembly::ConstraintGroup *ConstGrp=0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm,&ConstGrp)) + return; + + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { + Base::Console().Message("you must select two geometries on two diffrent parts\n"); + return; + }; + + Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); + Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); + if(!part1 || !part2) { + Base::Console().Message("The selected objects need to belong to the active assembly\n"); + return; + }; + + QStringList items; + items << QObject::tr("Parallel") << QObject::tr("Equal") << QObject::tr("Opposite"); + + QDialog dialog; + Ui_AlignmentDialog ui; + ui.setupUi(&dialog); + ui.comboBox->addItems(items); + if( dialog.exec() != QDialog::Accepted ) + return; + + openCommand("Insert Constraint Alignment"); + std::string ConstrName = getUniqueObjectName("Alignment"); + doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintAlignment','%s')",ConstrName.c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Orientation = '%s'", ui.comboBox->currentText().toStdString().c_str()); + doCommand(Doc,"App.activeDocument().ActiveObject.Offset = %f", ui.doubleSpinBox->value()); + doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); + + commitCommand(); + updateActive(); } @@ -194,5 +456,9 @@ void CreateAssemblyConstraintCommands(void) Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdAssemblyConstraintFix()); - rcCmdMgr.addCommand(new CmdAssemblyConstraintAxle()); + rcCmdMgr.addCommand(new CmdAssemblyConstraintDistance()); + rcCmdMgr.addCommand(new CmdAssemblyConstraintAngle()); + rcCmdMgr.addCommand(new CmdAssemblyConstraintOrientation()); + rcCmdMgr.addCommand(new CmdAssemblyConstraintCoincidence()); + rcCmdMgr.addCommand(new CmdAssemblyConstraintAlignment()); } diff --git a/src/Mod/Assembly/Gui/Resources/Assembly.qrc b/src/Mod/Assembly/Gui/Resources/Assembly.qrc index d670d89566f4..b680f4637f39 100644 --- a/src/Mod/Assembly/Gui/Resources/Assembly.qrc +++ b/src/Mod/Assembly/Gui/Resources/Assembly.qrc @@ -1,7 +1,11 @@ - icons/actions/Axle_constraint.svg icons/Assembly_ConstraintLock.svg + icons/Assembly_ConstraintDistance.svg + icons/Assembly_ConstraintAngle.svg + icons/Assembly_ConstraintOrientation.svg + icons/Assembly_ConstraintCoincidence.svg + icons/Assembly_ConstraintAlignment.svg translations/Assembly_af.qm translations/Assembly_de.qm translations/Assembly_fi.qm diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAngle.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAngle.svg new file mode 100644 index 000000000000..7d78cca9575f --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAngle.svg @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp new file mode 100644 index 000000000000..b602be39e21d --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraintAlignment.h" + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintAlignment, Gui::ViewProviderDocumentObject) + +ViewProviderConstraintAlignment::ViewProviderConstraintAlignment() { + + sPixmap = "Assembly_ConstraintAlignment"; +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h new file mode 100644 index 000000000000..38d2fadde932 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTAlignment_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTAlignment_H + +#include + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintAlignment : public Gui::ViewProviderDocumentObject { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintAlignment); + +public: + ViewProviderConstraintAlignment(); + +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp new file mode 100644 index 000000000000..229f80869f56 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraintAngle.h" + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintAngle, Gui::ViewProviderDocumentObject) + +ViewProviderConstraintAngle::ViewProviderConstraintAngle() { + + sPixmap = "Assembly_ConstraintAngle"; +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h new file mode 100644 index 000000000000..cd68cbe8c47e --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTANGLE_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTANGLE_H + +#include + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintAngle : public Gui::ViewProviderDocumentObject { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintAngle); + +public: + ViewProviderConstraintAngle(); + +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp new file mode 100644 index 000000000000..eeca7d5c024c --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraintCoincidence.h" + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintCoincidence, Gui::ViewProviderDocumentObject) + +ViewProviderConstraintCoincidence::ViewProviderConstraintCoincidence() { + + sPixmap = "Assembly_ConstraintCoincidence"; +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h new file mode 100644 index 000000000000..a4cbacd734b4 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTCoincidence_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTCoincidence_H + +#include + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintCoincidence : public Gui::ViewProviderDocumentObject { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintCoincidence); + +public: + ViewProviderConstraintCoincidence(); + +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp new file mode 100644 index 000000000000..817a6432f567 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraintDistance.h" + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintDistance, Gui::ViewProviderDocumentObject) + +ViewProviderConstraintDistance::ViewProviderConstraintDistance() { + + sPixmap = "Assembly_ConstraintDistance"; +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h new file mode 100644 index 000000000000..1c1c1c364465 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTDISTANCE_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTDISTANCE_H + +#include + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintDistance : public Gui::ViewProviderDocumentObject { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintDistance); + +public: + ViewProviderConstraintDistance(); + +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp index 1a10eda3f894..a03662c2dd91 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp @@ -65,7 +65,7 @@ void ViewProviderConstraintGroup::setDisplayMode(const char* ModeName) if ( strcmp("Main",ModeName)==0 ) setDisplayMaskMode("Main"); -// ViewProviderDocumentObject::setDisplayMode( ModeName ); + ViewProviderDocumentObject::setDisplayMode( ModeName ); } std::vector ViewProviderConstraintGroup::getDisplayModes(void) const @@ -74,7 +74,7 @@ std::vector ViewProviderConstraintGroup::getDisplayModes(void) cons std::vector StrList = ViewProviderDocumentObject::getDisplayModes(); // add your own modes -// StrList.push_back("Main"); + StrList.push_back("Main"); return StrList; } diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp new file mode 100644 index 000000000000..4240613c49ce --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraintOrientation.h" + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintOrientation, Gui::ViewProviderDocumentObject) + +ViewProviderConstraintOrientation::ViewProviderConstraintOrientation() { + + sPixmap = "Assembly_ConstraintOrientation"; +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h new file mode 100644 index 000000000000..1109d5d89be5 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTORIENTATION_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTORIENTATION_H + +#include + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintOrientation : public Gui::ViewProviderDocumentObject { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintOrientation); + +public: + ViewProviderConstraintOrientation(); + +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index 6d042316d18c..3db61cf6bf3f 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -52,8 +52,12 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand(QT_TR_NOOP("Assembly")); - //*part << "Assembly_ConstraintFix"; - *part << "Assembly_ConstraintAxle"; + *part << "Assembly_ConstraintFix"; + *part << "Assembly_ConstraintDistance"; + *part << "Assembly_ConstraintOrientation"; + *part << "Assembly_ConstraintAngle"; + *part << "Assembly_ConstraintCoincidence"; + *part << "Assembly_ConstraintAlignment"; *part << "Separator"; *part << "Assembly_AddNewPart"; *part << "Assembly_AddNewComponent"; @@ -70,7 +74,12 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* asmCmd = new Gui::MenuItem(); root->insertItem(item, asmCmd); asmCmd->setCommand("&Assembly"); - *asmCmd << "Assembly_ConstraintAxle" + *asmCmd << "Assembly_ConstraintFix" + << "Assembly_ConstraintDistance" + << "Assembly_ConstraintOrientation" + << "Assembly_ConstraintAngle" + << "Assembly_ConstraintCoincidence" + << "Assembly_ConstraintAlignment" << "Separator" << "Assembly_AddNewPart" << "Assembly_AddNewComponent" From d4f788f9e31f4fa7b4bd28320a2e1469b9cb147d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 13 May 2013 16:21:41 +0200 Subject: [PATCH 053/664] remove unneeded files --- src/Mod/Assembly/App/ConstraintAxis.cpp | 84 ---------------------- src/Mod/Assembly/App/ConstraintAxis.h | 60 ---------------- src/Mod/Assembly/App/ConstraintContact.cpp | 59 --------------- src/Mod/Assembly/App/ConstraintContact.h | 57 --------------- src/Mod/Assembly/App/ConstraintOffset.cpp | 59 --------------- src/Mod/Assembly/App/ConstraintOffset.h | 58 --------------- 6 files changed, 377 deletions(-) delete mode 100644 src/Mod/Assembly/App/ConstraintAxis.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintAxis.h delete mode 100644 src/Mod/Assembly/App/ConstraintContact.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintContact.h delete mode 100644 src/Mod/Assembly/App/ConstraintOffset.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintOffset.h diff --git a/src/Mod/Assembly/App/ConstraintAxis.cpp b/src/Mod/Assembly/App/ConstraintAxis.cpp deleted file mode 100644 index 1361e88c0782..000000000000 --- a/src/Mod/Assembly/App/ConstraintAxis.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel - * 2013 Stefan Tröger - * * - * 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 -#include - -#include "ConstraintAxis.h" -#include "ConstraintAxisPy.h" - -#include "ItemPart.h" - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintAxis, Assembly::Constraint) - -ConstraintAxis::ConstraintAxis() -{ - -} - -PyObject *ConstraintAxis::getPyObject(void) -{ - if (PythonObject.is(Py::_None())){ - // ref counter is set to 1 - PythonObject = Py::Object(new ConstraintAxisPy(this),true); - } - return Py::new_reference_to(PythonObject); -} - -short ConstraintAxis::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintAxis::execute(void) -{ - Base::Console().Message("Recalculate axis constraint\n"); - return App::DocumentObject::StdReturn; -} - -void ConstraintAxis::init(boost::shared_ptr< Solver > solver) -{ - Base::Console().Message("Init constraint axis\n"); - - //init the parts and geometries - Constraint::init(solver); - - //init the constraint - m_constraint = solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::distance = 0); -} - - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAxis.h b/src/Mod/Assembly/App/ConstraintAxis.h deleted file mode 100644 index f0e8bc1085a7..000000000000 --- a/src/Mod/Assembly/App/ConstraintAxis.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 Assembly_ConstraintAxis_H -#define Assembly_ConstraintAxis_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintAxis : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintAxis); - -public: - ConstraintAxis(); - - PyObject *getPyObject(void); - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraintAxis"; - //} - //@} - - virtual void init(boost::shared_ptr solver); -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintAxis_H diff --git a/src/Mod/Assembly/App/ConstraintContact.cpp b/src/Mod/Assembly/App/ConstraintContact.cpp deleted file mode 100644 index 94c28bc71002..000000000000 --- a/src/Mod/Assembly/App/ConstraintContact.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 - -#include "ConstraintContact.h" - - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintContact, Assembly::Constraint) - -ConstraintContact::ConstraintContact() -{ - -} - -short ConstraintContact::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintContact::execute(void) -{ - - return App::DocumentObject::StdReturn; -} - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintContact.h b/src/Mod/Assembly/App/ConstraintContact.h deleted file mode 100644 index 659bf4000ea2..000000000000 --- a/src/Mod/Assembly/App/ConstraintContact.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 Assembly_ConstraintContact_H -#define Assembly_ConstraintContact_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintContact : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintContact); - -public: - ConstraintContact(); - - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraintContact"; - //} - //@} -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintContact_H diff --git a/src/Mod/Assembly/App/ConstraintOffset.cpp b/src/Mod/Assembly/App/ConstraintOffset.cpp deleted file mode 100644 index e9b62e957614..000000000000 --- a/src/Mod/Assembly/App/ConstraintOffset.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 - -#include "ConstraintOffset.h" - - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintOffset, Assembly::Constraint) - -ConstraintOffset::ConstraintOffset() -{ - ADD_PROPERTY(Offset,(0)); -} - -short ConstraintOffset::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintOffset::execute(void) -{ - - return App::DocumentObject::StdReturn; -} - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintOffset.h b/src/Mod/Assembly/App/ConstraintOffset.h deleted file mode 100644 index 26cdd20a32de..000000000000 --- a/src/Mod/Assembly/App/ConstraintOffset.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 Assembly_ConstraintOffset_H -#define Assembly_ConstraintOffset_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintOffset : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintOffset); - -public: - ConstraintOffset(); - - App::PropertyFloat Offset; - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - //const char* getViewProviderName(void) const { - // return "PartDesignGui::ViewProviderConstraintOffset"; - //} - //@} -}; - -} //namespace PartDesign - - -#endif // PART_ConstraintOffset_H From 394085133ccb4dad6e4bf0edc93e97b94b6b4463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 13 May 2013 18:05:57 +0200 Subject: [PATCH 054/664] add missing files --- .../Assembly/App/opendcm/core/equations.hpp | 2 +- .../App/opendcm/module3d/coincident.hpp | 168 ++++++ .../App/opendcm/module3d/parallel.hpp | 37 +- src/Mod/Assembly/Gui/AlignmentDialog.ui | 111 ++++ .../icons/Assembly_ConstraintAlignment.svg | 337 +++++++++++ .../icons/Assembly_ConstraintCoincidence.svg | 483 ++++++++++++++++ .../icons/Assembly_ConstraintDistance.svg | 369 ++++++++++++ .../icons/Assembly_ConstraintOrientation.svg | 541 ++++++++++++++++++ .../Gui/ViewProviderConstraintFix.cpp | 34 ++ .../Assembly/Gui/ViewProviderConstraintFix.h | 42 ++ 10 files changed, 2109 insertions(+), 15 deletions(-) create mode 100644 src/Mod/Assembly/App/opendcm/module3d/coincident.hpp create mode 100644 src/Mod/Assembly/Gui/AlignmentDialog.ui create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAlignment.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintCoincidence.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintDistance.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOrientation.svg create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintFix.h diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index d852e9b5665b..8f3caae4503f 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -238,7 +238,7 @@ struct Distance : public Equation { }; //the possible directions -enum Direction { equal, opposite, parallel, perpendicular }; +enum Direction { parallel, equal, opposite, perpendicular }; struct Orientation : public Equation { diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp new file mode 100644 index 000000000000..0bbe62b85676 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -0,0 +1,168 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_COINCIDENT_HPP +#define DCM_COINCIDENT_HPP + +#include +#include "distance.hpp" + +namespace dcm { + +namespace details { + +//we need a custom orientation type to allow coincidents with points +struct ci_orientation : public Equation { + + using Equation::operator=; + ci_orientation() : Equation(parallel) {}; + + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + option_type value; + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::point3D, tag::point3D > : public dcm::PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + Scalar calculate(Vector& param1, Vector& param2) { + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.setZero(); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + gradient.setZero(); + }; +}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::point3D, tag::line3D > : public ci_orientation::type< Kernel, tag::point3D, tag::point3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::point3D, tag::plane3D > : public ci_orientation::type< Kernel, tag::point3D, tag::point3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::point3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::point3D, tag::point3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::line3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; + +}//details + +struct Coincidence : public dcm::constraint_sequence< fusion::vector2< Distance, details::ci_orientation > > { + //allow to set the distance + Coincidence& operator()(Direction val) { + fusion::at_c<1>(*this) = val; + return *this; + }; + Coincidence& operator=(Direction val) { + fusion::at_c<1>(*this) = val; + return *this; + }; +}; + +struct Alignment : public dcm::constraint_sequence< fusion::vector2< Distance, details::ci_orientation > > { + //allow to set the distance + Alignment& operator()(Direction val) { + fusion::at_c<1>(*this) = val; + return *this; + }; + Alignment& operator()(double val) { + fusion::at_c<0>(*this) = val; + return *this; + }; + Alignment& operator()(double val1, Direction val2) { + fusion::at_c<0>(*this) = val1; + fusion::at_c<1>(*this) = val2; + return *this; + }; + Alignment& operator()(Direction val1, double val2) { + fusion::at_c<0>(*this) = val2; + fusion::at_c<1>(*this) = val1; + return *this; + }; + Alignment& operator=(Direction val) { + fusion::at_c<1>(*this) = val; + return *this; + }; + Alignment& operator=(double val) { + fusion::at_c<0>(*this) = val; + return *this; + }; +}; + +//no standart equation, create our own object +static Coincidence coincidence; +static Alignment alignment; + +}//dcm + + +#endif //DCM_COINCIDENT_HPP diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp index 780dd3f30185..2dafc2043d57 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -38,12 +38,13 @@ inline typename Kernel::number_type calc(const T& d1, const Direction& dir) { switch(dir) { + case parallel: + if(d1.dot(d2) < 0) + return (d1+d2).norm(); case equal: return (d1-d2).norm(); case opposite: return (d1+d2).norm(); - case parallel: - return d1.dot(d2) - d1.norm()*d2.norm(); case perpendicular: return d1.dot(d2); default: @@ -61,15 +62,17 @@ inline typename Kernel::number_type calcGradFirst(const T& d1, typename Kernel::number_type res; switch(dir) { + case parallel: + if(d1.dot(d2) < 0) { + res= ((d1+d2).dot(dd1) / (d1+d2).norm()); + break; + } case equal: res = ((d1-d2).dot(dd1) / (d1-d2).norm()); break; case opposite: res= ((d1+d2).dot(dd1) / (d1+d2).norm()); break; - case parallel: - res = dd1.dot(d2) - d1.dot(dd1)/d1.norm()*d2.norm(); - break; case perpendicular: res = dd1.dot(d2); break; @@ -87,15 +90,17 @@ inline typename Kernel::number_type calcGradSecond(const T& d1, typename Kernel::number_type res; switch(dir) { + case parallel: + if(d1.dot(d2) < 0) { + res = ((d1+d2).dot(dd2) / (d1+d2).norm()); + break; + } case equal: res = ((d1-d2).dot(-dd2) / (d1-d2).norm()); break; case opposite: res = ((d1+d2).dot(dd2) / (d1+d2).norm()); break; - case parallel: - res = d1.dot(dd2) - d2.dot(dd2)/d2.norm()*d1.norm(); - break; case perpendicular: res = d1.dot(dd2); break; @@ -111,15 +116,17 @@ inline void calcGradFirstComp(const T& d1, const Direction& dir) { switch(dir) { + case parallel: + if(d1.dot(d2) < 0) { + const_cast< T& >(grad) = (d1+d2) / (d1+d2).norm(); + return; + } case equal: const_cast< T& >(grad) = (d1-d2) / (d1-d2).norm(); return; case opposite: const_cast< T& >(grad) = (d1+d2) / (d1+d2).norm(); return; - case parallel: - const_cast< T& >(grad) = d2 - d1/d1.norm()*d2.norm(); - return; case perpendicular: const_cast< T& >(grad) = d2; return; @@ -133,15 +140,17 @@ inline void calcGradSecondComp(const T& d1, const Direction& dir) { switch(dir) { + case parallel: + if(d1.dot(d2) < 0) { + const_cast< T& >(grad) = (d2+d1) / (d1+d2).norm(); + return; + } case equal: const_cast< T& >(grad) = (d2-d1) / (d1-d2).norm(); return; case opposite: const_cast< T& >(grad) = (d2+d1) / (d1+d2).norm(); return; - case parallel: - const_cast< T& >(grad) = d1 - d2/d2.norm()*d1.norm(); - return; case perpendicular: const_cast< T& >(grad) = d1; return; diff --git a/src/Mod/Assembly/Gui/AlignmentDialog.ui b/src/Mod/Assembly/Gui/AlignmentDialog.ui new file mode 100644 index 000000000000..e02156e12a68 --- /dev/null +++ b/src/Mod/Assembly/Gui/AlignmentDialog.ui @@ -0,0 +1,111 @@ + + + AlignmentDialog + + + + 0 + 0 + 270 + 95 + + + + Constraint value + + + + + + + + + 0 + 0 + + + + Offset: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Orientation: + + + + + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + AlignmentDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AlignmentDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAlignment.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAlignment.svg new file mode 100644 index 000000000000..f5b69e51abfd --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintAlignment.svg @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintCoincidence.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintCoincidence.svg new file mode 100644 index 000000000000..a0910aaebe90 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintCoincidence.svg @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintDistance.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintDistance.svg new file mode 100644 index 000000000000..d4d00bb3469d --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintDistance.svg @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOrientation.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOrientation.svg new file mode 100644 index 000000000000..37d12ebc41a0 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOrientation.svg @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp new file mode 100644 index 000000000000..f3f9d22efc33 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraintFix.h" + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintFix, Gui::ViewProviderDocumentObject) + +ViewProviderConstraintFix::ViewProviderConstraintFix() { + + sPixmap = "Assembly_ConstraintLock"; +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h new file mode 100644 index 000000000000..d4fabcc0c2e0 --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTFIX_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTFIX_H + +#include + +namespace AssemblyGui { + +class AssemblyGuiExport ViewProviderConstraintFix : public Gui::ViewProviderDocumentObject { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintFix); + +public: + ViewProviderConstraintFix(); + +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H From 6654b859eb66c6d30c6651765171149b5d0db1ea Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 28 Mar 2013 17:30:10 +0430 Subject: [PATCH 055/664] Fixed build error on Ubuntu --- src/Base/Uuid.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Base/Uuid.cpp b/src/Base/Uuid.cpp index c75b5fa2abf9..633b3b1916a4 100644 --- a/src/Base/Uuid.cpp +++ b/src/Base/Uuid.cpp @@ -27,6 +27,8 @@ # include #endif +#include + /// Here the FreeCAD includes sorted by Base,App,Gui...... #include "Uuid.h" #include "Exception.h" From 5dbc66ae849056968f494c44386bb09aea13e76e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 29 Mar 2013 20:07:26 +0430 Subject: [PATCH 056/664] Integrated PartDesign::Pad into Body feature workflow --- src/Mod/PartDesign/App/Body.cpp | 52 +- src/Mod/PartDesign/App/Body.h | 11 + src/Mod/PartDesign/App/Feature.cpp | 17 +- src/Mod/PartDesign/App/Feature.h | 9 +- src/Mod/PartDesign/App/FeaturePad.cpp | 19 +- src/Mod/PartDesign/Gui/Command.cpp | 2762 +++++++++---------- src/Mod/PartDesign/Gui/Command.cpp.orig | 1993 ++++++++----- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 14 +- 8 files changed, 2781 insertions(+), 2096 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 0af02620ef07..c255f871552e 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -31,6 +31,8 @@ #include "Body.h" #include "BodyPy.h" +#include + using namespace PartDesign; @@ -51,18 +53,54 @@ short Body::mustExecute() const return 0; } -App::DocumentObjectExecReturn *Body::execute(void) +const Part::TopoShape Body::getTipShape() { // TODO right selection for Body App::DocumentObject* link = Tip.getValue(); if (!link) - //return new App::DocumentObjectExecReturn("No object!"); - return App::DocumentObject::StdReturn; + return Part::TopoShape(); + //Base::Console().Error("Body tip: %s\n", link->getNameInDocument()); if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("Linked object is not a PartDesign object"); - //return App::DocumentObject::StdReturn; + //return new App::DocumentObjectExecReturn("Linked object is not a PartDesign object"); + return Part::TopoShape(); // get the shape of the tip - const Part::TopoShape& TipShape = static_cast(link)->Shape.getShape(); + return static_cast(link)->Shape.getShape(); +} + +const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) +{ + std::vector features = Model.getValues(); + std::vector::const_iterator it = std::find(features.begin(), features.end(), f); + if ((it == features.end()) || (it == features.begin())) + // Wrong body or there is no previous feature + return Part::TopoShape(); + // move to previous feature + it--; + // Skip sketches + while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + if (it == features.begin()) + return Part::TopoShape(); + it--; + } + + return static_cast(*it)->Shape.getShape(); +} + +const bool Body::hasFeature(const PartDesign::Feature* f) +{ + std::vector features = Model.getValues(); + return std::find(features.begin(), features.end(), f) != features.end(); +} + +App::DocumentObjectExecReturn *Body::execute(void) +{ + std::vector children = Model.getValues(); + //Base::Console().Error("Body exec children:\n"); + //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) + // Base::Console().Error("%s\n", (*o)->getNameInDocument()); + + const Part::TopoShape& TipShape = getTipShape(); + if (TipShape._Shape.IsNull()) //return new App::DocumentObjectExecReturn("empty shape"); return App::DocumentObject::StdReturn; @@ -82,4 +120,4 @@ PyObject *Body::getPyObject(void) return Py::new_reference_to(PythonObject); } -} \ No newline at end of file +} diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index ecf001f84b73..ffc46a5174d2 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -31,6 +31,8 @@ namespace PartDesign { +class Feature; + class Body : public Part::BodyBase { PROPERTY_HEADER(PartDesign::Body); @@ -49,6 +51,15 @@ class Body : public Part::BodyBase } //@} + /// Get the tip shape + const Part::TopoShape getTipShape(); + + /// Return the shape of the feature preceding this feature + const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); + + /// Return true if the feature belongs to this body + const bool hasFeature(const PartDesign::Feature* f); + PyObject *getPyObject(void); }; diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 9fa351f04ae2..3c08112d5af6 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -28,11 +28,13 @@ # include # include # include -# include +# include #endif #include +#include "App/Document.h" +#include "Body.h" #include "Feature.h" @@ -59,6 +61,17 @@ TopoDS_Shape Feature::getSolid(const TopoDS_Shape& shape) return TopoDS_Shape(); } +PartDesign::Body* Feature::getBody() +{ + std::vector bodies = this->getDocument()->getObjectsOfType(PartDesign::Body::getClassTypeId()); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->hasFeature(this)) + return body; + } + return NULL; +} + const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f) { if (!f.Infinite()) { @@ -73,5 +86,5 @@ const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f) // Or get a "corner" point if the face is limited? throw Base::Exception("getPointFromFace(): Not implemented yet for this case"); } - + } diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 42c9a3173d88..43e1be04c5b0 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -34,6 +34,8 @@ class gp_Pnt; namespace PartDesign { +class Body; + /** PartDesign feature * Base class of all PartDesign features. * This kind of features only produce solids or fail. @@ -46,11 +48,14 @@ class PartDesignExport Feature : public Part::Feature Feature(); protected: + /// Get the body feature which this feature belongs to + Body* getBody(); + /** * Get a solid of the given shape. If no solid is found an exception is raised. */ - static TopoDS_Shape getSolid(const TopoDS_Shape&); - + static TopoDS_Shape getSolid(const TopoDS_Shape&); + /// Grab any point from the given face static const gp_Pnt getPointFromFace(const TopoDS_Face& f); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index ca291fd2c69f..c8df8364b3e8 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -47,6 +47,7 @@ #include #include +#include "Body.h" #include "FeaturePad.h" @@ -95,13 +96,23 @@ App::DocumentObjectExecReturn *Pad::execute(void) return new App::DocumentObjectExecReturn(e.what()); } + // Find active Body feature and get the shape of the feature preceding this one for fusing + PartDesign::Body* body = getBody(); + if (body == NULL) { + return new App::DocumentObjectExecReturn( + "In order to use PartDesign you need an active Body object in the document. " + "Please make one active or create one. If you have a legacy document " + "with PartDesign objects without Body, use the transfer function in " + "PartDesign to put them into a Body." + ); + } + const Part::TopoShape& prevShape = body->getPreviousSolid(this); TopoDS_Shape support; - try { - support = getSupportShape(); - } catch (const Base::Exception&) { + if (prevShape.isNull()) // ignore, because support isn't mandatory support = TopoDS_Shape(); - } + else + support = prevShape._Shape; // get the Sketch plane Base::Placement SketchPos = sketch->Placement.getValue(); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 868229ea5b16..4d26f147342c 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1,1439 +1,1323 @@ -/*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * - * * - * 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 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "FeaturePickDialog.h" - -using namespace std; - -extern PartDesign::Body *ActivePartObject; - -namespace Gui { -//=========================================================================== -// Common utility functions -//=========================================================================== - -// Take a list of Part2DObjects and erase those which are not eligible for creating a -// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define -// a Subtractive feature -void validateSketches(std::vector& sketches, const bool supportRequired) -{ - std::vector::iterator s = sketches.begin(); - - while (s != sketches.end()) { - // sketch is allways part of the body first. - //// Check whether this sketch is already being used by another feature - //std::vector ref = (*s)->getInList(); - //std::vector::iterator r = ref.begin(); - //while (r != ref.end()) { - // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { - // r = ref.erase(r); - // continue; - // } - // ++r; - //} - //if (!ref.empty()) { - // // TODO: Display some information message that this sketch was removed? - // s = sketches.erase(s); - // continue; - //} - - // Check whether the sketch shape is valid - Part::Part2DObject* sketch = static_cast(*s); - const TopoDS_Shape& shape = sketch->Shape.getValue(); - if (shape.IsNull()) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - - // count free wires - int ctWires=0; - TopExp_Explorer ex; - for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { - ctWires++; - } - if (ctWires == 0) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - - // Check for support - if (supportRequired) { - App::DocumentObject* support = sketch->Support.getValue(); - if (support == NULL) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - } - - // All checks passed - go on to next candidate - s++; - } -} -} // namespace Gui - -//=========================================================================== -// Helper for Body -//=========================================================================== - -PartDesign::Body *getBody(void) -{ - if(!ActivePartObject){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), - QObject::tr("To do PartDesign you need a active Body object in the documnt. Please make one active or create one. If you have a document with PartDesign objects without Body, use the transfer methode in PartDesign to put it into a Body.")); - } - return ActivePartObject; - -} - - -//=========================================================================== -// Part_Pad -//=========================================================================== - -/* Sketch commands =======================================================*/ -DEF_STD_CMD_A(CmdPartDesignNewSketch); - -CmdPartDesignNewSketch::CmdPartDesignNewSketch() - :Command("PartDesign_NewSketch") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Create sketch"); - sToolTipText = QT_TR_NOOP("Create a new sketch"); - sWhatsThis = sToolTipText; - sStatusTip = sToolTipText; - sPixmap = "Sketcher_NewSketch"; -} - - -void CmdPartDesignNewSketch::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - // No PartDesign feature without Body past FreeCAD 0.13 - if(!pcActiveBody) return; - - Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); - Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); - - if (SketchFilter.match()) { - Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); - openCommand("Edit Sketch"); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); - } - else if (FaceFilter.match()) { - // get the selected object - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); - Base::Placement ObjectPos = part->Placement.getValue(); - const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); - if (sub.size() > 1){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), - QObject::tr("You have to select a single face as support for a sketch!")); - return; - } - // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); - const TopoDS_Face& face = TopoDS::Face(sh); - if (face.IsNull()){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), - QObject::tr("You have to select a face as support for a sketch!")); - return; - } - - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() != GeomAbs_Plane){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), - QObject::tr("You need a planar face as support for a sketch!")); - return; - } - - std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); - - // create Sketch on Face - std::string FeatName = getUniqueObjectName("Sketch"); - - openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support - //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - } - else { - // ask user for orientation - SketcherGui::SketchOrientationDialog Dlg; - - if (Dlg.exec() != QDialog::Accepted) - return; // canceled - Base::Vector3d p = Dlg.Pos.getPosition(); - Base::Rotation r = Dlg.Pos.getRotation(); - - // do the right view direction - std::string camstring; - switch(Dlg.DirType){ - case 0: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 1: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 2: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 3: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 4: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 5: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - } - std::string FeatName = getUniqueObjectName("Sketch"); - - openCommand("Create a new Sketch"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - } - -} - -bool CmdPartDesignNewSketch::isActive(void) -{ - if (getActiveGuiDocument()) - return true; - else - return false; -} - -//=========================================================================== -// PartDesign_Pad -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignPad); - -CmdPartDesignPad::CmdPartDesignPad() - : Command("PartDesign_Pad") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Pad"); - sToolTipText = QT_TR_NOOP("Pad a selected sketch"); - sWhatsThis = "PartDesign_Pad"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Pad"; -} - -void CmdPartDesignPad::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - bool bNoSketchWasSelected = false; - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - bNoSketchWasSelected = true; - } - Gui::validateSketches(sketches, false); - if (sketches.size() == 0) { - if (bNoSketchWasSelected) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first.")); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), - QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); - } - return; - } - - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Pad"); - - openCommand("Make Pad"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pad\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - if (support) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - // #0001721: use '0' as edit value to avoid switching off selection in - // ViewProviderGeometryObject::setEditViewer - doCommand(Gui,"Gui.activeDocument().setEdit('%s',0)",FeatName.c_str()); - - //commitCommand(); - adjustCameraPosition(); - - if (support) { - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); - } -} - -bool CmdPartDesignPad::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Pocket -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignPocket); - -CmdPartDesignPocket::CmdPartDesignPocket() - : Command("PartDesign_Pocket") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Pocket"); - sToolTipText = QT_TR_NOOP("Create a pocket with the selected sketch"); - sWhatsThis = "PartDesign_Pocket"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Pocket"; -} - -void CmdPartDesignPocket::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - // Next let the user choose from a list of all eligible objects - if (sketches.size() == 0) { - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - if (sketches.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); - return; - } - } - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Pocket"); - - openCommand("Make Pocket"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pocket\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); -} - -bool CmdPartDesignPocket::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Revolution -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignRevolution); - -CmdPartDesignRevolution::CmdPartDesignRevolution() - : Command("PartDesign_Revolution") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Revolution"); - sToolTipText = QT_TR_NOOP("Revolve a selected sketch"); - sWhatsThis = "PartDesign_Revolution"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Revolution"; -} - -void CmdPartDesignRevolution::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - bool bNoSketchWasSelected = false; - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - bNoSketchWasSelected = true; - } - Gui::validateSketches(sketches, false); - if (sketches.size() == 0) { - if (bNoSketchWasSelected) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first.")); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), - QObject::tr("None of selected sketches/2D objects is valid for revolving. Please select a valid sketch or 2D object that is not used by any other feature.")); - } - return; - } - - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Revolution"); - - openCommand("Make Revolution"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Revolution\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); - PartDesign::Revolution* pcRevolution = static_cast(getDocument()->getObject(FeatName.c_str())); - if (pcRevolution && pcRevolution->suggestReversed()) - doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - if (support) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - if (support) { - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); - } -} - -bool CmdPartDesignRevolution::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Groove -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignGroove); - -CmdPartDesignGroove::CmdPartDesignGroove() - : Command("PartDesign_Groove") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Groove"); - sToolTipText = QT_TR_NOOP("Groove a selected sketch"); - sWhatsThis = "PartDesign_Groove"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Groove"; -} - -void CmdPartDesignGroove::activated(int iMsg) -{ -// // Get a valid sketch from the user -// // First check selections -// std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); -// Gui::validateSketches(sketches, true); -// // Next let the user choose from a list of all eligible objects -// if (sketches.size() == 0) { -// sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); -// Gui::validateSketches(sketches, true); -// if (sketches.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), -// QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); -// return; -// } -// } -// // If there is more than one selection/possibility, show dialog and let user pick sketch -// if (sketches.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(sketches); -// if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } -// -// Part::Part2DObject* sketch = static_cast(sketches.front()); -// App::DocumentObject* support = sketch->Support.getValue(); -// std::string FeatName = getUniqueObjectName("Groove"); -// -// openCommand("Make Groove"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", -// FeatName.c_str(), sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); -// PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); -// if (pcGroove && pcGroove->suggestReversed()) -// doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); -// App::DocumentObjectGroup* grp = sketch->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),sketch->getNameInDocument()); -// } -// updateActive(); -// if (isActiveObjectValid()) { -// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); -// if (support) -// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); -// } -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// if (support) { -// copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); -// copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); -// copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); -// } -} - -bool CmdPartDesignGroove::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Fillet -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignFillet); - -CmdPartDesignFillet::CmdPartDesignFillet() - :Command("PartDesign_Fillet") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Fillet"); - sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); - sWhatsThis = "PartDesign_Fillet"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Fillet"; -} - -void CmdPartDesignFillet::activated(int iMsg) -{ - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select an edge, face or body. Only one body is allowed.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Fillet works only on parts.")); - return; - } - std::string SelString = selection[0].getAsPropertyLinkSubString(); - Part::Feature *base = static_cast(selection[0].getObject()); -// -// const Part::TopoShape& TopShape = base->Shape.getShape(); -// if (TopShape._Shape.IsNull()){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); -// return; -// } -// -// TopTools_IndexedMapOfShape mapOfEdges; -// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; -// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); -// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); -// -// std::vector SubNames = std::vector(selection[0].getSubNames()); -// -// unsigned int i = 0; -// -// while(i < SubNames.size()) -// { -// std::string aSubName = static_cast(SubNames.at(i)); -// -// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { -// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); -// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); -// -// if(los.Extent() != 2) -// { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// const TopoDS_Shape& face1 = los.First(); -// const TopoDS_Shape& face2 = los.Last(); -// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), -// TopoDS::Face(face1), -// TopoDS::Face(face2)); -// if (cont != GeomAbs_C0) { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// i++; -// } -// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { -// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); -// -// TopTools_IndexedMapOfShape mapOfFaces; -// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); -// -// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { -// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); -// -// int id = mapOfEdges.FindIndex(edge); -// -// std::stringstream buf; -// buf << "Edge"; -// buf << id; -// -// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) -// { -// SubNames.push_back(buf.str()); -// } -// -// } -// -// SubNames.erase(SubNames.begin()+i); -// } -// // empty name or any other sub-element -// else { -// SubNames.erase(SubNames.begin()+i); -// } -// } -// -// if (SubNames.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No fillet possible on selected faces/edges.")); -// return; -// } -// -// std::string SelString; -// SelString += "(App."; -// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); -// SelString += "."; -// SelString += selection[0].getFeatName(); -// SelString += ",["; -// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ -// SelString += "\""; -// SelString += *it; -// SelString += "\""; -// if(it != --SubNames.end()) -// SelString += ","; -// } -// SelString += "])"; -// - std::string FeatName = getUniqueObjectName("Fillet"); - - openCommand("Make Fillet"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -} - -bool CmdPartDesignFillet::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Chamfer -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignChamfer); - -CmdPartDesignChamfer::CmdPartDesignChamfer() - :Command("PartDesign_Chamfer") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Chamfer"); - sToolTipText = QT_TR_NOOP("Chamfer the selected edges of a shape"); - sWhatsThis = "PartDesign_Chamfer"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Chamfer"; -} - -void CmdPartDesignChamfer::activated(int iMsg) -{ - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select an edge, face or body. Only one body is allowed.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Chamfer works only on parts.")); - return; - } - std::string SelString = selection[0].getAsPropertyLinkSubString(); - - Part::Feature *base = static_cast(selection[0].getObject()); -// -// const Part::TopoShape& TopShape = base->Shape.getShape(); -// -// if (TopShape._Shape.IsNull()){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); -// return; -// } -// -// TopTools_IndexedMapOfShape mapOfEdges; -// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; -// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); -// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); -// -// std::vector SubNames = std::vector(selection[0].getSubNames()); -// -// unsigned int i = 0; -// -// while(i < SubNames.size()) -// { -// std::string aSubName = static_cast(SubNames.at(i)); -// -// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { -// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); -// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); -// -// if(los.Extent() != 2) -// { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// const TopoDS_Shape& face1 = los.First(); -// const TopoDS_Shape& face2 = los.Last(); -// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), -// TopoDS::Face(face1), -// TopoDS::Face(face2)); -// if (cont != GeomAbs_C0) { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// i++; -// } -// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { -// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); -// -// TopTools_IndexedMapOfShape mapOfFaces; -// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); -// -// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { -// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); -// -// int id = mapOfEdges.FindIndex(edge); -// -// std::stringstream buf; -// buf << "Edge"; -// buf << id; -// -// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) -// { -// SubNames.push_back(buf.str()); -// } -// -// } -// -// SubNames.erase(SubNames.begin()+i); -// } -// // empty name or any other sub-element -// else { -// SubNames.erase(SubNames.begin()+i); -// } -// } -// -// if (SubNames.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No chamfer possible on selected faces/edges.")); -// return; -// } -// -// std::string SelString; -// SelString += "(App."; -// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); -// SelString += "."; -// SelString += selection[0].getFeatName(); -// SelString += ",["; -// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ -// SelString += "\""; -// SelString += *it; -// SelString += "\""; -// if(it != --SubNames.end()) -// SelString += ","; -// } -// SelString += "])"; -// - std::string FeatName = getUniqueObjectName("Chamfer"); - - openCommand("Make Chamfer"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -} - -bool CmdPartDesignChamfer::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Draft -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignDraft); - -CmdPartDesignDraft::CmdPartDesignDraft() - :Command("PartDesign_Draft") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Draft"); - sToolTipText = QT_TR_NOOP("Make a draft on a face"); - sWhatsThis = "PartDesign_Draft"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Draft"; -} - -void CmdPartDesignDraft::activated(int iMsg) -{ -// std::vector selection = getSelection().getSelectionEx(); -// -// if (selection.size() < 1) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Select one or more faces.")); -// return; -// } -// -// if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), -// QObject::tr("Draft works only on parts.")); -// return; -// } -// -// Part::Feature *base = static_cast(selection[0].getObject()); -// -// const Part::TopoShape& TopShape = base->Shape.getShape(); -// if (TopShape._Shape.IsNull()){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Shape of selected Part is empty.")); -// return; -// } -// -// std::vector SubNames = std::vector(selection[0].getSubNames()); -// unsigned int i = 0; -// -// while(i < SubNames.size()) -// { -// std::string aSubName = static_cast(SubNames.at(i)); -// -// if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { -// // Check for valid face types -// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); -// BRepAdaptor_Surface sf(face); -// if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) -// SubNames.erase(SubNames.begin()+i); -// } else { -// // empty name or any other sub-element -// SubNames.erase(SubNames.begin()+i); -// } -// -// i++; -// } -// -// if (SubNames.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No draft possible on selected faces.")); -// return; -// } -// -// std::string SelString; -// SelString += "(App."; -// SelString += "ActiveDocument"; -// SelString += "."; -// SelString += selection[0].getFeatName(); -// SelString += ",["; -// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ -// SelString += "\""; -// SelString += *it; -// SelString += "\""; -// if(it != --SubNames.end()) -// SelString += ","; -// } -// SelString += "])"; -// -// std::string FeatName = getUniqueObjectName("Draft"); -// -// // We don't create any defaults for neutral plane and pull direction, but Draft::execute() -// // will choose them. -// // Note: When the body feature is there, the best thing would be to get pull direction and -// // neutral plane from the preceding feature in the tree. Or even store them as default in -// // the Body feature itself -// openCommand("Make Draft"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); -// updateActive(); -// if (isActiveObjectValid()) { -// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); -// } -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// App::DocumentObjectGroup* grp = base->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// } -// -// copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); -// copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); -// copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -} - -bool CmdPartDesignDraft::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Mirrored -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignMirrored); - -CmdPartDesignMirrored::CmdPartDesignMirrored() - : Command("PartDesign_Mirrored") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Mirrored"); - sToolTipText = QT_TR_NOOP("Create a mirrored feature"); - sWhatsThis = "PartDesign_Mirrored"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Mirrored"; -} - -void CmdPartDesignMirrored::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("Mirrored"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("Mirrored"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); -// // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like -// // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' -// updateActive(); // Helps to ensure that the object already exists when the next command comes up -// doCommand(Doc,str.str().c_str()); -// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); -// if (sketch) -// doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", -// FeatName.c_str(), sketch->getNameInDocument()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignMirrored::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_LinearPattern -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignLinearPattern); - -CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() - : Command("PartDesign_LinearPattern") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("LinearPattern"); - sToolTipText = QT_TR_NOOP("Create a linear pattern feature"); - sWhatsThis = "PartDesign_LinearPattern"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_LinearPattern"; -} - -void CmdPartDesignLinearPattern::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("LinearPattern"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("LinearPattern"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); -// if (sketch) -// doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", -// FeatName.c_str(), sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// App::DocumentObjectGroup* grp = sketch->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),sketch->getNameInDocument()); -// } -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignLinearPattern::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_PolarPattern -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignPolarPattern); - -CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() - : Command("PartDesign_PolarPattern") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("PolarPattern"); - sToolTipText = QT_TR_NOOP("Create a polar pattern feature"); - sWhatsThis = "PartDesign_PolarPattern"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_PolarPattern"; -} - -void CmdPartDesignPolarPattern::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("PolarPattern"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("PolarPattern"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); -// if (sketch) -// doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", -// FeatName.c_str(), sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// App::DocumentObjectGroup* grp = sketch->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),sketch->getNameInDocument()); -// } -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignPolarPattern::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Scaled -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignScaled); - -CmdPartDesignScaled::CmdPartDesignScaled() - : Command("PartDesign_Scaled") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Scaled"); - sToolTipText = QT_TR_NOOP("Create a scaled feature"); - sWhatsThis = "PartDesign_Scaled"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Scaled"; -} - -void CmdPartDesignScaled::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("Scaled"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("Scaled"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignScaled::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_MultiTransform -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignMultiTransform); - -CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() - : Command("PartDesign_MultiTransform") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("MultiTransform"); - sToolTipText = QT_TR_NOOP("Create a multitransform feature"); - sWhatsThis = "PartDesign_MultiTransform"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_MultiTransform"; -} - -void CmdPartDesignMultiTransform::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("MultiTransform"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("MultiTransform"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignMultiTransform::isActive(void) -{ - return hasActiveDocument(); -} - - -//=========================================================================== -// Initialization -//=========================================================================== - -void CreatePartDesignCommands(void) -{ - Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); - - rcCmdMgr.addCommand(new CmdPartDesignPad()); - rcCmdMgr.addCommand(new CmdPartDesignPocket()); - rcCmdMgr.addCommand(new CmdPartDesignRevolution()); -// rcCmdMgr.addCommand(new CmdPartDesignGroove()); - rcCmdMgr.addCommand(new CmdPartDesignFillet()); -// rcCmdMgr.addCommand(new CmdPartDesignDraft()); - rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); - rcCmdMgr.addCommand(new CmdPartDesignChamfer()); -// rcCmdMgr.addCommand(new CmdPartDesignMirrored()); -// rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); -// rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); -// //rcCmdMgr.addCommand(new CmdPartDesignScaled()); -// rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); - } +/*************************************************************************** + * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "FeaturePickDialog.h" + +using namespace std; + +extern PartDesign::Body *ActivePartObject; + + +//=========================================================================== +// Helper for Body +//=========================================================================== + +PartDesign::Body *getBody(void) +{ + if(!ActivePartObject){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), + QObject::tr("In order to use PartDesign you need an active Body object in the document. " + "Please make one active or create one. If you have a legacy document " + "with PartDesign objects without Body, use the transfer function in " + "PartDesign to put them into a Body." + )); + } + return ActivePartObject; + +} + + +//=========================================================================== +// PartDesign_Sketch +//=========================================================================== + +/* Sketch commands =======================================================*/ +DEF_STD_CMD_A(CmdPartDesignNewSketch); + +CmdPartDesignNewSketch::CmdPartDesignNewSketch() + :Command("PartDesign_NewSketch") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create sketch"); + sToolTipText = QT_TR_NOOP("Create a new sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_NewSketch"; +} + + +void CmdPartDesignNewSketch::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + // No PartDesign feature without Body past FreeCAD 0.13 + if(!pcActiveBody) return; + + Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); + Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + + if (SketchFilter.match()) { + Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); + openCommand("Edit Sketch"); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); + } + else if (FaceFilter.match()) { + // get the selected object + Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + Base::Placement ObjectPos = part->Placement.getValue(); + const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); + if (sub.size() > 1){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), + QObject::tr("You have to select a single face as support for a sketch!")); + return; + } + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); + const TopoDS_Face& face = TopoDS::Face(sh); + if (face.IsNull()){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), + QObject::tr("You have to select a face as support for a sketch!")); + return; + } + + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), + QObject::tr("You need a planar face as support for a sketch!")); + return; + } + + std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + + // create Sketch on Face + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a Sketch on Face"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + else { + // ask user for orientation + SketcherGui::SketchOrientationDialog Dlg; + + if (Dlg.exec() != QDialog::Accepted) + return; // canceled + Base::Vector3d p = Dlg.Pos.getPosition(); + Base::Rotation r = Dlg.Pos.getRotation(); + + // do the right view direction + std::string camstring; + switch(Dlg.DirType){ + case 0: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 1: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 2: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 3: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 4: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 5: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + } + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a new Sketch"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + +} + +bool CmdPartDesignNewSketch::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +//=========================================================================== +// Common utility functions for SketchBased features +//=========================================================================== + +// Take a list of Part2DObjects and erase those which are not eligible for creating a +// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define +// a Subtractive feature +void validateSketches(std::vector& sketches, const bool supportRequired) +{ + std::vector::iterator s = sketches.begin(); + + while (s != sketches.end()) { + // sketch is always part of the body first. + //// Check whether this sketch is already being used by another feature + //std::vector ref = (*s)->getInList(); + //std::vector::iterator r = ref.begin(); + //while (r != ref.end()) { + // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { + // r = ref.erase(r); + // continue; + // } + // ++r; + //} + //if (!ref.empty()) { + // // TODO: Display some information message that this sketch was removed? + // s = sketches.erase(s); + // continue; + //} + + // Check whether the sketch shape is valid + Part::Part2DObject* sketch = static_cast(*s); + const TopoDS_Shape& shape = sketch->Shape.getValue(); + if (shape.IsNull()) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + + // count free wires + int ctWires=0; + TopExp_Explorer ex; + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { + ctWires++; + } + if (ctWires == 0) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + + // Check for support + if (supportRequired) { + App::DocumentObject* support = sketch->Support.getValue(); + if (support == NULL) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + } + + // All checks passed - go on to next candidate + s++; + } +} + +void prepareSketchBased(Gui::Command* cmd, const std::string& which, + Part::Part2DObject*& sketch, std::string& FeatName) +{ + PartDesign::Body *pcActiveBody = getBody(); + if (!pcActiveBody) return; + + bool bNoSketchWasSelected = false; + // Get a valid sketch from the user + // First check selections + std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + validateSketches(sketches, false); + // Next let the user choose from a list of all eligible objects + if (sketches.size() == 0) { + sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + bNoSketchWasSelected = true; + } + if (sketches.size() == 0) { + if (bNoSketchWasSelected) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), + QObject::tr("Please create a sketch or 2D object first.")); + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), + QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); + } + return; + } + + // If there is more than one selection/possibility, show dialog and let user pick sketch + if (sketches.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches); + if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } + + sketch = static_cast(sketches.front()); + FeatName = cmd->getUniqueObjectName(which.c_str()); + + cmd->openCommand((std::string("Make ") + which).c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); +} + +void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) +{ + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + cmd->updateActive(); + if (cmd->isActiveObjectValid()) { + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); + } + // #0001721: use '0' as edit value to avoid switching off selection in + // ViewProviderGeometryObject::setEditViewer + cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + + /* + PartDesign::Body *pcActiveBody = getBody(); + if (pcActiveBody) { + cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); + }*/ +} + +//=========================================================================== +// PartDesign_Pad +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPad); + +CmdPartDesignPad::CmdPartDesignPad() + : Command("PartDesign_Pad") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Pad"); + sToolTipText = QT_TR_NOOP("Pad a selected sketch"); + sWhatsThis = "PartDesign_Pad"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Pad"; +} + +void CmdPartDesignPad::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Pad", sketch, FeatName); + + // specific parameters for Pad + doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignPad::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Pocket +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPocket); + +CmdPartDesignPocket::CmdPartDesignPocket() + : Command("PartDesign_Pocket") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Pocket"); + sToolTipText = QT_TR_NOOP("Create a pocket with the selected sketch"); + sWhatsThis = "PartDesign_Pocket"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Pocket"; +} + +void CmdPartDesignPocket::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Pocket", sketch, FeatName); + + doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignPocket::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Revolution +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignRevolution); + +CmdPartDesignRevolution::CmdPartDesignRevolution() + : Command("PartDesign_Revolution") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Revolution"); + sToolTipText = QT_TR_NOOP("Revolve a selected sketch"); + sWhatsThis = "PartDesign_Revolution"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Revolution"; +} + +void CmdPartDesignRevolution::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Revolution", sketch, FeatName); + + doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + PartDesign::Revolution* pcRevolution = static_cast(getDocument()->getObject(FeatName.c_str())); + if (pcRevolution && pcRevolution->suggestReversed()) + doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignRevolution::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Groove +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignGroove); + +CmdPartDesignGroove::CmdPartDesignGroove() + : Command("PartDesign_Groove") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Groove"); + sToolTipText = QT_TR_NOOP("Groove a selected sketch"); + sWhatsThis = "PartDesign_Groove"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Groove"; +} + +void CmdPartDesignGroove::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Groove", sketch, FeatName); + + doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); + if (pcGroove && pcGroove->suggestReversed()) + doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignGroove::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Fillet +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignFillet); + +CmdPartDesignFillet::CmdPartDesignFillet() + :Command("PartDesign_Fillet") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Fillet"); + sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); + sWhatsThis = "PartDesign_Fillet"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Fillet"; +} + +void CmdPartDesignFillet::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge, face or body. Only one body is allowed.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Fillet works only on parts.")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected part is empty.")); + return; + } + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); + + std::vector SubNames = std::vector(selection[0].getSubNames()); + + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); + const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); + + if(los.Extent() != 2) + { + SubNames.erase(SubNames.begin()+i); + continue; + } + + const TopoDS_Shape& face1 = los.First(); + const TopoDS_Shape& face2 = los.Last(); + GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), + TopoDS::Face(face1), + TopoDS::Face(face2)); + if (cont != GeomAbs_C0) { + SubNames.erase(SubNames.begin()+i); + continue; + } + + i++; + } + else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); + + for(int j = 1; j <= mapOfFaces.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); + + int id = mapOfEdges.FindIndex(edge); + + std::stringstream buf; + buf << "Edge"; + buf << id; + + if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) + { + SubNames.push_back(buf.str()); + } + + } + + SubNames.erase(SubNames.begin()+i); + } + // empty name or any other sub-element + else { + SubNames.erase(SubNames.begin()+i); + } + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No fillet possible on selected faces/edges.")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Fillet"); + + openCommand("Make Fillet"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.Selection.clearSelection()"); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignFillet::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Chamfer +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignChamfer); + +CmdPartDesignChamfer::CmdPartDesignChamfer() + :Command("PartDesign_Chamfer") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Chamfer"); + sToolTipText = QT_TR_NOOP("Chamfer the selected edges of a shape"); + sWhatsThis = "PartDesign_Chamfer"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Chamfer"; +} + +void CmdPartDesignChamfer::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge, face or body. Only one body is allowed.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Chamfer works only on parts.")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected part is empty.")); + return; + } + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); + + std::vector SubNames = std::vector(selection[0].getSubNames()); + + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); + const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); + + if(los.Extent() != 2) + { + SubNames.erase(SubNames.begin()+i); + continue; + } + + const TopoDS_Shape& face1 = los.First(); + const TopoDS_Shape& face2 = los.Last(); + GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), + TopoDS::Face(face1), + TopoDS::Face(face2)); + if (cont != GeomAbs_C0) { + SubNames.erase(SubNames.begin()+i); + continue; + } + + i++; + } + else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); + + for(int j = 1; j <= mapOfFaces.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); + + int id = mapOfEdges.FindIndex(edge); + + std::stringstream buf; + buf << "Edge"; + buf << id; + + if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) + { + SubNames.push_back(buf.str()); + } + + } + + SubNames.erase(SubNames.begin()+i); + } + // empty name or any other sub-element + else { + SubNames.erase(SubNames.begin()+i); + } + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No chamfer possible on selected faces/edges.")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Chamfer"); + + openCommand("Make Chamfer"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.Selection.clearSelection()"); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignChamfer::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Draft +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignDraft); + +CmdPartDesignDraft::CmdPartDesignDraft() + :Command("PartDesign_Draft") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Draft"); + sToolTipText = QT_TR_NOOP("Make a draft on a face"); + sWhatsThis = "PartDesign_Draft"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Draft"; +} + +void CmdPartDesignDraft::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() < 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select one or more faces.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Draft works only on parts.")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected Part is empty.")); + return; + } + + std::vector SubNames = std::vector(selection[0].getSubNames()); + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + // Check for valid face types + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + BRepAdaptor_Surface sf(face); + if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) + SubNames.erase(SubNames.begin()+i); + } else { + // empty name or any other sub-element + SubNames.erase(SubNames.begin()+i); + } + + i++; + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No draft possible on selected faces.")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument"; + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Draft"); + + // We don't create any defaults for neutral plane and pull direction, but Draft::execute() + // will choose them. + // Note: When the body feature is there, the best thing would be to get pull direction and + // neutral plane from the preceding feature in the tree. Or even store them as default in + // the Body feature itself + openCommand("Make Draft"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + } + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignDraft::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Mirrored +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMirrored); + +CmdPartDesignMirrored::CmdPartDesignMirrored() + : Command("PartDesign_Mirrored") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Mirrored"); + sToolTipText = QT_TR_NOOP("Create a mirrored feature"); + sWhatsThis = "PartDesign_Mirrored"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Mirrored"; +} + +void CmdPartDesignMirrored::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("Mirrored"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("Mirrored"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); + // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like + // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' + updateActive(); // Helps to ensure that the object already exists when the next command comes up + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignMirrored::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_LinearPattern +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignLinearPattern); + +CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() + : Command("PartDesign_LinearPattern") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("LinearPattern"); + sToolTipText = QT_TR_NOOP("Create a linear pattern feature"); + sWhatsThis = "PartDesign_LinearPattern"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_LinearPattern"; +} + +void CmdPartDesignLinearPattern::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("LinearPattern"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("LinearPattern"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignLinearPattern::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_PolarPattern +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPolarPattern); + +CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() + : Command("PartDesign_PolarPattern") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("PolarPattern"); + sToolTipText = QT_TR_NOOP("Create a polar pattern feature"); + sWhatsThis = "PartDesign_PolarPattern"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_PolarPattern"; +} + +void CmdPartDesignPolarPattern::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("PolarPattern"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("PolarPattern"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignPolarPattern::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Scaled +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignScaled); + +CmdPartDesignScaled::CmdPartDesignScaled() + : Command("PartDesign_Scaled") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Scaled"); + sToolTipText = QT_TR_NOOP("Create a scaled feature"); + sWhatsThis = "PartDesign_Scaled"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Scaled"; +} + +void CmdPartDesignScaled::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("Scaled"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("Scaled"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignScaled::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_MultiTransform +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMultiTransform); + +CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() + : Command("PartDesign_MultiTransform") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("MultiTransform"); + sToolTipText = QT_TR_NOOP("Create a multitransform feature"); + sWhatsThis = "PartDesign_MultiTransform"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_MultiTransform"; +} + +void CmdPartDesignMultiTransform::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please.")); + return; + } + } + + std::string FeatName = getUniqueObjectName("MultiTransform"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("MultiTransform"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignMultiTransform::isActive(void) +{ + return hasActiveDocument(); +} + + +//=========================================================================== +// Initialization +//=========================================================================== + +void CreatePartDesignCommands(void) +{ + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + + rcCmdMgr.addCommand(new CmdPartDesignPad()); + rcCmdMgr.addCommand(new CmdPartDesignPocket()); + rcCmdMgr.addCommand(new CmdPartDesignRevolution()); + rcCmdMgr.addCommand(new CmdPartDesignGroove()); + rcCmdMgr.addCommand(new CmdPartDesignFillet()); + rcCmdMgr.addCommand(new CmdPartDesignDraft()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignChamfer()); + rcCmdMgr.addCommand(new CmdPartDesignMirrored()); + rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); + rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); + //rcCmdMgr.addCommand(new CmdPartDesignScaled()); + rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + } diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig index d5e5fa667582..f89af8a923d2 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp.orig +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -1,3 +1,4 @@ +<<<<<<< ac24729340fa24c813f627f5e72fa487a8b4e5f9 /*************************************************************************** * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * * * @@ -75,21 +76,22 @@ void validateSketches(std::vector& sketches, const bool su std::vector::iterator s = sketches.begin(); while (s != sketches.end()) { - // Check whether this sketch is already being used by another feature - std::vector ref = (*s)->getInList(); - std::vector::iterator r = ref.begin(); - while (r != ref.end()) { - if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { - r = ref.erase(r); - continue; - } - ++r; - } - if (!ref.empty()) { - // TODO: Display some information message that this sketch was removed? - s = sketches.erase(s); - continue; - } + // sketch is allways part of the body first. + //// Check whether this sketch is already being used by another feature + //std::vector ref = (*s)->getInList(); + //std::vector::iterator r = ref.begin(); + //while (r != ref.end()) { + // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { + // r = ref.erase(r); + // continue; + // } + // ++r; + //} + //if (!ref.empty()) { + // // TODO: Display some information message that this sketch was removed? + // s = sketches.erase(s); + // continue; + //} // Check whether the sketch shape is valid Part::Part2DObject* sketch = static_cast(*s); @@ -548,62 +550,6 @@ CmdPartDesignGroove::CmdPartDesignGroove() void CmdPartDesignGroove::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - // Next let the user choose from a list of all eligible objects - if (sketches.size() == 0) { - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - if (sketches.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); - return; - } - } - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Groove"); - - openCommand("Make Groove"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); - PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); - if (pcGroove && pcGroove->suggestReversed()) - doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - if (support) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - if (support) { - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); - } -======= // // Get a valid sketch from the user // // First check selections // std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); @@ -614,7 +560,7 @@ void CmdPartDesignGroove::activated(int iMsg) // Gui::validateSketches(sketches, true); // if (sketches.size() == 0) { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), -// QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid")); +// QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); // return; // } // } @@ -658,7 +604,6 @@ void CmdPartDesignGroove::activated(int iMsg) // copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); // copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); // } ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignGroove::isActive(void) @@ -700,107 +645,11 @@ void CmdPartDesignFillet::activated(int iMsg) } std::string SelString = selection[0].getAsPropertyLinkSubString(); Part::Feature *base = static_cast(selection[0].getObject()); -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - - std::vector SubNames = std::vector(selection[0].getSubNames()); - - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { - TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); - const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); - - if(los.Extent() != 2) - { - SubNames.erase(SubNames.begin()+i); - continue; - } - - const TopoDS_Shape& face1 = los.First(); - const TopoDS_Shape& face2 = los.Last(); - GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), - TopoDS::Face(face1), - TopoDS::Face(face2)); - if (cont != GeomAbs_C0) { - SubNames.erase(SubNames.begin()+i); - continue; - } - - i++; - } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - - TopTools_IndexedMapOfShape mapOfFaces; - TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); - - for(int j = 1; j <= mapOfFaces.Extent(); ++j) { - TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); - - int id = mapOfEdges.FindIndex(edge); - - std::stringstream buf; - buf << "Edge"; - buf << id; - - if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) - { - SubNames.push_back(buf.str()); - } - - } - - SubNames.erase(SubNames.begin()+i); - } - // empty name or any other sub-element - else { - SubNames.erase(SubNames.begin()+i); - } - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No fillet possible on selected faces/edges.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - -======= // // const Part::TopoShape& TopShape = base->Shape.getShape(); // if (TopShape._Shape.IsNull()){ // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Shape of selected part is empty")); + QObject::tr("Shape of selected part is empty.")); // return; // } // @@ -871,7 +720,7 @@ void CmdPartDesignFillet::activated(int iMsg) // // if (SubNames.size() == 0) { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No fillet possible on selected faces/edges")); + QObject::tr("No fillet possible on selected faces/edges.")); // return; // } // @@ -890,7 +739,6 @@ void CmdPartDesignFillet::activated(int iMsg) // } // SelString += "])"; // ->>>>>>> switch PartDesign to Bodies std::string FeatName = getUniqueObjectName("Fillet"); openCommand("Make Fillet"); @@ -950,109 +798,12 @@ void CmdPartDesignChamfer::activated(int iMsg) std::string SelString = selection[0].getAsPropertyLinkSubString(); Part::Feature *base = static_cast(selection[0].getObject()); -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - - const Part::TopoShape& TopShape = base->Shape.getShape(); - - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - - std::vector SubNames = std::vector(selection[0].getSubNames()); - - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { - TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); - const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); - - if(los.Extent() != 2) - { - SubNames.erase(SubNames.begin()+i); - continue; - } - - const TopoDS_Shape& face1 = los.First(); - const TopoDS_Shape& face2 = los.Last(); - GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), - TopoDS::Face(face1), - TopoDS::Face(face2)); - if (cont != GeomAbs_C0) { - SubNames.erase(SubNames.begin()+i); - continue; - } - - i++; - } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - - TopTools_IndexedMapOfShape mapOfFaces; - TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); - - for(int j = 1; j <= mapOfFaces.Extent(); ++j) { - TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); - - int id = mapOfEdges.FindIndex(edge); - - std::stringstream buf; - buf << "Edge"; - buf << id; - - if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) - { - SubNames.push_back(buf.str()); - } - - } - - SubNames.erase(SubNames.begin()+i); - } - // empty name or any other sub-element - else { - SubNames.erase(SubNames.begin()+i); - } - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No chamfer possible on selected faces/edges.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - -======= // // const Part::TopoShape& TopShape = base->Shape.getShape(); // // if (TopShape._Shape.IsNull()){ // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Shape of selected part is empty")); + QObject::tr("Shape of selected part is empty.")); // return; // } // @@ -1123,7 +874,7 @@ void CmdPartDesignChamfer::activated(int iMsg) // // if (SubNames.size() == 0) { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No chamfer possible on selected faces/edges")); +// QObject::tr("No chamfer possible on selected faces/edges.")); // return; // } // @@ -1142,7 +893,6 @@ void CmdPartDesignChamfer::activated(int iMsg) // } // SelString += "])"; // ->>>>>>> switch PartDesign to Bodies std::string FeatName = getUniqueObjectName("Chamfer"); openCommand("Make Chamfer"); @@ -1186,98 +936,6 @@ CmdPartDesignDraft::CmdPartDesignDraft() void CmdPartDesignDraft::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() < 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select one or more faces.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Draft works only on parts.")); - return; - } - - Part::Feature *base = static_cast(selection[0].getObject()); - - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected Part is empty.")); - return; - } - - std::vector SubNames = std::vector(selection[0].getSubNames()); - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - // Check for valid face types - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - BRepAdaptor_Surface sf(face); - if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) - SubNames.erase(SubNames.begin()+i); - } else { - // empty name or any other sub-element - SubNames.erase(SubNames.begin()+i); - } - - i++; - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No draft possible on selected faces.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument"; - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - - std::string FeatName = getUniqueObjectName("Draft"); - - // We don't create any defaults for neutral plane and pull direction, but Draft::execute() - // will choose them. - // Note: When the body feature is there, the best thing would be to get pull direction and - // neutral plane from the preceding feature in the tree. Or even store them as default in - // the Body feature itself - openCommand("Make Draft"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -======= // std::vector selection = getSelection().getSelectionEx(); // // if (selection.size() < 1) { @@ -1288,7 +946,7 @@ void CmdPartDesignDraft::activated(int iMsg) // // if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), -// QObject::tr("Draft works only on parts")); +// QObject::tr("Draft works only on parts.")); // return; // } // @@ -1297,7 +955,7 @@ void CmdPartDesignDraft::activated(int iMsg) // const Part::TopoShape& TopShape = base->Shape.getShape(); // if (TopShape._Shape.IsNull()){ // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Shape of selected Part is empty")); +// QObject::tr("Shape of selected Part is empty.")); // return; // } // @@ -1324,7 +982,7 @@ void CmdPartDesignDraft::activated(int iMsg) // // if (SubNames.size() == 0) { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No draft possible on selected faces")); +// QObject::tr("No draft possible on selected faces.")); // return; // } // @@ -1368,7 +1026,6 @@ void CmdPartDesignDraft::activated(int iMsg) // copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); // copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); // copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignDraft::isActive(void) @@ -1395,58 +1052,6 @@ CmdPartDesignMirrored::CmdPartDesignMirrored() void CmdPartDesignMirrored::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("Mirrored"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("Mirrored"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); - // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like - // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' - updateActive(); // Helps to ensure that the object already exists when the next command comes up - doCommand(Doc,str.str().c_str()); - Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); - if (sketch) - doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -======= // // Get a valid original from the user // // First check selections // std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1464,7 +1069,7 @@ void CmdPartDesignMirrored::activated(int iMsg) // return; // Cancelled or nothing selected // } else { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first")); +// QObject::tr("Please create a subtractive or additive feature first.")); // return; // } // } @@ -1497,7 +1102,6 @@ void CmdPartDesignMirrored::activated(int iMsg) // // copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); // copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignMirrored::isActive(void) @@ -1524,65 +1128,6 @@ CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() void CmdPartDesignLinearPattern::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("LinearPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("LinearPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); - if (sketch) - doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -======= // // Get a valid original from the user // // First check selections // std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1600,7 +1145,7 @@ void CmdPartDesignLinearPattern::activated(int iMsg) // return; // Cancelled or nothing selected // } else { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please")); +// QObject::tr("Please create a subtractive or additive feature first, please.")); // return; // } // } @@ -1640,7 +1185,6 @@ void CmdPartDesignLinearPattern::activated(int iMsg) // // copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); // copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignLinearPattern::isActive(void) @@ -1667,65 +1211,6 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() void CmdPartDesignPolarPattern::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("PolarPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("PolarPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); - if (sketch) - doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -======= // // Get a valid original from the user // // First check selections // std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1743,7 +1228,7 @@ void CmdPartDesignPolarPattern::activated(int iMsg) // return; // Cancelled or nothing selected // } else { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please")); +// QObject::tr("Please create a subtractive or additive feature first, please.")); // return; // } // } @@ -1783,7 +1268,6 @@ void CmdPartDesignPolarPattern::activated(int iMsg) // // copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); // copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignPolarPattern::isActive(void) @@ -1810,54 +1294,6 @@ CmdPartDesignScaled::CmdPartDesignScaled() void CmdPartDesignScaled::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("Scaled"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("Scaled"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -======= // // Get a valid original from the user // // First check selections // std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1875,7 +1311,7 @@ void CmdPartDesignScaled::activated(int iMsg) // return; // Cancelled or nothing selected // } else { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please")); +// QObject::tr("Please create a subtractive or additive feature first, please.")); // return; // } // } @@ -1904,7 +1340,6 @@ void CmdPartDesignScaled::activated(int iMsg) // // copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); // copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignScaled::isActive(void) @@ -1931,50 +1366,6 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { -<<<<<<< 692dcf6d1e4f4c50cdecebc0c5c53e05014f57e0 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("MultiTransform"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; - - openCommand("MultiTransform"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,str.str().c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -======= // // Get a valid original from the user // // First check selections // std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1992,7 +1383,7 @@ void CmdPartDesignMultiTransform::activated(int iMsg) // return; // Cancelled or nothing selected // } else { // QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please")); +// QObject::tr("Please create a subtractive or additive feature first, please.")); // return; // } // } @@ -2017,7 +1408,6 @@ void CmdPartDesignMultiTransform::activated(int iMsg) // // copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); // copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); ->>>>>>> switch PartDesign to Bodies } bool CmdPartDesignMultiTransform::isActive(void) @@ -2048,3 +1438,1326 @@ void CreatePartDesignCommands(void) // //rcCmdMgr.addCommand(new CmdPartDesignScaled()); // rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); } +======= +/*************************************************************************** + * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "FeaturePickDialog.h" + +using namespace std; + +extern PartDesign::Body *ActivePartObject; + + +//=========================================================================== +// Helper for Body +//=========================================================================== + +PartDesign::Body *getBody(void) +{ + if(!ActivePartObject){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), + QObject::tr("In order to use PartDesign you need an active Body object in the document. " + "Please make one active or create one. If you have a legacy document " + "with PartDesign objects without Body, use the transfer function in " + "PartDesign to put them into a Body." + )); + } + return ActivePartObject; + +} + + +//=========================================================================== +// PartDesign_Sketch +//=========================================================================== + +/* Sketch commands =======================================================*/ +DEF_STD_CMD_A(CmdPartDesignNewSketch); + +CmdPartDesignNewSketch::CmdPartDesignNewSketch() + :Command("PartDesign_NewSketch") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create sketch"); + sToolTipText = QT_TR_NOOP("Create a new sketch"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_NewSketch"; +} + + +void CmdPartDesignNewSketch::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + + // No PartDesign feature without Body past FreeCAD 0.13 + if(!pcActiveBody) return; + + Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); + Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + + if (SketchFilter.match()) { + Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); + openCommand("Edit Sketch"); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); + } + else if (FaceFilter.match()) { + // get the selected object + Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + Base::Placement ObjectPos = part->Placement.getValue(); + const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); + if (sub.size() > 1){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), + QObject::tr("You have to select a single face as support for a sketch!")); + return; + } + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); + const TopoDS_Face& face = TopoDS::Face(sh); + if (face.IsNull()){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), + QObject::tr("You have to select a face as support for a sketch!")); + return; + } + + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), + QObject::tr("You need a planar face as support for a sketch!")); + return; + } + + std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + + // create Sketch on Face + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a Sketch on Face"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + else { + // ask user for orientation + SketcherGui::SketchOrientationDialog Dlg; + + if (Dlg.exec() != QDialog::Accepted) + return; // canceled + Base::Vector3d p = Dlg.Pos.getPosition(); + Base::Rotation r = Dlg.Pos.getRotation(); + + // do the right view direction + std::string camstring; + switch(Dlg.DirType){ + case 0: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 1: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; + break; + case 2: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 3: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 4: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + case 5: + camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; + break; + } + std::string FeatName = getUniqueObjectName("Sketch"); + + openCommand("Create a new Sketch"); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + } + +} + +bool CmdPartDesignNewSketch::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +//=========================================================================== +// Common utility functions for SketchBased features +//=========================================================================== + +// Take a list of Part2DObjects and erase those which are not eligible for creating a +// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define +// a Subtractive feature +void validateSketches(std::vector& sketches, const bool supportRequired) +{ + std::vector::iterator s = sketches.begin(); + + while (s != sketches.end()) { + // sketch is always part of the body first. + //// Check whether this sketch is already being used by another feature + //std::vector ref = (*s)->getInList(); + //std::vector::iterator r = ref.begin(); + //while (r != ref.end()) { + // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { + // r = ref.erase(r); + // continue; + // } + // ++r; + //} + //if (!ref.empty()) { + // // TODO: Display some information message that this sketch was removed? + // s = sketches.erase(s); + // continue; + //} + + // Check whether the sketch shape is valid + Part::Part2DObject* sketch = static_cast(*s); + const TopoDS_Shape& shape = sketch->Shape.getValue(); + if (shape.IsNull()) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + + // count free wires + int ctWires=0; + TopExp_Explorer ex; + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { + ctWires++; + } + if (ctWires == 0) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + + // Check for support + if (supportRequired) { + App::DocumentObject* support = sketch->Support.getValue(); + if (support == NULL) { + s = sketches.erase(s); + continue; + // TODO: Display some information message that this sketch was removed? + } + } + + // All checks passed - go on to next candidate + s++; + } +} + +void prepareSketchBased(Gui::Command* cmd, const std::string& which, + Part::Part2DObject*& sketch, std::string& FeatName) +{ + PartDesign::Body *pcActiveBody = getBody(); + if (!pcActiveBody) return; + + bool bNoSketchWasSelected = false; + // Get a valid sketch from the user + // First check selections + std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + validateSketches(sketches, false); + // Next let the user choose from a list of all eligible objects + if (sketches.size() == 0) { + sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); + bNoSketchWasSelected = true; + } + if (sketches.size() == 0) { + if (bNoSketchWasSelected) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), + QObject::tr("Please create a sketch or 2D object first")); + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), + QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); + } + return; + } + + // If there is more than one selection/possibility, show dialog and let user pick sketch + if (sketches.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches); + if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } + + sketch = static_cast(sketches.front()); + FeatName = cmd->getUniqueObjectName(which.c_str()); + + cmd->openCommand((std::string("Make ") + which).c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); +} + +void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) +{ + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + cmd->updateActive(); + if (cmd->isActiveObjectValid()) { + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); + } + // #0001721: use '0' as edit value to avoid switching off selection in + // ViewProviderGeometryObject::setEditViewer + cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + + /* + PartDesign::Body *pcActiveBody = getBody(); + if (pcActiveBody) { + cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); + }*/ +} + +//=========================================================================== +// PartDesign_Pad +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPad); + +CmdPartDesignPad::CmdPartDesignPad() + : Command("PartDesign_Pad") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Pad"); + sToolTipText = QT_TR_NOOP("Pad a selected sketch"); + sWhatsThis = "PartDesign_Pad"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Pad"; +} + +void CmdPartDesignPad::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Pad", sketch, FeatName); + + // specific parameters for Pad + doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignPad::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Pocket +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPocket); + +CmdPartDesignPocket::CmdPartDesignPocket() + : Command("PartDesign_Pocket") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Pocket"); + sToolTipText = QT_TR_NOOP("create a pocket with the selected sketch"); + sWhatsThis = "PartDesign_Pocket"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Pocket"; +} + +void CmdPartDesignPocket::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Pocket", sketch, FeatName); + + doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignPocket::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Revolution +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignRevolution); + +CmdPartDesignRevolution::CmdPartDesignRevolution() + : Command("PartDesign_Revolution") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Revolution"); + sToolTipText = QT_TR_NOOP("Revolve a selected sketch"); + sWhatsThis = "PartDesign_Revolution"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Revolution"; +} + +void CmdPartDesignRevolution::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Revolution", sketch, FeatName); + + doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + PartDesign::Revolution* pcRevolution = static_cast(getDocument()->getObject(FeatName.c_str())); + if (pcRevolution && pcRevolution->suggestReversed()) + doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignRevolution::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Groove +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignGroove); + +CmdPartDesignGroove::CmdPartDesignGroove() + : Command("PartDesign_Groove") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Groove"); + sToolTipText = QT_TR_NOOP("Groove a selected sketch"); + sWhatsThis = "PartDesign_Groove"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Groove"; +} + +void CmdPartDesignGroove::activated(int iMsg) +{ + Part::Part2DObject* sketch; + std::string FeatName; + prepareSketchBased(this, "Groove", sketch, FeatName); + + doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); + PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); + if (pcGroove && pcGroove->suggestReversed()) + doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); + + finishSketchBased(this, sketch, FeatName); + adjustCameraPosition(); +} + +bool CmdPartDesignGroove::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Fillet +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignFillet); + +CmdPartDesignFillet::CmdPartDesignFillet() + :Command("PartDesign_Fillet") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Fillet"); + sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); + sWhatsThis = "PartDesign_Fillet"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Fillet"; +} + +void CmdPartDesignFillet::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge, face or body. Only one body is allowed.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Fillet works only on parts")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected part is empty")); + return; + } + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); + + std::vector SubNames = std::vector(selection[0].getSubNames()); + + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); + const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); + + if(los.Extent() != 2) + { + SubNames.erase(SubNames.begin()+i); + continue; + } + + const TopoDS_Shape& face1 = los.First(); + const TopoDS_Shape& face2 = los.Last(); + GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), + TopoDS::Face(face1), + TopoDS::Face(face2)); + if (cont != GeomAbs_C0) { + SubNames.erase(SubNames.begin()+i); + continue; + } + + i++; + } + else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); + + for(int j = 1; j <= mapOfFaces.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); + + int id = mapOfEdges.FindIndex(edge); + + std::stringstream buf; + buf << "Edge"; + buf << id; + + if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) + { + SubNames.push_back(buf.str()); + } + + } + + SubNames.erase(SubNames.begin()+i); + } + // empty name or any other sub-element + else { + SubNames.erase(SubNames.begin()+i); + } + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No fillet possible on selected faces/edges")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Fillet"); + + openCommand("Make Fillet"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignFillet::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Chamfer +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignChamfer); + +CmdPartDesignChamfer::CmdPartDesignChamfer() + :Command("PartDesign_Chamfer") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Chamfer"); + sToolTipText = QT_TR_NOOP("Chamfer the selected edges of a shape"); + sWhatsThis = "PartDesign_Chamfer"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Chamfer"; +} + +void CmdPartDesignChamfer::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select an edge, face or body. Only one body is allowed.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Chamfer works only on parts")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected part is empty")); + return; + } + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); + + std::vector SubNames = std::vector(selection[0].getSubNames()); + + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { + TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); + const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); + + if(los.Extent() != 2) + { + SubNames.erase(SubNames.begin()+i); + continue; + } + + const TopoDS_Shape& face1 = los.First(); + const TopoDS_Shape& face2 = los.Last(); + GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), + TopoDS::Face(face1), + TopoDS::Face(face2)); + if (cont != GeomAbs_C0) { + SubNames.erase(SubNames.begin()+i); + continue; + } + + i++; + } + else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + + TopTools_IndexedMapOfShape mapOfFaces; + TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); + + for(int j = 1; j <= mapOfFaces.Extent(); ++j) { + TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); + + int id = mapOfEdges.FindIndex(edge); + + std::stringstream buf; + buf << "Edge"; + buf << id; + + if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) + { + SubNames.push_back(buf.str()); + } + + } + + SubNames.erase(SubNames.begin()+i); + } + // empty name or any other sub-element + else { + SubNames.erase(SubNames.begin()+i); + } + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No chamfer possible on selected faces/edges")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Chamfer"); + + openCommand("Make Chamfer"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignChamfer::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Draft +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignDraft); + +CmdPartDesignDraft::CmdPartDesignDraft() + :Command("PartDesign_Draft") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Draft"); + sToolTipText = QT_TR_NOOP("Make a draft on a face"); + sWhatsThis = "PartDesign_Draft"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Draft"; +} + +void CmdPartDesignDraft::activated(int iMsg) +{ + std::vector selection = getSelection().getSelectionEx(); + + if (selection.size() < 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select one or more faces.")); + return; + } + + if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), + QObject::tr("Draft works only on parts")); + return; + } + + Part::Feature *base = static_cast(selection[0].getObject()); + + const Part::TopoShape& TopShape = base->Shape.getShape(); + if (TopShape._Shape.IsNull()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Shape of selected Part is empty")); + return; + } + + std::vector SubNames = std::vector(selection[0].getSubNames()); + unsigned int i = 0; + + while(i < SubNames.size()) + { + std::string aSubName = static_cast(SubNames.at(i)); + + if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { + // Check for valid face types + TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); + BRepAdaptor_Surface sf(face); + if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) + SubNames.erase(SubNames.begin()+i); + } else { + // empty name or any other sub-element + SubNames.erase(SubNames.begin()+i); + } + + i++; + } + + if (SubNames.size() == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("No draft possible on selected faces")); + return; + } + + std::string SelString; + SelString += "(App."; + SelString += "ActiveDocument"; + SelString += "."; + SelString += selection[0].getFeatName(); + SelString += ",["; + for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ + SelString += "\""; + SelString += *it; + SelString += "\""; + if(it != --SubNames.end()) + SelString += ","; + } + SelString += "])"; + + std::string FeatName = getUniqueObjectName("Draft"); + + // We don't create any defaults for neutral plane and pull direction, but Draft::execute() + // will choose them. + // Note: When the body feature is there, the best thing would be to get pull direction and + // neutral plane from the preceding feature in the tree. Or even store them as default in + // the Body feature itself + openCommand("Make Draft"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); + updateActive(); + if (isActiveObjectValid()) { + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); + } + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = base->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); + copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +} + +bool CmdPartDesignDraft::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Mirrored +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMirrored); + +CmdPartDesignMirrored::CmdPartDesignMirrored() + : Command("PartDesign_Mirrored") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Mirrored"); + sToolTipText = QT_TR_NOOP("create a mirrored feature"); + sWhatsThis = "PartDesign_Mirrored"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Mirrored"; +} + +void CmdPartDesignMirrored::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first")); + return; + } + } + + std::string FeatName = getUniqueObjectName("Mirrored"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("Mirrored"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); + // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like + // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' + updateActive(); // Helps to ensure that the object already exists when the next command comes up + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignMirrored::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_LinearPattern +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignLinearPattern); + +CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() + : Command("PartDesign_LinearPattern") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("LinearPattern"); + sToolTipText = QT_TR_NOOP("create a linear pattern feature"); + sWhatsThis = "PartDesign_LinearPattern"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_LinearPattern"; +} + +void CmdPartDesignLinearPattern::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please")); + return; + } + } + + std::string FeatName = getUniqueObjectName("LinearPattern"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("LinearPattern"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignLinearPattern::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_PolarPattern +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignPolarPattern); + +CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() + : Command("PartDesign_PolarPattern") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("PolarPattern"); + sToolTipText = QT_TR_NOOP("create a polar pattern feature"); + sWhatsThis = "PartDesign_PolarPattern"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_PolarPattern"; +} + +void CmdPartDesignPolarPattern::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please")); + return; + } + } + + std::string FeatName = getUniqueObjectName("PolarPattern"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("PolarPattern"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); + if (sketch) + doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", + FeatName.c_str(), sketch->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + App::DocumentObjectGroup* grp = sketch->getGroup(); + if (grp) { + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" + ,grp->getNameInDocument(),sketch->getNameInDocument()); + } + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignPolarPattern::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_Scaled +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignScaled); + +CmdPartDesignScaled::CmdPartDesignScaled() + : Command("PartDesign_Scaled") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Scaled"); + sToolTipText = QT_TR_NOOP("create a scaled feature"); + sWhatsThis = "PartDesign_Scaled"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Scaled"; +} + +void CmdPartDesignScaled::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please")); + return; + } + } + + std::string FeatName = getUniqueObjectName("Scaled"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("Scaled"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); + for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignScaled::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_MultiTransform +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMultiTransform); + +CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() + : Command("PartDesign_MultiTransform") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("MultiTransform"); + sToolTipText = QT_TR_NOOP("create a multitransform feature"); + sWhatsThis = "PartDesign_MultiTransform"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_MultiTransform"; +} + +void CmdPartDesignMultiTransform::activated(int iMsg) +{ + // Get a valid original from the user + // First check selections + std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // Next create a list of all eligible objects + if (features.size() == 0) { + features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features.insert(features.end(), subtractive.begin(), subtractive.end()); + // If there is more than one selected or eligible object, show dialog and let user pick one + if (features.size() > 1) { + PartDesignGui::FeaturePickDialog Dlg(features); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), + QObject::tr("Please create a subtractive or additive feature first, please")); + return; + } + } + + std::string FeatName = getUniqueObjectName("MultiTransform"); + + std::stringstream str; + std::vector tempSelNames; + str << "App.activeDocument()." << FeatName << ".Originals = ["; + for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ + str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; + tempSelNames.push_back((*it)->getNameInDocument()); + } + str << "]"; + + openCommand("MultiTransform"); + doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); + updateActive(); + doCommand(Doc,str.str().c_str()); + + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + + copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); +} + +bool CmdPartDesignMultiTransform::isActive(void) +{ + return hasActiveDocument(); +} + + +//=========================================================================== +// Initialization +//=========================================================================== + +void CreatePartDesignCommands(void) +{ + Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + + rcCmdMgr.addCommand(new CmdPartDesignPad()); + rcCmdMgr.addCommand(new CmdPartDesignPocket()); + rcCmdMgr.addCommand(new CmdPartDesignRevolution()); + rcCmdMgr.addCommand(new CmdPartDesignGroove()); + rcCmdMgr.addCommand(new CmdPartDesignFillet()); + rcCmdMgr.addCommand(new CmdPartDesignDraft()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignChamfer()); + rcCmdMgr.addCommand(new CmdPartDesignMirrored()); + rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); + rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); + //rcCmdMgr.addCommand(new CmdPartDesignScaled()); + rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + } +>>>>>>> Integrated PartDesign::Pad into Body feature workflow diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 1374d2639772..8942fe356920 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -33,6 +33,8 @@ #include #include +#include "Base/Console.h" + using namespace PartDesignGui; PROPERTY_SOURCE(PartDesignGui::ViewProviderBody,PartGui::ViewProviderPart) @@ -109,7 +111,9 @@ std::vector ViewProviderBody::claimChildren(void)const for(std::vector::const_iterator it = Model.begin();it!=Model.end();++it){ // sketches of SketchBased features get claimed under the feature so has to be removed from the Body if ((*it)->isDerivedFrom(PartDesign::SketchBased::getClassTypeId())){ - OutSet.insert(static_cast(*it)->Sketch.getValue()); + App::DocumentObject* sketch = static_cast(*it)->Sketch.getValue(); + if (sketch != NULL) + OutSet.insert(sketch); } } @@ -118,6 +122,9 @@ std::vector ViewProviderBody::claimChildren(void)const sort (Model.begin(), Model.end()); std::vector::iterator it = set_difference (Model.begin(), Model.end(), OutSet.begin(),OutSet.end(), Result.begin()); + //Base::Console().Error("Body claimed children:\n"); + //for (std::vector::const_iterator o = Result.begin(); o != it; o++) + // Base::Console().Error("%s\n", (*o)->getNameInDocument()); // return the rest as claim set of the Body return std::vector(Result.begin(),it); } @@ -125,7 +132,10 @@ std::vector ViewProviderBody::claimChildren(void)const std::vector ViewProviderBody::claimChildren3D(void)const { - + std::vector children = static_cast(getObject())->Model.getValues(); + //Base::Console().Error("Body 3D claimed children:\n"); + //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) + // Base::Console().Error("%s\n", (*o)->getNameInDocument()); return static_cast(getObject())->Model.getValues(); } From d16a886ad9991f702a79e826e25f35fc08be0c3a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 29 Mar 2013 20:09:56 +0430 Subject: [PATCH 057/664] Automatically create Body feature when choosing "New PartDesign Project" from StartPage --- src/Mod/Start/StartPage/PartDesign.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Mod/Start/StartPage/PartDesign.py b/src/Mod/Start/StartPage/PartDesign.py index b312913dcdba..923f04bf0363 100644 --- a/src/Mod/Start/StartPage/PartDesign.py +++ b/src/Mod/Start/StartPage/PartDesign.py @@ -21,6 +21,8 @@ #* * #*************************************************************************** -import FreeCADGui +import FreeCADGui, PartDesignGui FreeCADGui.activateWorkbench("PartDesignWorkbench") App.newDocument() +App.ActiveDocument.addObject("PartDesign::Body") +PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject) From 94b6b8961087e2d85a9f66d9fd843c5e735e6b34 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 30 Mar 2013 14:33:06 +0430 Subject: [PATCH 058/664] Enhanced Pick dialog for PartDesign feature's sketches --- src/Mod/PartDesign/App/Body.cpp | 2 +- src/Mod/PartDesign/App/Body.h | 2 +- src/Mod/PartDesign/Gui/Command.cpp | 125 +- src/Mod/PartDesign/Gui/Command.cpp.orig | 1612 +---------------- src/Mod/PartDesign/Gui/FeaturePickDialog.cpp | 96 +- .../PartDesign/Gui/FeaturePickDialog.cpp.orig | 166 ++ src/Mod/PartDesign/Gui/FeaturePickDialog.h | 18 +- src/Mod/PartDesign/Gui/FeaturePickDialog.ui | 39 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 9 +- 9 files changed, 469 insertions(+), 1600 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/FeaturePickDialog.cpp.orig diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index c255f871552e..27af6aadaf12 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -86,7 +86,7 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return static_cast(*it)->Shape.getShape(); } -const bool Body::hasFeature(const PartDesign::Feature* f) +const bool Body::hasFeature(const App::DocumentObject* f) { std::vector features = Model.getValues(); return std::find(features.begin(), features.end(), f) != features.end(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index ffc46a5174d2..074bb0e731fa 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -58,7 +58,7 @@ class Body : public Part::BodyBase const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); /// Return true if the feature belongs to this body - const bool hasFeature(const PartDesign::Feature* f); + const bool hasFeature(const App::DocumentObject *f); PyObject *getPyObject(void); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 4d26f147342c..4537692e089e 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -81,7 +81,6 @@ PartDesign::Body *getBody(void) } - //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -217,37 +216,46 @@ bool CmdPartDesignNewSketch::isActive(void) //=========================================================================== // Take a list of Part2DObjects and erase those which are not eligible for creating a -// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define -// a Subtractive feature -void validateSketches(std::vector& sketches, const bool supportRequired) -{ - std::vector::iterator s = sketches.begin(); - - while (s != sketches.end()) { - // sketch is always part of the body first. - //// Check whether this sketch is already being used by another feature - //std::vector ref = (*s)->getInList(); - //std::vector::iterator r = ref.begin(); - //while (r != ref.end()) { - // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { - // r = ref.erase(r); - // continue; - // } - // ++r; - //} - //if (!ref.empty()) { - // // TODO: Display some information message that this sketch was removed? - // s = sketches.erase(s); - // continue; - //} +// SketchBased feature. + const unsigned validateSketches(std::vector& sketches, + std::vector& status, + std::vector::iterator& firstValidSketch) +{ + // TODO: If the user previously opted to allow multiple use of sketches or use of sketches from other bodies, + // then count these as valid sketches! + unsigned validSketches = 0; + firstValidSketch = sketches.end(); + + for (std::vector::iterator s = sketches.begin(); s != sketches.end(); s++) { + // Check whether this sketch is already being used by another feature + // Body features don't count... + std::vector inList = (*s)->getInList(); + std::vector::iterator o = inList.begin(); + while (o != inList.end()) { + Base::Console().Error("InList: %s\n", (*o)->getNameInDocument()); + if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) + o = inList.erase(o); + else + ++o; + } + if (inList.size() > 0) { + status.push_back(PartDesignGui::FeaturePickDialog::isUsed); + continue; + } + + // Check whether this sketch belongs to the active body + PartDesign::Body* body = getBody(); + if (!body->hasFeature(*s)) { + status.push_back(PartDesignGui::FeaturePickDialog::otherBody); + continue; + } // Check whether the sketch shape is valid Part::Part2DObject* sketch = static_cast(*s); const TopoDS_Shape& shape = sketch->Shape.getValue(); if (shape.IsNull()) { - s = sketches.erase(s); + status.push_back(PartDesignGui::FeaturePickDialog::invalidShape); continue; - // TODO: Display some information message that this sketch was removed? } // count free wires @@ -257,24 +265,18 @@ void validateSketches(std::vector& sketches, const bool su ctWires++; } if (ctWires == 0) { - s = sketches.erase(s); + status.push_back(PartDesignGui::FeaturePickDialog::noWire); continue; - // TODO: Display some information message that this sketch was removed? } - // Check for support - if (supportRequired) { - App::DocumentObject* support = sketch->Support.getValue(); - if (support == NULL) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - } - - // All checks passed - go on to next candidate - s++; + // All checks passed - found a valid sketch + if (firstValidSketch == sketches.end()) + firstValidSketch = s; + validSketches++; + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); } + + return validSketches; } void prepareSketchBased(Gui::Command* cmd, const std::string& which, @@ -283,35 +285,33 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, PartDesign::Body *pcActiveBody = getBody(); if (!pcActiveBody) return; - bool bNoSketchWasSelected = false; // Get a valid sketch from the user // First check selections + FeatName = ""; // Empty string means prepareSketchBased() was not successful + std::vector status; + std::vector::iterator firstValidSketch; std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - validateSketches(sketches, false); - // Next let the user choose from a list of all eligible objects - if (sketches.size() == 0) { + // Next let the user choose from a list of all eligible objects + unsigned validSketches = validateSketches(sketches, status, firstValidSketch); + if (validSketches == 0) { + status.clear(); sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - bNoSketchWasSelected = true; - } - if (sketches.size() == 0) { - if (bNoSketchWasSelected) { + validSketches = validateSketches(sketches, status, firstValidSketch); + if (validSketches == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), QObject::tr("Please create a sketch or 2D object first.")); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), - QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); + return; } - return; } - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); + if (validSketches > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches, status); if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) return; // Cancelled or nothing selected + firstValidSketch = sketches.begin(); } - sketch = static_cast(sketches.front()); + sketch = static_cast(*firstValidSketch); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); @@ -323,7 +323,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { - App::DocumentObjectGroup* grp = sketch->getGroup(); + App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" ,grp->getNameInDocument(),FeatName.c_str()); @@ -334,18 +334,17 @@ void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch cmd->updateActive(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - } + } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer - cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); - /* PartDesign::Body *pcActiveBody = getBody(); if (pcActiveBody) { cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - }*/ + } } //=========================================================================== @@ -370,6 +369,7 @@ void CmdPartDesignPad::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Pad", sketch, FeatName); + if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); @@ -405,6 +405,7 @@ void CmdPartDesignPocket::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Pocket", sketch, FeatName); + if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); @@ -439,6 +440,7 @@ void CmdPartDesignRevolution::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Revolution", sketch, FeatName); + if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", FeatName.c_str(), sketch->getNameInDocument()); @@ -478,6 +480,7 @@ void CmdPartDesignGroove::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Groove", sketch, FeatName); + if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", FeatName.c_str(), sketch->getNameInDocument()); diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig index f89af8a923d2..c007b284c901 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp.orig +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -1,1444 +1,3 @@ -<<<<<<< ac24729340fa24c813f627f5e72fa487a8b4e5f9 -/*************************************************************************** - * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * - * * - * 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 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "FeaturePickDialog.h" - -using namespace std; - -extern PartDesign::Body *ActivePartObject; - -namespace Gui { -//=========================================================================== -// Common utility functions -//=========================================================================== - -// Take a list of Part2DObjects and erase those which are not eligible for creating a -// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define -// a Subtractive feature -void validateSketches(std::vector& sketches, const bool supportRequired) -{ - std::vector::iterator s = sketches.begin(); - - while (s != sketches.end()) { - // sketch is allways part of the body first. - //// Check whether this sketch is already being used by another feature - //std::vector ref = (*s)->getInList(); - //std::vector::iterator r = ref.begin(); - //while (r != ref.end()) { - // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { - // r = ref.erase(r); - // continue; - // } - // ++r; - //} - //if (!ref.empty()) { - // // TODO: Display some information message that this sketch was removed? - // s = sketches.erase(s); - // continue; - //} - - // Check whether the sketch shape is valid - Part::Part2DObject* sketch = static_cast(*s); - const TopoDS_Shape& shape = sketch->Shape.getValue(); - if (shape.IsNull()) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - - // count free wires - int ctWires=0; - TopExp_Explorer ex; - for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { - ctWires++; - } - if (ctWires == 0) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - - // Check for support - if (supportRequired) { - App::DocumentObject* support = sketch->Support.getValue(); - if (support == NULL) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } - } - - // All checks passed - go on to next candidate - s++; - } -} -} // namespace Gui - -//=========================================================================== -// Helper for Body -//=========================================================================== - -PartDesign::Body *getBody(void) -{ - if(!ActivePartObject){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), - QObject::tr("To do PartDesign you need a active Body object in the documnt. Please make one active or create one. If you have a document with PartDesign objects without Body, use the transfer methode in PartDesign to put it into a Body.")); - } - return ActivePartObject; - -} - - -//=========================================================================== -// Part_Pad -//=========================================================================== - -/* Sketch commands =======================================================*/ -DEF_STD_CMD_A(CmdPartDesignNewSketch); - -CmdPartDesignNewSketch::CmdPartDesignNewSketch() - :Command("PartDesign_NewSketch") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Create sketch"); - sToolTipText = QT_TR_NOOP("Create a new sketch"); - sWhatsThis = sToolTipText; - sStatusTip = sToolTipText; - sPixmap = "Sketcher_NewSketch"; -} - - -void CmdPartDesignNewSketch::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - // No PartDesign feature without Body past FreeCAD 0.13 - if(!pcActiveBody) return; - - Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); - Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); - - if (SketchFilter.match()) { - Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); - openCommand("Edit Sketch"); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); - } - else if (FaceFilter.match()) { - // get the selected object - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); - Base::Placement ObjectPos = part->Placement.getValue(); - const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); - if (sub.size() > 1){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), - QObject::tr("You have to select a single face as support for a sketch!")); - return; - } - // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); - const TopoDS_Face& face = TopoDS::Face(sh); - if (face.IsNull()){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), - QObject::tr("You have to select a face as support for a sketch!")); - return; - } - - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() != GeomAbs_Plane){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), - QObject::tr("You need a planar face as support for a sketch!")); - return; - } - - std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); - - // create Sketch on Face - std::string FeatName = getUniqueObjectName("Sketch"); - - openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support - //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - } - else { - // ask user for orientation - SketcherGui::SketchOrientationDialog Dlg; - - if (Dlg.exec() != QDialog::Accepted) - return; // canceled - Base::Vector3d p = Dlg.Pos.getPosition(); - Base::Rotation r = Dlg.Pos.getRotation(); - - // do the right view direction - std::string camstring; - switch(Dlg.DirType){ - case 0: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 1: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 2: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 3: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 4: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 5: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - } - std::string FeatName = getUniqueObjectName("Sketch"); - - openCommand("Create a new Sketch"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - } - -} - -bool CmdPartDesignNewSketch::isActive(void) -{ - if (getActiveGuiDocument()) - return true; - else - return false; -} - -//=========================================================================== -// PartDesign_Pad -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignPad); - -CmdPartDesignPad::CmdPartDesignPad() - : Command("PartDesign_Pad") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Pad"); - sToolTipText = QT_TR_NOOP("Pad a selected sketch"); - sWhatsThis = "PartDesign_Pad"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Pad"; -} - -void CmdPartDesignPad::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - bool bNoSketchWasSelected = false; - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - bNoSketchWasSelected = true; - } - Gui::validateSketches(sketches, false); - if (sketches.size() == 0) { - if (bNoSketchWasSelected) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first.")); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), - QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); - } - return; - } - - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Pad"); - - openCommand("Make Pad"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pad\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - if (support) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - // #0001721: use '0' as edit value to avoid switching off selection in - // ViewProviderGeometryObject::setEditViewer - doCommand(Gui,"Gui.activeDocument().setEdit('%s',0)",FeatName.c_str()); - - //commitCommand(); - adjustCameraPosition(); - - if (support) { - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); - } -} - -bool CmdPartDesignPad::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Pocket -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignPocket); - -CmdPartDesignPocket::CmdPartDesignPocket() - : Command("PartDesign_Pocket") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Pocket"); - sToolTipText = QT_TR_NOOP("Create a pocket with the selected sketch"); - sWhatsThis = "PartDesign_Pocket"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Pocket"; -} - -void CmdPartDesignPocket::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - // Next let the user choose from a list of all eligible objects - if (sketches.size() == 0) { - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - Gui::validateSketches(sketches, true); - if (sketches.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); - return; - } - } - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Pocket"); - - openCommand("Make Pocket"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Pocket\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); -} - -bool CmdPartDesignPocket::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Revolution -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignRevolution); - -CmdPartDesignRevolution::CmdPartDesignRevolution() - : Command("PartDesign_Revolution") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Revolution"); - sToolTipText = QT_TR_NOOP("Revolve a selected sketch"); - sWhatsThis = "PartDesign_Revolution"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Revolution"; -} - -void CmdPartDesignRevolution::activated(int iMsg) -{ - PartDesign::Body *pcActiveBody = getBody(); - - bool bNoSketchWasSelected = false; - // Get a valid sketch from the user - // First check selections - std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - if (sketches.size() == 0) {//no sketches were selected. Let user pick an object from valid ones available in document - sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - bNoSketchWasSelected = true; - } - Gui::validateSketches(sketches, false); - if (sketches.size() == 0) { - if (bNoSketchWasSelected) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first.")); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), - QObject::tr("None of selected sketches/2D objects is valid for revolving. Please select a valid sketch or 2D object that is not used by any other feature.")); - } - return; - } - - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); - if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } - - Part::Part2DObject* sketch = static_cast(sketches.front()); - App::DocumentObject* support = sketch->Support.getValue(); - std::string FeatName = getUniqueObjectName("Revolution"); - - openCommand("Make Revolution"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Revolution\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", - FeatName.c_str(), sketch->getNameInDocument()); - doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); - PartDesign::Revolution* pcRevolution = static_cast(getDocument()->getObject(FeatName.c_str())); - if (pcRevolution && pcRevolution->suggestReversed()) - doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); - if (support) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - - if (support) { - copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); - copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); - } -} - -bool CmdPartDesignRevolution::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Groove -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignGroove); - -CmdPartDesignGroove::CmdPartDesignGroove() - : Command("PartDesign_Groove") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Groove"); - sToolTipText = QT_TR_NOOP("Groove a selected sketch"); - sWhatsThis = "PartDesign_Groove"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Groove"; -} - -void CmdPartDesignGroove::activated(int iMsg) -{ -// // Get a valid sketch from the user -// // First check selections -// std::vector sketches = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); -// Gui::validateSketches(sketches, true); -// // Next let the user choose from a list of all eligible objects -// if (sketches.size() == 0) { -// sketches = getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); -// Gui::validateSketches(sketches, true); -// if (sketches.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), -// QObject::tr("Please create a sketch or 2D object first. It must have a support face on a solid.")); -// return; -// } -// } -// // If there is more than one selection/possibility, show dialog and let user pick sketch -// if (sketches.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(sketches); -// if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } -// -// Part::Part2DObject* sketch = static_cast(sketches.front()); -// App::DocumentObject* support = sketch->Support.getValue(); -// std::string FeatName = getUniqueObjectName("Groove"); -// -// openCommand("Make Groove"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Groove\",\"%s\")",FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", -// FeatName.c_str(), sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.Angle = 360.0",FeatName.c_str()); -// PartDesign::Groove* pcGroove = static_cast(getDocument()->getObject(FeatName.c_str())); -// if (pcGroove && pcGroove->suggestReversed()) -// doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); -// App::DocumentObjectGroup* grp = sketch->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),sketch->getNameInDocument()); -// } -// updateActive(); -// if (isActiveObjectValid()) { -// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); -// if (support) -// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); -// } -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// if (support) { -// copyVisual(FeatName.c_str(), "ShapeColor", support->getNameInDocument()); -// copyVisual(FeatName.c_str(), "LineColor", support->getNameInDocument()); -// copyVisual(FeatName.c_str(), "PointColor", support->getNameInDocument()); -// } -} - -bool CmdPartDesignGroove::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Fillet -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignFillet); - -CmdPartDesignFillet::CmdPartDesignFillet() - :Command("PartDesign_Fillet") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Fillet"); - sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); - sWhatsThis = "PartDesign_Fillet"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Fillet"; -} - -void CmdPartDesignFillet::activated(int iMsg) -{ - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select an edge, face or body. Only one body is allowed.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Fillet works only on parts.")); - return; - } - std::string SelString = selection[0].getAsPropertyLinkSubString(); - Part::Feature *base = static_cast(selection[0].getObject()); -// -// const Part::TopoShape& TopShape = base->Shape.getShape(); -// if (TopShape._Shape.IsNull()){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); -// return; -// } -// -// TopTools_IndexedMapOfShape mapOfEdges; -// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; -// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); -// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); -// -// std::vector SubNames = std::vector(selection[0].getSubNames()); -// -// unsigned int i = 0; -// -// while(i < SubNames.size()) -// { -// std::string aSubName = static_cast(SubNames.at(i)); -// -// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { -// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); -// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); -// -// if(los.Extent() != 2) -// { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// const TopoDS_Shape& face1 = los.First(); -// const TopoDS_Shape& face2 = los.Last(); -// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), -// TopoDS::Face(face1), -// TopoDS::Face(face2)); -// if (cont != GeomAbs_C0) { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// i++; -// } -// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { -// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); -// -// TopTools_IndexedMapOfShape mapOfFaces; -// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); -// -// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { -// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); -// -// int id = mapOfEdges.FindIndex(edge); -// -// std::stringstream buf; -// buf << "Edge"; -// buf << id; -// -// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) -// { -// SubNames.push_back(buf.str()); -// } -// -// } -// -// SubNames.erase(SubNames.begin()+i); -// } -// // empty name or any other sub-element -// else { -// SubNames.erase(SubNames.begin()+i); -// } -// } -// -// if (SubNames.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No fillet possible on selected faces/edges.")); -// return; -// } -// -// std::string SelString; -// SelString += "(App."; -// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); -// SelString += "."; -// SelString += selection[0].getFeatName(); -// SelString += ",["; -// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ -// SelString += "\""; -// SelString += *it; -// SelString += "\""; -// if(it != --SubNames.end()) -// SelString += ","; -// } -// SelString += "])"; -// - std::string FeatName = getUniqueObjectName("Fillet"); - - openCommand("Make Fillet"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -} - -bool CmdPartDesignFillet::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Chamfer -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignChamfer); - -CmdPartDesignChamfer::CmdPartDesignChamfer() - :Command("PartDesign_Chamfer") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Chamfer"); - sToolTipText = QT_TR_NOOP("Chamfer the selected edges of a shape"); - sWhatsThis = "PartDesign_Chamfer"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Chamfer"; -} - -void CmdPartDesignChamfer::activated(int iMsg) -{ - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select an edge, face or body. Only one body is allowed.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Chamfer works only on parts.")); - return; - } - std::string SelString = selection[0].getAsPropertyLinkSubString(); - - Part::Feature *base = static_cast(selection[0].getObject()); -// -// const Part::TopoShape& TopShape = base->Shape.getShape(); -// -// if (TopShape._Shape.IsNull()){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); -// return; -// } -// -// TopTools_IndexedMapOfShape mapOfEdges; -// TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; -// TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); -// TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); -// -// std::vector SubNames = std::vector(selection[0].getSubNames()); -// -// unsigned int i = 0; -// -// while(i < SubNames.size()) -// { -// std::string aSubName = static_cast(SubNames.at(i)); -// -// if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { -// TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); -// const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); -// -// if(los.Extent() != 2) -// { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// const TopoDS_Shape& face1 = los.First(); -// const TopoDS_Shape& face2 = los.Last(); -// GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), -// TopoDS::Face(face1), -// TopoDS::Face(face2)); -// if (cont != GeomAbs_C0) { -// SubNames.erase(SubNames.begin()+i); -// continue; -// } -// -// i++; -// } -// else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { -// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); -// -// TopTools_IndexedMapOfShape mapOfFaces; -// TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); -// -// for(int j = 1; j <= mapOfFaces.Extent(); ++j) { -// TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); -// -// int id = mapOfEdges.FindIndex(edge); -// -// std::stringstream buf; -// buf << "Edge"; -// buf << id; -// -// if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) -// { -// SubNames.push_back(buf.str()); -// } -// -// } -// -// SubNames.erase(SubNames.begin()+i); -// } -// // empty name or any other sub-element -// else { -// SubNames.erase(SubNames.begin()+i); -// } -// } -// -// if (SubNames.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No chamfer possible on selected faces/edges.")); -// return; -// } -// -// std::string SelString; -// SelString += "(App."; -// SelString += "ActiveDocument";//getObject()->getDocument()->getName(); -// SelString += "."; -// SelString += selection[0].getFeatName(); -// SelString += ",["; -// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ -// SelString += "\""; -// SelString += *it; -// SelString += "\""; -// if(it != --SubNames.end()) -// SelString += ","; -// } -// SelString += "])"; -// - std::string FeatName = getUniqueObjectName("Chamfer"); - - openCommand("Make Chamfer"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -} - -bool CmdPartDesignChamfer::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Draft -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignDraft); - -CmdPartDesignDraft::CmdPartDesignDraft() - :Command("PartDesign_Draft") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Draft"); - sToolTipText = QT_TR_NOOP("Make a draft on a face"); - sWhatsThis = "PartDesign_Draft"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Draft"; -} - -void CmdPartDesignDraft::activated(int iMsg) -{ -// std::vector selection = getSelection().getSelectionEx(); -// -// if (selection.size() < 1) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Select one or more faces.")); -// return; -// } -// -// if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), -// QObject::tr("Draft works only on parts.")); -// return; -// } -// -// Part::Feature *base = static_cast(selection[0].getObject()); -// -// const Part::TopoShape& TopShape = base->Shape.getShape(); -// if (TopShape._Shape.IsNull()){ -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("Shape of selected Part is empty.")); -// return; -// } -// -// std::vector SubNames = std::vector(selection[0].getSubNames()); -// unsigned int i = 0; -// -// while(i < SubNames.size()) -// { -// std::string aSubName = static_cast(SubNames.at(i)); -// -// if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { -// // Check for valid face types -// TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); -// BRepAdaptor_Surface sf(face); -// if ((sf.GetType() != GeomAbs_Plane) && (sf.GetType() != GeomAbs_Cylinder) && (sf.GetType() != GeomAbs_Cone)) -// SubNames.erase(SubNames.begin()+i); -// } else { -// // empty name or any other sub-element -// SubNames.erase(SubNames.begin()+i); -// } -// -// i++; -// } -// -// if (SubNames.size() == 0) { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -// QObject::tr("No draft possible on selected faces.")); -// return; -// } -// -// std::string SelString; -// SelString += "(App."; -// SelString += "ActiveDocument"; -// SelString += "."; -// SelString += selection[0].getFeatName(); -// SelString += ",["; -// for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ -// SelString += "\""; -// SelString += *it; -// SelString += "\""; -// if(it != --SubNames.end()) -// SelString += ","; -// } -// SelString += "])"; -// -// std::string FeatName = getUniqueObjectName("Draft"); -// -// // We don't create any defaults for neutral plane and pull direction, but Draft::execute() -// // will choose them. -// // Note: When the body feature is there, the best thing would be to get pull direction and -// // neutral plane from the preceding feature in the tree. Or even store them as default in -// // the Body feature itself -// openCommand("Make Draft"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); -// updateActive(); -// if (isActiveObjectValid()) { -// doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); -// } -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// App::DocumentObjectGroup* grp = base->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// } -// -// copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); -// copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); -// copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -} - -bool CmdPartDesignDraft::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Mirrored -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignMirrored); - -CmdPartDesignMirrored::CmdPartDesignMirrored() - : Command("PartDesign_Mirrored") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Mirrored"); - sToolTipText = QT_TR_NOOP("Create a mirrored feature"); - sWhatsThis = "PartDesign_Mirrored"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Mirrored"; -} - -void CmdPartDesignMirrored::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("Mirrored"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("Mirrored"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); -// // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like -// // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' -// updateActive(); // Helps to ensure that the object already exists when the next command comes up -// doCommand(Doc,str.str().c_str()); -// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); -// if (sketch) -// doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", -// FeatName.c_str(), sketch->getNameInDocument()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignMirrored::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_LinearPattern -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignLinearPattern); - -CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() - : Command("PartDesign_LinearPattern") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("LinearPattern"); - sToolTipText = QT_TR_NOOP("Create a linear pattern feature"); - sWhatsThis = "PartDesign_LinearPattern"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_LinearPattern"; -} - -void CmdPartDesignLinearPattern::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("LinearPattern"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("LinearPattern"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); -// if (sketch) -// doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", -// FeatName.c_str(), sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// App::DocumentObjectGroup* grp = sketch->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),sketch->getNameInDocument()); -// } -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignLinearPattern::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_PolarPattern -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignPolarPattern); - -CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() - : Command("PartDesign_PolarPattern") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("PolarPattern"); - sToolTipText = QT_TR_NOOP("Create a polar pattern feature"); - sWhatsThis = "PartDesign_PolarPattern"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_PolarPattern"; -} - -void CmdPartDesignPolarPattern::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("PolarPattern"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("PolarPattern"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); -// if (sketch) -// doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", -// FeatName.c_str(), sketch->getNameInDocument()); -// doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// App::DocumentObjectGroup* grp = sketch->getGroup(); -// if (grp) { -// doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" -// ,grp->getNameInDocument(),sketch->getNameInDocument()); -// } -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignPolarPattern::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_Scaled -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignScaled); - -CmdPartDesignScaled::CmdPartDesignScaled() - : Command("PartDesign_Scaled") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Scaled"); - sToolTipText = QT_TR_NOOP("Create a scaled feature"); - sWhatsThis = "PartDesign_Scaled"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Scaled"; -} - -void CmdPartDesignScaled::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("Scaled"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("Scaled"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); -// doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); -// for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) -// doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignScaled::isActive(void) -{ - return hasActiveDocument(); -} - -//=========================================================================== -// PartDesign_MultiTransform -//=========================================================================== -DEF_STD_CMD_A(CmdPartDesignMultiTransform); - -CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() - : Command("PartDesign_MultiTransform") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("MultiTransform"); - sToolTipText = QT_TR_NOOP("Create a multitransform feature"); - sWhatsThis = "PartDesign_MultiTransform"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_MultiTransform"; -} - -void CmdPartDesignMultiTransform::activated(int iMsg) -{ -// // Get a valid original from the user -// // First check selections -// std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // Next create a list of all eligible objects -// if (features.size() == 0) { -// features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); -// subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); -// features.insert(features.end(), subtractive.begin(), subtractive.end()); -// // If there is more than one selected or eligible object, show dialog and let user pick one -// if (features.size() > 1) { -// PartDesignGui::FeaturePickDialog Dlg(features); -// if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) -// return; // Cancelled or nothing selected -// } else { -// QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), -// QObject::tr("Please create a subtractive or additive feature first, please.")); -// return; -// } -// } -// -// std::string FeatName = getUniqueObjectName("MultiTransform"); -// -// std::stringstream str; -// std::vector tempSelNames; -// str << "App.activeDocument()." << FeatName << ".Originals = ["; -// for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ -// str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; -// tempSelNames.push_back((*it)->getNameInDocument()); -// } -// str << "]"; -// -// openCommand("MultiTransform"); -// doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); -// updateActive(); -// doCommand(Doc,str.str().c_str()); -// -// doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); -// -// copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); -// copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); -} - -bool CmdPartDesignMultiTransform::isActive(void) -{ - return hasActiveDocument(); -} - - -//=========================================================================== -// Initialization -//=========================================================================== - -void CreatePartDesignCommands(void) -{ - Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); - - rcCmdMgr.addCommand(new CmdPartDesignPad()); - rcCmdMgr.addCommand(new CmdPartDesignPocket()); - rcCmdMgr.addCommand(new CmdPartDesignRevolution()); -// rcCmdMgr.addCommand(new CmdPartDesignGroove()); - rcCmdMgr.addCommand(new CmdPartDesignFillet()); -// rcCmdMgr.addCommand(new CmdPartDesignDraft()); - rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); - rcCmdMgr.addCommand(new CmdPartDesignChamfer()); -// rcCmdMgr.addCommand(new CmdPartDesignMirrored()); -// rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); -// rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); -// //rcCmdMgr.addCommand(new CmdPartDesignScaled()); -// rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); - } -======= /*************************************************************************** * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * * * @@ -1522,7 +81,6 @@ PartDesign::Body *getBody(void) } - //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -1658,37 +216,46 @@ bool CmdPartDesignNewSketch::isActive(void) //=========================================================================== // Take a list of Part2DObjects and erase those which are not eligible for creating a -// SketchBased feature. If supportRequired is true, also erase those that cannot be used to define -// a Subtractive feature -void validateSketches(std::vector& sketches, const bool supportRequired) -{ - std::vector::iterator s = sketches.begin(); - - while (s != sketches.end()) { - // sketch is always part of the body first. - //// Check whether this sketch is already being used by another feature - //std::vector ref = (*s)->getInList(); - //std::vector::iterator r = ref.begin(); - //while (r != ref.end()) { - // if (!(*r)->getTypeId().isDerivedFrom(PartDesign::SketchBased().getClassTypeId())) { - // r = ref.erase(r); - // continue; - // } - // ++r; - //} - //if (!ref.empty()) { - // // TODO: Display some information message that this sketch was removed? - // s = sketches.erase(s); - // continue; - //} +// SketchBased feature. + const unsigned validateSketches(std::vector& sketches, + std::vector& status, + std::vector::iterator& firstValidSketch) +{ + // TODO: If the user previously opted to allow multiple use of sketches or use of sketches from other bodies, + // then count these as valid sketches! + unsigned validSketches = 0; + firstValidSketch = sketches.end(); + + for (std::vector::iterator s = sketches.begin(); s != sketches.end(); s++) { + // Check whether this sketch is already being used by another feature + // Body features don't count... + std::vector inList = (*s)->getInList(); + std::vector::iterator o = inList.begin(); + while (o != inList.end()) { + Base::Console().Error("InList: %s\n", (*o)->getNameInDocument()); + if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) + o = inList.erase(o); + else + ++o; + } + if (inList.size() > 0) { + status.push_back(PartDesignGui::FeaturePickDialog::isUsed); + continue; + } + + // Check whether this sketch belongs to the active body + PartDesign::Body* body = getBody(); + if (!body->hasFeature(*s)) { + status.push_back(PartDesignGui::FeaturePickDialog::otherBody); + continue; + } // Check whether the sketch shape is valid Part::Part2DObject* sketch = static_cast(*s); const TopoDS_Shape& shape = sketch->Shape.getValue(); if (shape.IsNull()) { - s = sketches.erase(s); + status.push_back(PartDesignGui::FeaturePickDialog::invalidShape); continue; - // TODO: Display some information message that this sketch was removed? } // count free wires @@ -1698,24 +265,18 @@ void validateSketches(std::vector& sketches, const bool su ctWires++; } if (ctWires == 0) { - s = sketches.erase(s); + status.push_back(PartDesignGui::FeaturePickDialog::noWire); continue; - // TODO: Display some information message that this sketch was removed? - } - - // Check for support - if (supportRequired) { - App::DocumentObject* support = sketch->Support.getValue(); - if (support == NULL) { - s = sketches.erase(s); - continue; - // TODO: Display some information message that this sketch was removed? - } } - // All checks passed - go on to next candidate - s++; + // All checks passed - found a valid sketch + if (firstValidSketch == sketches.end()) + firstValidSketch = s; + validSketches++; + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); } + + return validSketches; } void prepareSketchBased(Gui::Command* cmd, const std::string& which, @@ -1724,35 +285,40 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, PartDesign::Body *pcActiveBody = getBody(); if (!pcActiveBody) return; - bool bNoSketchWasSelected = false; // Get a valid sketch from the user // First check selections + FeatName = ""; // Empty string means prepareSketchBased() was not successful + std::vector status; + std::vector::iterator firstValidSketch; std::vector sketches = cmd->getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); - validateSketches(sketches, false); - // Next let the user choose from a list of all eligible objects - if (sketches.size() == 0) { + // Next let the user choose from a list of all eligible objects + unsigned validSketches = validateSketches(sketches, status, firstValidSketch); + if (validSketches == 0) { + status.clear(); sketches = cmd->getDocument()->getObjectsOfType(Part::Part2DObject::getClassTypeId()); - bNoSketchWasSelected = true; - } - if (sketches.size() == 0) { - if (bNoSketchWasSelected) { + validSketches = validateSketches(sketches, status, firstValidSketch); + if (validSketches == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), - QObject::tr("Please create a sketch or 2D object first")); +<<<<<<< 135164d3d8f15df2a58ef70fc1fae48b59c89679 + QObject::tr("Please create a sketch or 2D object first.")); } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); +======= + QObject::tr("Please create a sketch or 2D object first")); + return; +>>>>>>> Enhanced Pick dialog for PartDesign feature's sketches } - return; } - // If there is more than one selection/possibility, show dialog and let user pick sketch - if (sketches.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(sketches); + if (validSketches > 1) { + PartDesignGui::FeaturePickDialog Dlg(sketches, status); if ((Dlg.exec() != QDialog::Accepted) || (sketches = Dlg.getFeatures()).empty()) return; // Cancelled or nothing selected + firstValidSketch = sketches.begin(); } - sketch = static_cast(sketches.front()); + sketch = static_cast(*firstValidSketch); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); @@ -1764,7 +330,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { - App::DocumentObjectGroup* grp = sketch->getGroup(); + App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" ,grp->getNameInDocument(),FeatName.c_str()); @@ -1775,18 +341,17 @@ void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch cmd->updateActive(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - } + } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer - cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); - /* PartDesign::Body *pcActiveBody = getBody(); if (pcActiveBody) { cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - }*/ + } } //=========================================================================== @@ -1811,6 +376,7 @@ void CmdPartDesignPad::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Pad", sketch, FeatName); + if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); @@ -1835,7 +401,7 @@ CmdPartDesignPocket::CmdPartDesignPocket() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("Pocket"); - sToolTipText = QT_TR_NOOP("create a pocket with the selected sketch"); + sToolTipText = QT_TR_NOOP("Create a pocket with the selected sketch"); sWhatsThis = "PartDesign_Pocket"; sStatusTip = sToolTipText; sPixmap = "PartDesign_Pocket"; @@ -1846,6 +412,7 @@ void CmdPartDesignPocket::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Pocket", sketch, FeatName); + if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); @@ -1880,6 +447,7 @@ void CmdPartDesignRevolution::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Revolution", sketch, FeatName); + if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", FeatName.c_str(), sketch->getNameInDocument()); @@ -1919,6 +487,7 @@ void CmdPartDesignGroove::activated(int iMsg) Part::Part2DObject* sketch; std::string FeatName; prepareSketchBased(this, "Groove", sketch, FeatName); + if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", FeatName.c_str(), sketch->getNameInDocument()); @@ -1965,7 +534,7 @@ void CmdPartDesignFillet::activated(int iMsg) if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Fillet works only on parts")); + QObject::tr("Fillet works only on parts.")); return; } @@ -1974,7 +543,7 @@ void CmdPartDesignFillet::activated(int iMsg) const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty")); + QObject::tr("Shape of selected part is empty.")); return; } @@ -2045,7 +614,7 @@ void CmdPartDesignFillet::activated(int iMsg) if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No fillet possible on selected faces/edges")); + QObject::tr("No fillet possible on selected faces/edges.")); return; } @@ -2069,6 +638,7 @@ void CmdPartDesignFillet::activated(int iMsg) openCommand("Make Fillet"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.Selection.clearSelection()"); doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); App::DocumentObjectGroup* grp = base->getGroup(); @@ -2116,7 +686,7 @@ void CmdPartDesignChamfer::activated(int iMsg) if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Chamfer works only on parts")); + QObject::tr("Chamfer works only on parts.")); return; } @@ -2126,7 +696,7 @@ void CmdPartDesignChamfer::activated(int iMsg) if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty")); + QObject::tr("Shape of selected part is empty.")); return; } @@ -2197,7 +767,7 @@ void CmdPartDesignChamfer::activated(int iMsg) if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No chamfer possible on selected faces/edges")); + QObject::tr("No chamfer possible on selected faces/edges.")); return; } @@ -2221,6 +791,7 @@ void CmdPartDesignChamfer::activated(int iMsg) openCommand("Make Chamfer"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + doCommand(Gui,"Gui.Selection.clearSelection()"); doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); App::DocumentObjectGroup* grp = base->getGroup(); @@ -2268,7 +839,7 @@ void CmdPartDesignDraft::activated(int iMsg) if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Draft works only on parts")); + QObject::tr("Draft works only on parts.")); return; } @@ -2277,7 +848,7 @@ void CmdPartDesignDraft::activated(int iMsg) const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected Part is empty")); + QObject::tr("Shape of selected Part is empty.")); return; } @@ -2304,7 +875,7 @@ void CmdPartDesignDraft::activated(int iMsg) if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No draft possible on selected faces")); + QObject::tr("No draft possible on selected faces.")); return; } @@ -2366,7 +937,7 @@ CmdPartDesignMirrored::CmdPartDesignMirrored() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("Mirrored"); - sToolTipText = QT_TR_NOOP("create a mirrored feature"); + sToolTipText = QT_TR_NOOP("Create a mirrored feature"); sWhatsThis = "PartDesign_Mirrored"; sStatusTip = sToolTipText; sPixmap = "PartDesign_Mirrored"; @@ -2391,7 +962,7 @@ void CmdPartDesignMirrored::activated(int iMsg) return; // Cancelled or nothing selected } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first")); + QObject::tr("Please create a subtractive or additive feature first.")); return; } } @@ -2442,7 +1013,7 @@ CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("LinearPattern"); - sToolTipText = QT_TR_NOOP("create a linear pattern feature"); + sToolTipText = QT_TR_NOOP("Create a linear pattern feature"); sWhatsThis = "PartDesign_LinearPattern"; sStatusTip = sToolTipText; sPixmap = "PartDesign_LinearPattern"; @@ -2467,7 +1038,7 @@ void CmdPartDesignLinearPattern::activated(int iMsg) return; // Cancelled or nothing selected } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please")); + QObject::tr("Please create a subtractive or additive feature first, please.")); return; } } @@ -2525,7 +1096,7 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("PolarPattern"); - sToolTipText = QT_TR_NOOP("create a polar pattern feature"); + sToolTipText = QT_TR_NOOP("Create a polar pattern feature"); sWhatsThis = "PartDesign_PolarPattern"; sStatusTip = sToolTipText; sPixmap = "PartDesign_PolarPattern"; @@ -2550,7 +1121,7 @@ void CmdPartDesignPolarPattern::activated(int iMsg) return; // Cancelled or nothing selected } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please")); + QObject::tr("Please create a subtractive or additive feature first, please.")); return; } } @@ -2608,7 +1179,7 @@ CmdPartDesignScaled::CmdPartDesignScaled() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("Scaled"); - sToolTipText = QT_TR_NOOP("create a scaled feature"); + sToolTipText = QT_TR_NOOP("Create a scaled feature"); sWhatsThis = "PartDesign_Scaled"; sStatusTip = sToolTipText; sPixmap = "PartDesign_Scaled"; @@ -2633,7 +1204,7 @@ void CmdPartDesignScaled::activated(int iMsg) return; // Cancelled or nothing selected } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please")); + QObject::tr("Please create a subtractive or additive feature first, please.")); return; } } @@ -2680,7 +1251,7 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); sMenuText = QT_TR_NOOP("MultiTransform"); - sToolTipText = QT_TR_NOOP("create a multitransform feature"); + sToolTipText = QT_TR_NOOP("Create a multitransform feature"); sWhatsThis = "PartDesign_MultiTransform"; sStatusTip = sToolTipText; sPixmap = "PartDesign_MultiTransform"; @@ -2705,7 +1276,7 @@ void CmdPartDesignMultiTransform::activated(int iMsg) return; // Cancelled or nothing selected } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please")); + QObject::tr("Please create a subtractive or additive feature first, please.")); return; } } @@ -2760,4 +1331,3 @@ void CreatePartDesignCommands(void) //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); } ->>>>>>> Integrated PartDesign::Pad into Body feature workflow diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp index 029e4e76b284..c46b6662d087 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp @@ -39,12 +39,51 @@ using namespace PartDesignGui; -FeaturePickDialog::FeaturePickDialog(std::vector& objects) +const QString FeaturePickDialog::getFeatureStatusString(const featureStatus st) +{ + switch (st) { + case validFeature: return tr("Valid"); + case invalidShape: return tr("Invalid shape"); + case noWire: return tr("No wire in sketch"); + case isUsed: return tr("Sketch already used by other feature"); + case otherBody: return tr("Sketch belongs to another Body feature"); + } + + return tr(""); +} + +FeaturePickDialog::FeaturePickDialog(std::vector& objects, + const std::vector& status) : QDialog(Gui::getMainWindow()), ui(new Ui_FeaturePickDialog) { ui->setupUi(this); - for (std::vector::const_iterator o = objects.begin(); o != objects.end(); ++o) - ui->listWidget->addItem(QString::fromLatin1((*o)->getNameInDocument())); + + connect(ui->checkOtherBody, SIGNAL(toggled(bool)), this, SLOT(onCheckOtherBody(bool))); + connect(ui->checkOtherFeature, SIGNAL(toggled(bool)), this, SLOT(onCheckOtherFeature(bool))); + connect(ui->radioIndependent, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + connect(ui->radioDependent, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + connect(ui->radioXRef, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + + ui->checkOtherBody->setChecked(false); + ui->checkOtherBody->setEnabled(false); // TODO: implement + ui->checkOtherFeature->setChecked(false); + ui->checkOtherFeature->setEnabled(false); // TODO: implement + ui->radioIndependent->setChecked(true); + ui->radioIndependent->setEnabled(false); + // These are not implemented yet + ui->radioDependent->setEnabled(false); + ui->radioXRef->setEnabled(false); + + std::vector::const_iterator st = status.begin(); + for (std::vector::const_iterator o = objects.begin(); o != objects.end(); ++o) { + QListWidgetItem* item = new QListWidgetItem(QString::fromAscii((*o)->getNameInDocument()) + + QString::fromAscii(" (") + getFeatureStatusString(*st) + QString::fromAscii(")")); + ui->listWidget->addItem(item); + st++; + } + + statuses = status; + updateList(); } FeaturePickDialog::~FeaturePickDialog() @@ -52,6 +91,50 @@ FeaturePickDialog::~FeaturePickDialog() } +void FeaturePickDialog::updateList() +{ + int index = 0; + + for (std::vector::const_iterator st = statuses.begin(); st != statuses.end(); st++) { + QListWidgetItem* item = ui->listWidget->item(index); + + switch (*st) { + case validFeature: item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); break; + case invalidShape: item->setFlags(Qt::NoItemFlags); break; + case noWire: item->setFlags(Qt::NoItemFlags); break; + case isUsed: item->setFlags(ui->checkOtherFeature->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; + case otherBody: item->setFlags(ui->checkOtherBody->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; + } + + index++; + } +} + +void FeaturePickDialog::onCheckOtherFeature(bool checked) +{ + ui->radioIndependent->setEnabled(checked); + // TODO: Not implemented yet + //ui->radioDependent->setEnabled(checked); + //ui->radioXRef->setEnabled(checked); + + updateList(); +} + +void FeaturePickDialog::onCheckOtherBody(bool checked) +{ + ui->radioIndependent->setEnabled(checked); + // TODO: Not implemented yet + //ui->radioDependent->setEnabled(checked); + //ui->radioXRef->setEnabled(checked); + + updateList(); +} + +void FeaturePickDialog::onUpdate(bool) +{ + updateList(); +} + std::vector FeaturePickDialog::getFeatures() { std::vector result; @@ -67,8 +150,11 @@ void FeaturePickDialog::accept() { features.clear(); QListIterator i(ui->listWidget->selectedItems()); - while (i.hasNext()) - features.push_back(i.next()->text()); + while (i.hasNext()) { + QString t = i.next()->text(); + t = t.left(t.indexOf(QString::fromAscii("(")) - 1); + features.push_back(t); + } QDialog::accept(); } diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp.orig b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp.orig new file mode 100644 index 000000000000..598d7bb96140 --- /dev/null +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp.orig @@ -0,0 +1,166 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +# include +# include +#endif + +#include +#include +#include +#include +#include + +#include "ui_FeaturePickDialog.h" +#include "FeaturePickDialog.h" + +using namespace PartDesignGui; + +const QString FeaturePickDialog::getFeatureStatusString(const featureStatus st) +{ + switch (st) { + case validFeature: return tr("Valid"); + case invalidShape: return tr("Invalid shape"); + case noWire: return tr("No wire in sketch"); + case isUsed: return tr("Sketch already used by other feature"); + case otherBody: return tr("Sketch belongs to another Body feature"); + } + + return tr(""); +} + +FeaturePickDialog::FeaturePickDialog(std::vector& objects, + const std::vector& status) + : QDialog(Gui::getMainWindow()), ui(new Ui_FeaturePickDialog) +{ + ui->setupUi(this); +<<<<<<< 90079612b9f3db27654ac1d04ee2262d99842e1b + for (std::vector::const_iterator o = objects.begin(); o != objects.end(); ++o) + ui->listWidget->addItem(QString::fromLatin1((*o)->getNameInDocument())); +======= + + connect(ui->checkOtherBody, SIGNAL(toggled(bool)), this, SLOT(onCheckOtherBody(bool))); + connect(ui->checkOtherFeature, SIGNAL(toggled(bool)), this, SLOT(onCheckOtherFeature(bool))); + connect(ui->radioIndependent, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + connect(ui->radioDependent, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + connect(ui->radioXRef, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + + ui->checkOtherBody->setChecked(false); + ui->checkOtherBody->setEnabled(false); // TODO: implement + ui->checkOtherFeature->setChecked(false); + ui->checkOtherFeature->setEnabled(false); // TODO: implement + ui->radioIndependent->setChecked(true); + ui->radioIndependent->setEnabled(false); + // These are not implemented yet + ui->radioDependent->setEnabled(false); + ui->radioXRef->setEnabled(false); + + std::vector::const_iterator st = status.begin(); + for (std::vector::const_iterator o = objects.begin(); o != objects.end(); ++o) { + QListWidgetItem* item = new QListWidgetItem(QString::fromAscii((*o)->getNameInDocument()) + + QString::fromAscii(" (") + getFeatureStatusString(*st) + QString::fromAscii(")")); + ui->listWidget->addItem(item); + st++; + } + + statuses = status; + updateList(); +>>>>>>> Enhanced Pick dialog for PartDesign feature's sketches +} + +FeaturePickDialog::~FeaturePickDialog() +{ + +} + +void FeaturePickDialog::updateList() +{ + int index = 0; + + for (std::vector::const_iterator st = statuses.begin(); st != statuses.end(); st++) { + QListWidgetItem* item = ui->listWidget->item(index); + + switch (*st) { + case validFeature: item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); break; + case invalidShape: item->setFlags(Qt::NoItemFlags); break; + case noWire: item->setFlags(Qt::NoItemFlags); break; + case isUsed: item->setFlags(ui->checkOtherFeature->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; + case otherBody: item->setFlags(ui->checkOtherBody->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; + } + + index++; + } +} + +void FeaturePickDialog::onCheckOtherFeature(bool checked) +{ + ui->radioIndependent->setEnabled(checked); + // TODO: Not implemented yet + //ui->radioDependent->setEnabled(checked); + //ui->radioXRef->setEnabled(checked); + + updateList(); +} + +void FeaturePickDialog::onCheckOtherBody(bool checked) +{ + ui->radioIndependent->setEnabled(checked); + // TODO: Not implemented yet + //ui->radioDependent->setEnabled(checked); + //ui->radioXRef->setEnabled(checked); + + updateList(); +} + +void FeaturePickDialog::onUpdate(bool) +{ + updateList(); +} + +std::vector FeaturePickDialog::getFeatures() { + std::vector result; + + for (std::vector::const_iterator s = features.begin(); s != features.end(); ++s) + result.push_back(App::GetApplication().getActiveDocument()->getObject(s->toLatin1().data())); + + return result; +} + + + +void FeaturePickDialog::accept() +{ + features.clear(); + QListIterator i(ui->listWidget->selectedItems()); + while (i.hasNext()) { + QString t = i.next()->text(); + t = t.left(t.indexOf(QString::fromAscii("(")) - 1); + features.push_back(t); + } + + QDialog::accept(); +} +#include "moc_FeaturePickDialog.cpp" diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.h b/src/Mod/PartDesign/Gui/FeaturePickDialog.h index c8569d2a2df2..72a96458e865 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.h +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.h @@ -35,7 +35,15 @@ class FeaturePickDialog : public QDialog Q_OBJECT public: - FeaturePickDialog(std::vector &objects); + enum featureStatus { + validFeature = 0, + invalidShape, + noWire, + isUsed, + otherBody + }; + + FeaturePickDialog(std::vector &objects, const std::vector &status); ~FeaturePickDialog(); std::vector getFeatures(); @@ -43,11 +51,19 @@ class FeaturePickDialog : public QDialog void accept(); protected Q_SLOTS: + void onCheckOtherFeature(bool); + void onCheckOtherBody(bool); + void onUpdate(bool); private: Ui_FeaturePickDialog* ui; std::vector features; + std::vector statuses; + + void updateList(); + + const QString getFeatureStatusString(const featureStatus st); }; } diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.ui b/src/Mod/PartDesign/Gui/FeaturePickDialog.ui index 22e119385006..76e5e728af4a 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.ui +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.ui @@ -6,8 +6,8 @@ 0 0 - 218 - 235 + 318 + 357 @@ -17,6 +17,41 @@ + + + + Allow sketch from other Body + + + + + + + Allow sketch used by other feature + + + + + + + Make independent copy (recommended) + + + + + + + Make dependent copy + + + + + + + Create cross-reference + + + diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 56d96265558c..39641b39a17f 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -549,10 +549,8 @@ bool TaskDlgPadParameters::reject() // get the support and Sketch PartDesign::Pad* pcPad = static_cast(PadView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcPad->Sketch.getValue()) { - pcSketch = static_cast(pcPad->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); + pcSketch = static_cast(pcPad->Sketch.getValue()); } // roll back the done things @@ -563,13 +561,8 @@ bool TaskDlgPadParameters::reject() if (!Gui::Application::Instance->getViewProvider(pcPad)) { if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); } - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); - return true; } From f3e8c331da61bca083f107e432e75b65c670769e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 30 Mar 2013 14:33:36 +0430 Subject: [PATCH 059/664] Preliminary work on Transformed feature's pick dialog to make Command.cpp compile --- src/Mod/PartDesign/Gui/Command.cpp | 261 ++++++++---------------- src/Mod/PartDesign/Gui/Command.cpp.orig | 140 +++++++++---- 2 files changed, 193 insertions(+), 208 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 4537692e089e..7f3d3265ad45 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -920,39 +920,33 @@ bool CmdPartDesignDraft::isActive(void) } //=========================================================================== -// PartDesign_Mirrored +// Common functions for all Transformed features //=========================================================================== -DEF_STD_CMD_A(CmdPartDesignMirrored); - -CmdPartDesignMirrored::CmdPartDesignMirrored() - : Command("PartDesign_Mirrored") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Mirrored"); - sToolTipText = QT_TR_NOOP("Create a mirrored feature"); - sWhatsThis = "PartDesign_Mirrored"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Mirrored"; -} - -void CmdPartDesignMirrored::activated(int iMsg) +;;; +void prepareTransformed(Gui::Command* cmd, const std::string& which, + std::vector& features, std::string& FeatName, + std::vector& selList, std::string& selNames) { // Get a valid original from the user // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features = cmd->getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = cmd->getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); features.insert(features.end(), subtractive.begin(), subtractive.end()); // Next create a list of all eligible objects if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features = cmd->getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = cmd->getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); features.insert(features.end(), subtractive.begin(), subtractive.end()); // If there is more than one selected or eligible object, show dialog and let user pick one if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + std::vector status; + for (unsigned i = 0; i < features.size(); i++) + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); + PartDesignGui::FeaturePickDialog Dlg(features, status); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) { + features.clear(); return; // Cancelled or nothing selected + } } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), QObject::tr("Please create a subtractive or additive feature first.")); @@ -960,34 +954,61 @@ void CmdPartDesignMirrored::activated(int iMsg) } } - std::string FeatName = getUniqueObjectName("Mirrored"); + FeatName = cmd->getUniqueObjectName("Mirrored"); std::stringstream str; - std::vector tempSelNames; str << "App.activeDocument()." << FeatName << ".Originals = ["; for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); + selList.push_back((*it)->getNameInDocument()); } str << "]"; + selNames = str.str(); +} + +//=========================================================================== +// PartDesign_Mirrored +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMirrored); + +CmdPartDesignMirrored::CmdPartDesignMirrored() + : Command("PartDesign_Mirrored") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Mirrored"); + sToolTipText = QT_TR_NOOP("create a mirrored feature"); + sWhatsThis = "PartDesign_Mirrored"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Mirrored"; +} + +void CmdPartDesignMirrored::activated(int iMsg) +{ + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "Mirrored", features, FeatName, selList, selNames); + if (features.empty()) + return; openCommand("Mirrored"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' updateActive(); // Helps to ensure that the object already exists when the next command comes up - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignMirrored::isActive(void) @@ -1014,50 +1035,24 @@ CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() void CmdPartDesignLinearPattern::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("LinearPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "LinearPattern", features, FeatName, selList, selNames); + if (features.empty()) + return; openCommand("LinearPattern"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -1069,8 +1064,8 @@ void CmdPartDesignLinearPattern::activated(int iMsg) ,grp->getNameInDocument(),sketch->getNameInDocument()); } - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignLinearPattern::isActive(void) @@ -1097,50 +1092,24 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() void CmdPartDesignPolarPattern::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("PolarPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "PolarPattern", features, FeatName, selList, selNames); + if (features.empty()) + return; openCommand("PolarPattern"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -1152,8 +1121,8 @@ void CmdPartDesignPolarPattern::activated(int iMsg) ,grp->getNameInDocument(),sketch->getNameInDocument()); } - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignPolarPattern::isActive(void) @@ -1180,52 +1149,26 @@ CmdPartDesignScaled::CmdPartDesignScaled() void CmdPartDesignScaled::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("Scaled"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "Scaled", features, FeatName, selList, selNames); + if (features.empty()) + return; openCommand("Scaled"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignScaled::isActive(void) @@ -1252,48 +1195,22 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("MultiTransform"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); + if (features.empty()) + return; openCommand("MultiTransform"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignMultiTransform::isActive(void) diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig index c007b284c901..e127dffa8ff3 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp.orig +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -299,15 +299,8 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, validSketches = validateSketches(sketches, status, firstValidSketch); if (validSketches == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches in this document"), -<<<<<<< 135164d3d8f15df2a58ef70fc1fae48b59c89679 QObject::tr("Please create a sketch or 2D object first.")); - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid sketches selected"), - QObject::tr("None of selected sketches/2D objects is valid for padding. Please select a valid sketch or 2D object that is not used by any other feature.")); -======= - QObject::tr("Please create a sketch or 2D object first")); return; ->>>>>>> Enhanced Pick dialog for PartDesign feature's sketches } } // If there is more than one selection/possibility, show dialog and let user pick sketch @@ -927,8 +920,9 @@ bool CmdPartDesignDraft::isActive(void) } //=========================================================================== -// PartDesign_Mirrored +// Common functions for all Transformed features //=========================================================================== +<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 DEF_STD_CMD_A(CmdPartDesignMirrored); CmdPartDesignMirrored::CmdPartDesignMirrored() @@ -944,22 +938,33 @@ CmdPartDesignMirrored::CmdPartDesignMirrored() } void CmdPartDesignMirrored::activated(int iMsg) +======= +;;; +void prepareTransformed(Gui::Command* cmd, const std::string& which, + std::vector& features, std::string& FeatName, + std::vector& selList, std::string& selNames) +>>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile { // Get a valid original from the user // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features = cmd->getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); + std::vector subtractive = cmd->getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); features.insert(features.end(), subtractive.begin(), subtractive.end()); // Next create a list of all eligible objects if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); + features = cmd->getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); + subtractive = cmd->getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); features.insert(features.end(), subtractive.begin(), subtractive.end()); // If there is more than one selected or eligible object, show dialog and let user pick one if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) + std::vector status; + for (unsigned i = 0; i < features.size(); i++) + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); + PartDesignGui::FeaturePickDialog Dlg(features, status); + if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) { + features.clear(); return; // Cancelled or nothing selected + } } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), QObject::tr("Please create a subtractive or additive feature first.")); @@ -967,34 +972,61 @@ void CmdPartDesignMirrored::activated(int iMsg) } } - std::string FeatName = getUniqueObjectName("Mirrored"); + FeatName = cmd->getUniqueObjectName("Mirrored"); std::stringstream str; - std::vector tempSelNames; str << "App.activeDocument()." << FeatName << ".Originals = ["; for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); + selList.push_back((*it)->getNameInDocument()); } str << "]"; + selNames = str.str(); +} + +//=========================================================================== +// PartDesign_Mirrored +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMirrored); + +CmdPartDesignMirrored::CmdPartDesignMirrored() + : Command("PartDesign_Mirrored") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Mirrored"); + sToolTipText = QT_TR_NOOP("create a mirrored feature"); + sWhatsThis = "PartDesign_Mirrored"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Mirrored"; +} + +void CmdPartDesignMirrored::activated(int iMsg) +{ + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "Mirrored", features, FeatName, selList, selNames); + if (features.empty()) + return; openCommand("Mirrored"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' updateActive(); // Helps to ensure that the object already exists when the next command comes up - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignMirrored::isActive(void) @@ -1021,6 +1053,7 @@ CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() void CmdPartDesignLinearPattern::activated(int iMsg) { +<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 // Get a valid original from the user // First check selections std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1053,18 +1086,26 @@ void CmdPartDesignLinearPattern::activated(int iMsg) tempSelNames.push_back((*it)->getNameInDocument()); } str << "]"; +======= + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "LinearPattern", features, FeatName, selList, selNames); + if (features.empty()) + return; +>>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile openCommand("LinearPattern"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -1076,8 +1117,8 @@ void CmdPartDesignLinearPattern::activated(int iMsg) ,grp->getNameInDocument(),sketch->getNameInDocument()); } - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignLinearPattern::isActive(void) @@ -1104,6 +1145,7 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() void CmdPartDesignPolarPattern::activated(int iMsg) { +<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 // Get a valid original from the user // First check selections std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1136,18 +1178,26 @@ void CmdPartDesignPolarPattern::activated(int iMsg) tempSelNames.push_back((*it)->getNameInDocument()); } str << "]"; +======= + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "PolarPattern", features, FeatName, selList, selNames); + if (features.empty()) + return; +>>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile openCommand("PolarPattern"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -1159,8 +1209,8 @@ void CmdPartDesignPolarPattern::activated(int iMsg) ,grp->getNameInDocument(),sketch->getNameInDocument()); } - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignPolarPattern::isActive(void) @@ -1187,6 +1237,7 @@ CmdPartDesignScaled::CmdPartDesignScaled() void CmdPartDesignScaled::activated(int iMsg) { +<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 // Get a valid original from the user // First check selections std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1219,20 +1270,28 @@ void CmdPartDesignScaled::activated(int iMsg) tempSelNames.push_back((*it)->getNameInDocument()); } str << "]"; +======= + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "Scaled", features, FeatName, selList, selNames); + if (features.empty()) + return; +>>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile openCommand("Scaled"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = tempSelNames.begin(); it != tempSelNames.end(); ++it) + for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignScaled::isActive(void) @@ -1259,6 +1318,7 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { +<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 // Get a valid original from the user // First check selections std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); @@ -1291,16 +1351,24 @@ void CmdPartDesignMultiTransform::activated(int iMsg) tempSelNames.push_back((*it)->getNameInDocument()); } str << "]"; +======= + std::string FeatName, selNames; + std::vector features; + std::vector selList; + prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); + if (features.empty()) + return; +>>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile openCommand("MultiTransform"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); updateActive(); - doCommand(Doc,str.str().c_str()); + doCommand(Doc,selNames.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", tempSelNames.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", tempSelNames.front().c_str()); + copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); + copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); } bool CmdPartDesignMultiTransform::isActive(void) From ae9aae703c1c40b5b132220d25b28bab040cbe55 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 30 Mar 2013 15:35:46 +0430 Subject: [PATCH 060/664] Hide previous Tip shape when adding a new SketchBased feature --- src/Mod/PartDesign/Gui/Command.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 7f3d3265ad45..4ebbeb3bf33a 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -280,10 +280,11 @@ bool CmdPartDesignNewSketch::isActive(void) } void prepareSketchBased(Gui::Command* cmd, const std::string& which, - Part::Part2DObject*& sketch, std::string& FeatName) + Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevTip) { PartDesign::Body *pcActiveBody = getBody(); if (!pcActiveBody) return; + prevTip = pcActiveBody->Tip.getValue(); // Get a valid sketch from the user // First check selections @@ -321,7 +322,8 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); } -void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) +void finishSketchBased(const Gui::Command* cmd, + const Part::Part2DObject* sketch, const std::string& FeatName, App::DocumentObject*& prevTip) { App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { @@ -334,6 +336,8 @@ void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch cmd->updateActive(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); + if (prevTip != NULL) + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevTip->getNameInDocument()); } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer @@ -368,13 +372,14 @@ void CmdPartDesignPad::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - prepareSketchBased(this, "Pad", sketch, FeatName); + App::DocumentObject* prevTip; + prepareSketchBased(this, "Pad", sketch, FeatName, prevTip); if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName); + finishSketchBased(this, sketch, FeatName, prevTip); adjustCameraPosition(); } @@ -404,12 +409,13 @@ void CmdPartDesignPocket::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - prepareSketchBased(this, "Pocket", sketch, FeatName); + App::DocumentObject* prevTip; + prepareSketchBased(this, "Pocket", sketch, FeatName, prevTip); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName); + finishSketchBased(this, sketch, FeatName, prevTip); adjustCameraPosition(); } @@ -439,7 +445,8 @@ void CmdPartDesignRevolution::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - prepareSketchBased(this, "Revolution", sketch, FeatName); + App::DocumentObject* prevTip; + prepareSketchBased(this, "Revolution", sketch, FeatName, prevTip); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -449,7 +456,7 @@ void CmdPartDesignRevolution::activated(int iMsg) if (pcRevolution && pcRevolution->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName); + finishSketchBased(this, sketch, FeatName, prevTip); adjustCameraPosition(); } @@ -479,7 +486,8 @@ void CmdPartDesignGroove::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - prepareSketchBased(this, "Groove", sketch, FeatName); + App::DocumentObject* prevTip; + prepareSketchBased(this, "Groove", sketch, FeatName, prevTip); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -489,7 +497,7 @@ void CmdPartDesignGroove::activated(int iMsg) if (pcGroove && pcGroove->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName); + finishSketchBased(this, sketch, FeatName, prevTip); adjustCameraPosition(); } From 1b809f305eb226b5c868a667b5f00cc60f474ab0 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 30 Mar 2013 15:57:50 +0430 Subject: [PATCH 061/664] Add command PartDesign_Body and integrate it into the Workbench --- src/Mod/PartDesign/Gui/Command.cpp | 31 +++++++++ src/Mod/PartDesign/Gui/Workbench.cpp | 95 +++++++++++++++------------ src/Mod/Start/StartPage/PartDesign.py | 2 + 3 files changed, 87 insertions(+), 41 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 4ebbeb3bf33a..132c17e6adc6 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -81,6 +81,36 @@ PartDesign::Body *getBody(void) } +//=========================================================================== +// PartDesign_Body +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignBody); + +CmdPartDesignBody::CmdPartDesignBody() + : Command("PartDesign_Body") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create body"); + sToolTipText = QT_TR_NOOP("Create a new body feature"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Body"; +} + +void CmdPartDesignBody::activated(int iMsg) +{ + std::string FeatName = getUniqueObjectName("Body"); + openCommand("Add a body feature"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + +} + +bool CmdPartDesignBody::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -1235,6 +1265,7 @@ void CreatePartDesignCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.addCommand(new CmdPartDesignBody()); rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index c380e135449d..20bbfff1c66b 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -83,7 +83,7 @@ void Workbench::activated() "PartDesign_NewSketch", "PartDesign_Fillet", "PartDesign_Chamfer", -// "PartDesign_Draft", + "PartDesign_Draft", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 1", @@ -92,10 +92,29 @@ void Workbench::activated() "Part_Box" )); + const char* Body[] = { + "PartDesign_NewSketch", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::Body COUNT 1", + Body, + "Start Body", + "Part_Box" + )); + + const char* NoSel[] = { + "PartDesign_Body", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommandsEmptySelection( + NoSel, + "Start Part", + "Part_Box" + )); + const char* Faces[] = { "PartDesign_Fillet", "PartDesign_Chamfer", -// "PartDesign_Draft", + "PartDesign_Draft", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 2..", @@ -109,6 +128,7 @@ void Workbench::activated() "PartDesign_Pad", "PartDesign_Pocket", "PartDesign_Revolution", + "PartDesign_Groove", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Sketcher::SketchObject COUNT 1", @@ -117,29 +137,18 @@ void Workbench::activated() "Part_Box" )); -// const char* Transformed[] = { -// "PartDesign_Mirrored", -// "PartDesign_LinearPattern", -// "PartDesign_PolarPattern", -//// "PartDesign_Scaled", -// "PartDesign_MultiTransform", -// 0}; -// Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( -// "SELECT PartDesign::SketchBased", -// Transformed, -// "Transformation tools", -// "PartDesign_MultiTransform" -// )); - - const char* Empty[] = { - "PartDesign_NewSketch", - "Part_Box", - "Part_Cylinder", + const char* Transformed[] = { + "PartDesign_Mirrored", + "PartDesign_LinearPattern", + "PartDesign_PolarPattern", +// "PartDesign_Scaled", + "PartDesign_MultiTransform", 0}; - Watcher.push_back(new Gui::TaskView::TaskWatcherCommandsEmptySelection( - Empty, - "Create Geometry", - "Part_Box" + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::SketchBased", + Transformed, + "Transformation tools", + "PartDesign_MultiTransform" )); // set the previous used active Body @@ -190,10 +199,12 @@ Gui::MenuItem* Workbench::setupMenuBar() const root->insertItem(item, part); part->setCommand("&Part Design"); SketcherGui::addSketcherWorkbenchSketchActions( *part ); - *part << "PartDesign_NewSketch" + *part << "PartDesign_Body" + << "PartDesign_NewSketch" << "Sketcher_LeaveSketch" << "Sketcher_ViewSketch" << "Sketcher_MapSketch" + << "Sketcher_ReorientSketch" << geom << cons << consaccel @@ -201,15 +212,15 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" -// << "PartDesign_Groove" + << "PartDesign_Groove" << "PartDesign_Fillet" - << "PartDesign_Chamfer"; -// << "PartDesign_Draft" -// << "PartDesign_Mirrored" -// << "PartDesign_LinearPattern" -// << "PartDesign_PolarPattern" + << "PartDesign_Chamfer" + << "PartDesign_Draft" + << "PartDesign_Mirrored" + << "PartDesign_LinearPattern" + << "PartDesign_PolarPattern" // << "PartDesign_Scaled" -// << "PartDesign_MultiTransform"; + << "PartDesign_MultiTransform"; // For 0.13 a couple of python packages like numpy, matplotlib and others // are not deployed with the installer on Windows. Thus, the WizardShaft is // not deployed either hence the check for the existence of the command. @@ -228,23 +239,25 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand("Part Design"); -// TODO: reenable features than rebasing // SketcherGui::addSketcherWorkbenchSketchActions( *part ); - *part << "PartDesign_NewSketch" + *part << "PartDesign_Body" + << "PartDesign_NewSketch" + << "Sketcher_ViewSketch" + << "Sketcher_MapSketch" << "Sketcher_LeaveSketch" << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" -// << "PartDesign_Groove" + << "PartDesign_Groove" << "PartDesign_Fillet" - << "PartDesign_Chamfer"; -// << "PartDesign_Draft" -// << "PartDesign_Mirrored" -// << "PartDesign_LinearPattern" -// << "PartDesign_PolarPattern" + << "PartDesign_Chamfer" + << "PartDesign_Draft" + << "PartDesign_Mirrored" + << "PartDesign_LinearPattern" + << "PartDesign_PolarPattern" // << "PartDesign_Scaled" -// << "PartDesign_MultiTransform"; + << "PartDesign_MultiTransform"; Gui::ToolBarItem* geom = new Gui::ToolBarItem(root); geom->setCommand("Sketcher geometries"); diff --git a/src/Mod/Start/StartPage/PartDesign.py b/src/Mod/Start/StartPage/PartDesign.py index 923f04bf0363..4ce875328936 100644 --- a/src/Mod/Start/StartPage/PartDesign.py +++ b/src/Mod/Start/StartPage/PartDesign.py @@ -26,3 +26,5 @@ App.newDocument() App.ActiveDocument.addObject("PartDesign::Body") PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject) +# Make the "Create sketch" prompt appear in the task panel +Gui.Selection.addSelection(App.ActiveDocument.ActiveObject) From acd88878afb11d8d738c751b648d7c62bb7f9709 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 31 Mar 2013 16:03:13 +0430 Subject: [PATCH 062/664] When switching to the PartDesign workbench, activate the Body feature that was active when the document was last saved, and move the selection to its Tip feature so that the user can start creating new features right away --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 2 ++ src/Mod/PartDesign/App/Body.cpp | 2 +- src/Mod/PartDesign/App/Body.h | 4 ++++ src/Mod/PartDesign/App/FeaturePad.cpp | 2 +- src/Mod/PartDesign/Gui/Workbench.cpp | 24 +++++++++++++++++++++--- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 133c8fdd5d8a..e048646e9e5f 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -55,6 +55,7 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) break; } + ActivePartObject->IsActive.setValue(false); ActivePartObject = 0; ActiveGuiDoc =0; ActiveAppDoc =0; @@ -67,6 +68,7 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) // Should be set! assert(Item); + Item->IsActive.setValue(true); ActivePartObject = Item; ActiveAppDoc = Item->getDocument(); ActiveGuiDoc = Gui::Application::Instance->getDocument(ActiveAppDoc); diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 27af6aadaf12..40e33035d669 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -43,7 +43,7 @@ PROPERTY_SOURCE(PartDesign::Body, Part::BodyBase) Body::Body() { - + ADD_PROPERTY(IsActive,(0)); } short Body::mustExecute() const diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 074bb0e731fa..b72a183cc718 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -38,6 +38,10 @@ class Body : public Part::BodyBase PROPERTY_HEADER(PartDesign::Body); public: + + /// True if this body feature is active or was active when the document was last closed + App::PropertyBool IsActive; + Body(); /** @name methods override feature */ diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index c8df8364b3e8..0a1e262b9ef8 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -96,7 +96,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) return new App::DocumentObjectExecReturn(e.what()); } - // Find active Body feature and get the shape of the feature preceding this one for fusing + // Find Body feature which owns this Pad and get the shape of the feature preceding this one for fusing PartDesign::Body* body = getBody(); if (body == NULL) { return new App::DocumentObjectExecReturn( diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 20bbfff1c66b..3738605bac5c 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -151,9 +151,26 @@ void Workbench::activated() "PartDesign_MultiTransform" )); - // set the previous used active Body - if(oldActive != "") - Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(App.activeDocument().%s)",oldActive.c_str()); + // make the previously used active Body active again + PartDesign::Body* activeBody = NULL; + std::vector bodies = App::GetApplication().getActiveDocument()->getObjectsOfType(PartDesign::Body::getClassTypeId()); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->IsActive.getValue()) { + activeBody = body; + break; + } + } + // If there is only one body, make it active + if ((activeBody == NULL) && (bodies.size() == 1)) + activeBody = static_cast(bodies.front()); + + if (activeBody != NULL) { + Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); + // Move selection to the Tip feature so that the user can start creating new features right away + Gui::Command::doCommand(Gui::Command::Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s.Tip)", activeBody->getNameInDocument()); + } addTaskWatcher(Watcher); Gui::Control().showTaskView(); @@ -165,6 +182,7 @@ void Workbench::deactivated() { removeTaskWatcher(); // remember the body for later activation + // TODO: Remove this if the IsActive Property of Body works OK if(ActivePartObject) oldActive = ActivePartObject->getNameInDocument(); else From 7dee0b7018913452d1ba1241d318d2be20b1d38d Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 31 Mar 2013 17:43:37 +0430 Subject: [PATCH 063/664] Create standard XY, XZ, YZ planes when running the PartDesign_Body command if they don't exist yet --- src/Mod/PartDesign/Gui/Command.cpp | 43 +++++++++++++++++++++++++-- src/Mod/PartDesign/Gui/Workbench.cpp | 23 ++++++++------ src/Mod/Start/StartPage/PartDesign.py | 7 ++--- 3 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 132c17e6adc6..2f5ca4e1e351 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -100,10 +101,48 @@ CmdPartDesignBody::CmdPartDesignBody() void CmdPartDesignBody::activated(int iMsg) { - std::string FeatName = getUniqueObjectName("Body"); openCommand("Add a body feature"); + std::string FeatName = getUniqueObjectName("Body"); + + // add the standard planes at the root of the feature tree + // first check if they already exist + // FIXME: If the user renames them, they won't be found... + bool found = false; + std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { + if ((strcmp("Body_PlaneXY", (*p)->getNameInDocument()) == 0) || + (strcmp("Body_PlaneYZ", (*p)->getNameInDocument()) == 0) || + (strcmp("Body_PlaneXZ", (*p)->getNameInDocument()) == 0)) { + found = true; + break; + } + } + + if (!found) { + // Add the planes ... + doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneXY')"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneYZ')"); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneXZ')"); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'"); + // ... and put them in the 'Origin' group + doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','Origin')"); + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneXY'))"); + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneYZ'))"); + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneXZ'))"); + // TODO: Fold the group (is that possible through the Python interface?) + } + + // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); + // Make the "Create sketch" prompt appear in the task panel + doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); + updateActive(); } bool CmdPartDesignBody::isActive(void) @@ -960,7 +999,7 @@ bool CmdPartDesignDraft::isActive(void) //=========================================================================== // Common functions for all Transformed features //=========================================================================== -;;; + void prepareTransformed(Gui::Command* cmd, const std::string& which, std::vector& features, std::string& FeatName, std::vector& selList, std::string& selNames) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 3738605bac5c..4158d905a891 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -153,17 +153,22 @@ void Workbench::activated() // make the previously used active Body active again PartDesign::Body* activeBody = NULL; - std::vector bodies = App::GetApplication().getActiveDocument()->getObjectsOfType(PartDesign::Body::getClassTypeId()); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { - PartDesign::Body* body = static_cast(*b); - if (body->IsActive.getValue()) { - activeBody = body; - break; + App::Document* activeDocument = App::GetApplication().getActiveDocument(); + if (activeDocument != NULL) { + std::vector bodies = activeDocument->getObjectsOfType(PartDesign::Body::getClassTypeId()); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->IsActive.getValue()) { + activeBody = body; + break; + } } + + // If there is only one body, make it active + if ((activeBody == NULL) && (bodies.size() == 1)) + activeBody = static_cast(bodies.front()); } - // If there is only one body, make it active - if ((activeBody == NULL) && (bodies.size() == 1)) - activeBody = static_cast(bodies.front()); + if (activeBody != NULL) { Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); diff --git a/src/Mod/Start/StartPage/PartDesign.py b/src/Mod/Start/StartPage/PartDesign.py index 4ce875328936..3931e02570f1 100644 --- a/src/Mod/Start/StartPage/PartDesign.py +++ b/src/Mod/Start/StartPage/PartDesign.py @@ -21,10 +21,7 @@ #* * #*************************************************************************** -import FreeCADGui, PartDesignGui +import FreeCADGui FreeCADGui.activateWorkbench("PartDesignWorkbench") App.newDocument() -App.ActiveDocument.addObject("PartDesign::Body") -PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject) -# Make the "Create sketch" prompt appear in the task panel -Gui.Selection.addSelection(App.ActiveDocument.ActiveObject) +FreeCADGui.runCommand('PartDesign_Body') From 417576d5eb2c0ea08b8af46bdd074bb2c6be2566 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 1 Apr 2013 20:36:41 +0430 Subject: [PATCH 064/664] Show three base planes (XY, YZ, XZ) at the beginning of the feature tree and allow to create sketches on them --- src/Mod/Part/App/Part2DObject.cpp | 82 +++++---- src/Mod/PartDesign/Gui/Command.cpp | 173 +++++++++++-------- src/Mod/PartDesign/Gui/FeaturePickDialog.cpp | 2 + src/Mod/PartDesign/Gui/FeaturePickDialog.h | 3 +- src/Mod/PartDesign/Gui/Workbench.cpp | 10 ++ src/Mod/Start/StartPage/PartDesign.py | 3 + 6 files changed, 169 insertions(+), 104 deletions(-) diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index 159b5a8cf44c..46f0635415d5 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -45,6 +45,7 @@ #include +#include #include "Part2DObject.h" #include "Geometry.h" @@ -74,42 +75,57 @@ App::DocumentObjectExecReturn *Part2DObject::execute(void) void Part2DObject::positionBySupport(void) { // recalculate support: - Part::Feature *part = static_cast(Support.getValue()); - if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return; - - Base::Placement Place = part->Placement.getValue(); - const std::vector &sub = Support.getSubValues(); - assert(sub.size()==1); - // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getShape(); - if (shape._Shape.IsNull()) - throw Base::Exception("Support shape is empty!"); + Base::Placement Place; TopoDS_Shape sh; - try { - sh = shape.getSubShape(sub[0].c_str()); - } - catch (Standard_Failure) { - throw Base::Exception("Face in support shape doesn't exist!"); - } - const TopoDS_Face &face = TopoDS::Face(sh); - if (face.IsNull()) - throw Base::Exception("Null face in Part2DObject::positionBySupport()!"); + bool Reverse = false; + gp_Pln plane; + App::DocumentObject* support = Support.getValue(); + + if (support->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + Place = static_cast(support)->Placement.getValue(); + // TODO: How to handle the Reverse property??? + Base::Vector3d pos = Place.getPosition(); + Base::Vector3d dir; + Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); + plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); + } else { + Part::Feature *part = static_cast(support); + if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return; + + Place = part->Placement.getValue(); + const std::vector &sub = Support.getSubValues(); + assert(sub.size()==1); + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getShape(); + if (shape._Shape.IsNull()) + throw Base::Exception("Support shape is empty!"); + + try { + sh = shape.getSubShape(sub[0].c_str()); + } + catch (Standard_Failure) { + throw Base::Exception("Face in support shape doesn't exist!"); + } - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() != GeomAbs_Plane) - throw Base::Exception("No planar face in Part2DObject::positionBySupport()!"); + const TopoDS_Face &face = TopoDS::Face(sh); + if (face.IsNull()) + throw Base::Exception("Null face in Part2DObject::positionBySupport()!"); - bool Reverse = false; - if (face.Orientation() == TopAbs_REVERSED) - Reverse = true; - - gp_Pln plane = adapt.Plane(); - Standard_Boolean ok = plane.Direct(); - if (!ok) { - // toggle if plane has a left-handed coordinate system - plane.UReverse(); - Reverse = !Reverse; + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane) + throw Base::Exception("No planar face in Part2DObject::positionBySupport()!"); + + if (face.Orientation() == TopAbs_REVERSED) + Reverse = true; + + plane = adapt.Plane(); + Standard_Boolean ok = plane.Direct(); + if (!ok) { + // toggle if plane has a left-handed coordinate system + plane.UReverse(); + Reverse = !Reverse; + } } gp_Ax1 Normal = plane.Axis(); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 2f5ca4e1e351..6f46c38ea240 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -82,6 +82,8 @@ PartDesign::Body *getBody(void) } +const char* BasePlaneNames[3] = {"Body_PlaneXY", "Body_PlaneYZ", "Body_PlaneXZ"}; + //=========================================================================== // PartDesign_Body //=========================================================================== @@ -110,34 +112,35 @@ void CmdPartDesignBody::activated(int iMsg) bool found = false; std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { - if ((strcmp("Body_PlaneXY", (*p)->getNameInDocument()) == 0) || - (strcmp("Body_PlaneYZ", (*p)->getNameInDocument()) == 0) || - (strcmp("Body_PlaneXZ", (*p)->getNameInDocument()) == 0)) { - found = true; - break; + for (unsigned i = 0; i < 3; i++) { + if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + found = true; + break; + } } + if (found) break; } if (!found) { // Add the planes ... - doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneXY')"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[0]); doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'"); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneYZ')"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[1]); doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'"); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','Body_PlaneXZ')"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[2]); doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'"); // ... and put them in the 'Origin' group doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','Origin')"); - doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneXY'))"); - doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneYZ'))"); - doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('Body_PlaneXZ'))"); + for (unsigned i = 0; i < 3; i++) + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", BasePlaneNames[i]); // TODO: Fold the group (is that possible through the Python interface?) } // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Doc,"import PartDesignGui"); doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); // Make the "Create sketch" prompt appear in the task panel doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); @@ -179,42 +182,48 @@ void CmdPartDesignNewSketch::activated(int iMsg) Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); openCommand("Edit Sketch"); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); } - else if (FaceFilter.match()) { + else if (FaceFilter.match() || PlaneFilter.match()) { // get the selected object - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); - Base::Placement ObjectPos = part->Placement.getValue(); - const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); - if (sub.size() > 1){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), - QObject::tr("You have to select a single face as support for a sketch!")); - return; - } - // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); - const TopoDS_Face& face = TopoDS::Face(sh); - if (face.IsNull()){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), - QObject::tr("You have to select a face as support for a sketch!")); - return; - } + std::string supportString; + + if (FaceFilter.match()) { + Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); + if (sub.size() > 1){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), + QObject::tr("You have to select a single face as support for a sketch!")); + return; + } + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); + const TopoDS_Face& face = TopoDS::Face(sh); + if (face.IsNull()){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), + QObject::tr("You have to select a face as support for a sketch!")); + return; + } - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() != GeomAbs_Plane){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), - QObject::tr("You need a planar face as support for a sketch!")); - return; - } + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), + QObject::tr("You need a planar face as support for a sketch!")); + return; + } - std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + } else { + supportString = PlaneFilter.Result[0][0].getAsPropertyLinkSubString(); + } // create Sketch on Face std::string FeatName = getUniqueObjectName("Sketch"); @@ -229,47 +238,71 @@ void CmdPartDesignNewSketch::activated(int iMsg) doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } else { - // ask user for orientation - SketcherGui::SketchOrientationDialog Dlg; - - if (Dlg.exec() != QDialog::Accepted) - return; // canceled - Base::Vector3d p = Dlg.Pos.getPosition(); - Base::Rotation r = Dlg.Pos.getRotation(); - - // do the right view direction - std::string camstring; - switch(Dlg.DirType){ - case 0: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 1: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 2: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 3: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 4: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 5: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; + // Get a valid plane from the user + std::vector status; + std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + + unsigned validPlanes = 0; + std::vector::const_iterator firstValidPlane = planes.end(); + + for (std::vector::iterator p = planes.begin(); p != planes.end(); p++) { + // Check whether this plane is a base plane + bool base = false; + for (unsigned i = 0; i < 3; i++) { + if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + status.push_back(PartDesignGui::FeaturePickDialog::basePlane); + if (firstValidPlane == planes.end()) + firstValidPlane = p; + validPlanes++; + base = true; + break; + } + } + if (base) continue; + + // Check whether this plane belongs to the active body + PartDesign::Body* body = getBody(); + if (!body->hasFeature(*p)) { + status.push_back(PartDesignGui::FeaturePickDialog::otherBody); + continue; + } + + // All checks passed - found a valid plane + if (firstValidPlane == planes.end()) + firstValidPlane = p; + validPlanes++; + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); + } + + if (validPlanes == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid planes in this document"), + QObject::tr("Please create a plane first or select a face to sketch on")); + return; + } + + // If there is more than one possibility, show dialog and let user pick plane + if (validPlanes > 1) { + PartDesignGui::FeaturePickDialog Dlg(planes, status); + if ((Dlg.exec() != QDialog::Accepted) || (planes = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + firstValidPlane = planes.begin(); } + + App::Plane* plane = static_cast(*firstValidPlane); + Base::Vector3d p = plane->Placement.getValue().getPosition(); + Base::Rotation r = plane->Placement.getValue().getRotation(); + std::string FeatName = getUniqueObjectName("Sketch"); + std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } - } bool CmdPartDesignNewSketch::isActive(void) @@ -392,7 +425,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, } void finishSketchBased(const Gui::Command* cmd, - const Part::Part2DObject* sketch, const std::string& FeatName, App::DocumentObject*& prevTip) + const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevTip) { App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp index c46b6662d087..a2003b666c02 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp @@ -47,6 +47,7 @@ const QString FeaturePickDialog::getFeatureStatusString(const featureStatus st) case noWire: return tr("No wire in sketch"); case isUsed: return tr("Sketch already used by other feature"); case otherBody: return tr("Sketch belongs to another Body feature"); + case basePlane: return tr("Base plane"); } return tr(""); @@ -104,6 +105,7 @@ void FeaturePickDialog::updateList() case noWire: item->setFlags(Qt::NoItemFlags); break; case isUsed: item->setFlags(ui->checkOtherFeature->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; case otherBody: item->setFlags(ui->checkOtherBody->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; + case basePlane: item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); break; } index++; diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.h b/src/Mod/PartDesign/Gui/FeaturePickDialog.h index 72a96458e865..e70c0422924d 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.h +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.h @@ -40,7 +40,8 @@ class FeaturePickDialog : public QDialog invalidShape, noWire, isUsed, - otherBody + otherBody, + basePlane }; FeaturePickDialog(std::vector &objects, const std::vector &status); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 4158d905a891..088cb1a0c939 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -102,6 +102,16 @@ void Workbench::activated() "Part_Box" )); + const char* Plane[] = { + "PartDesign_NewSketch", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT App::Plane COUNT 1", + Plane, + "Start Part", + "Part_Box" + )); + const char* NoSel[] = { "PartDesign_Body", 0}; diff --git a/src/Mod/Start/StartPage/PartDesign.py b/src/Mod/Start/StartPage/PartDesign.py index 3931e02570f1..bf59c27db1d2 100644 --- a/src/Mod/Start/StartPage/PartDesign.py +++ b/src/Mod/Start/StartPage/PartDesign.py @@ -25,3 +25,6 @@ FreeCADGui.activateWorkbench("PartDesignWorkbench") App.newDocument() FreeCADGui.runCommand('PartDesign_Body') +# Make the planes properly visible +FreeCADGui.activeDocument().activeView().viewAxometric() +FreeCADGui.SendMsgToActiveView("ViewFit") From 6235385c5ac5c486c06774adc7e5ad09dcd7fb28 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 2 Apr 2013 20:51:31 +0430 Subject: [PATCH 065/664] Create Base property for SketchBased features and changed Pad to use it --- src/Mod/PartDesign/App/Body.cpp | 16 ++++++++ src/Mod/PartDesign/App/Body.h | 8 ++++ src/Mod/PartDesign/App/FeaturePad.cpp | 31 ++++++++++++-- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 21 ++++++++++ src/Mod/PartDesign/App/FeatureSketchBased.h | 7 +++- src/Mod/PartDesign/Gui/Command.cpp | 40 ++++++++++--------- 6 files changed, 100 insertions(+), 23 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 40e33035d669..a6fb49143c24 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -86,6 +86,22 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return static_cast(*it)->Shape.getShape(); } +App::DocumentObject* Body::getTipSolidFeature() +{ + std::vector features = Model.getValues(); + if (features.empty()) return NULL; + std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + + // Skip sketches + while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + if (it == features.begin()) + return NULL; + it--; + } + + return *it; +} + const bool Body::hasFeature(const App::DocumentObject* f) { std::vector features = Model.getValues(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index b72a183cc718..8fc28d5c9878 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -58,6 +58,14 @@ class Body : public Part::BodyBase /// Get the tip shape const Part::TopoShape getTipShape(); + /** + * Return Tip feature if it is a solid. Otherwise, go backwards in the Model and + * find the first feature that is a solid (i.e. Sketches are skipped) + * This is used by SketchBased features to determine the shape they should fuse with or cut out off + * NOTE: Currently only PartDesign features are accepted as TipSolidFeatures + */ + App::DocumentObject *getTipSolidFeature(); + /// Return the shape of the feature preceding this feature const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 0a1e262b9ef8..b1d053edbc78 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -96,7 +96,20 @@ App::DocumentObjectExecReturn *Pad::execute(void) return new App::DocumentObjectExecReturn(e.what()); } + TopoDS_Shape support; + try { + support = getSupportShape(); + } catch (const Base::Exception&) { + // ignore, because support isn't mandatory + support = TopoDS_Shape(); + } + +/* // Find Body feature which owns this Pad and get the shape of the feature preceding this one for fusing + // This method was rejected in favour of the Base property because it makes the feature atomic (independent of the + // Body object). See + // https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=19&t=3831 + // https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=19&t=3855 PartDesign::Body* body = getBody(); if (body == NULL) { return new App::DocumentObjectExecReturn( @@ -113,6 +126,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) support = TopoDS_Shape(); else support = prevShape._Shape; +*/ // get the Sketch plane Base::Placement SketchPos = sketch->Placement.getValue(); @@ -184,13 +198,22 @@ App::DocumentObjectExecReturn *Pad::execute(void) prism = refineShapeIfActive(prism); this->AddShape.setValue(prism); - // if the sketch has a support fuse them to get one result object - if (!support.IsNull()) { + // if the Base property has a valid shape, fuse the prism into it + TopoDS_Shape base; + try { + base = getBaseShape(); + base.Move(invObjLoc); + } catch (const Base::Exception&) { + // fall back to support (for legacy features) + base = support; + } + + if (!base.IsNull()) { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(support, prism); + BRepAlgoAPI_Fuse mkFuse(base, prism); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) - return new App::DocumentObjectExecReturn("Pad: Fusion with support failed"); + return new App::DocumentObjectExecReturn("Pad: Fusion with base feature failed"); TopoDS_Shape result = mkFuse.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 147e8fb20db6..52b58c08401b 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -98,6 +98,7 @@ PROPERTY_SOURCE(PartDesign::SketchBased, PartDesign::Feature) SketchBased::SketchBased() { + ADD_PROPERTY(Base,(0)); ADD_PROPERTY_TYPE(Sketch,(0),"SketchBased", App::Prop_None, "Reference to sketch"); ADD_PROPERTY_TYPE(Midplane,(0),"SketchBased", App::Prop_None, "Extrude symmetric to sketch face"); ADD_PROPERTY_TYPE(Reversed, (0),"SketchBased", App::Prop_None, "Reverse extrusion direction"); @@ -231,6 +232,26 @@ const TopoDS_Shape& SketchBased::getSupportShape() const { return result; } +const TopoDS_Shape& SketchBased::getBaseShape() const { + App::DocumentObject* BaseLink = Base.getValue(); + if (BaseLink == NULL) throw Base::Exception("Base property not set"); + Part::Feature* BaseObject = NULL; + if (BaseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + BaseObject = static_cast(BaseLink); + + if (BaseObject == NULL) + throw Base::Exception("No base feature linked"); + + const TopoDS_Shape& result = BaseObject->Shape.getValue(); + if (result.IsNull()) + throw Base::Exception("Base feature's shape is invalid"); + TopExp_Explorer xp (result, TopAbs_SOLID); + if (!xp.More()) + throw Base::Exception("Base feature's shape is not a solid"); + + return result; +} + int SketchBased::getSketchAxisCount(void) const { Part::Part2DObject *sketch = static_cast(Sketch.getValue()); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index abb034e804b7..84269ef9fb13 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -44,7 +44,10 @@ class PartDesignExport SketchBased : public PartDesign::Feature public: SketchBased(); - /// Common properties for all sketch based features + // Common properties for all sketch based features + /// Base feature which this feature will be fused into or cut out of + App::PropertyLink Base; + /// Sketch used to create this feature App::PropertyLink Sketch; /// Reverse extrusion direction App::PropertyBool Reversed; @@ -72,6 +75,8 @@ class PartDesignExport SketchBased : public PartDesign::Feature Part::Feature* getSupport() const; /// Returns the sketch support shape (if any) const TopoDS_Shape& getSupportShape() const; + /// Returns the base property's shape (if any) + const TopoDS_Shape& getBaseShape() const; /// retrieves the number of axes in the linked sketch (defined as construction lines) int getSketchAxisCount(void) const; diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 6f46c38ea240..31be55b6f450 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -300,7 +300,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } } @@ -382,11 +382,10 @@ bool CmdPartDesignNewSketch::isActive(void) } void prepareSketchBased(Gui::Command* cmd, const std::string& which, - Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevTip) + Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevSolidFeature) { PartDesign::Body *pcActiveBody = getBody(); if (!pcActiveBody) return; - prevTip = pcActiveBody->Tip.getValue(); // Get a valid sketch from the user // First check selections @@ -415,17 +414,22 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, } sketch = static_cast(*firstValidSketch); + + // Find valid Body feature to set as the base feature + prevSolidFeature = pcActiveBody->getTipSolidFeature(); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + if (prevSolidFeature != NULL) + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s",FeatName.c_str(),prevSolidFeature->getNameInDocument()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); } void finishSketchBased(const Gui::Command* cmd, - const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevTip) + const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevSolidFeature) { App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { @@ -438,8 +442,8 @@ void finishSketchBased(const Gui::Command* cmd, cmd->updateActive(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - if (prevTip != NULL) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevTip->getNameInDocument()); + if (prevSolidFeature != NULL) + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer @@ -474,14 +478,14 @@ void CmdPartDesignPad::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Pad", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Pad", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } @@ -511,13 +515,13 @@ void CmdPartDesignPocket::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Pocket", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Pocket", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } @@ -547,8 +551,8 @@ void CmdPartDesignRevolution::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Revolution", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Revolution", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -558,7 +562,7 @@ void CmdPartDesignRevolution::activated(int iMsg) if (pcRevolution && pcRevolution->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } @@ -588,8 +592,8 @@ void CmdPartDesignGroove::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevTip; - prepareSketchBased(this, "Groove", sketch, FeatName, prevTip); + App::DocumentObject* prevSolidFeature; + prepareSketchBased(this, "Groove", sketch, FeatName, prevSolidFeature); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -599,7 +603,7 @@ void CmdPartDesignGroove::activated(int iMsg) if (pcGroove && pcGroove->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevTip); + finishSketchBased(this, sketch, FeatName, prevSolidFeature); adjustCameraPosition(); } From 2f658733b7875efd751e4fe8f2e89ffd0d4b460e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 4 Apr 2013 16:33:56 +0430 Subject: [PATCH 066/664] Feature tree: Insert mode for SketchBased features --- src/Mod/PartDesign/App/Body.cpp | 25 ++++ src/Mod/PartDesign/App/Body.h | 11 ++ src/Mod/PartDesign/Gui/Command.cpp | 124 ++++++++++++++++++-- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 2 +- src/Mod/PartDesign/Gui/Workbench.cpp | 10 ++ src/Mod/PartDesign/Gui/Workbench.h | 9 ++ 6 files changed, 170 insertions(+), 11 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index a6fb49143c24..d6b4b948911c 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -102,12 +102,37 @@ App::DocumentObject* Body::getTipSolidFeature() return *it; } +App::DocumentObject* Body::getNextSolidFeature() +{ + std::vector features = Model.getValues(); + if (features.empty()) return NULL; + if (Tip.getValue() == features.back()) return NULL; + + std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + it++; // Move beyond the Tip + + // Skip sketches + while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + it++; + if (it == features.end()) + return NULL; + } + + return *it; +} + const bool Body::hasFeature(const App::DocumentObject* f) { std::vector features = Model.getValues(); return std::find(features.begin(), features.end(), f) != features.end(); } +const bool Body::insertMode() { + std::vector features = Model.getValues(); + if (features.empty()) return false; + return Tip.getValue() != features.back(); +} + App::DocumentObjectExecReturn *Body::execute(void) { std::vector children = Model.getValues(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 8fc28d5c9878..49f22d4bea3a 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -66,14 +66,25 @@ class Body : public Part::BodyBase */ App::DocumentObject *getTipSolidFeature(); + /** + * Return the next solid feature after the Tip feature (so this only makes sense in insert mode) + * This is used by Sketchbased features in insert mode to re-route the Base property + * NOTE: Currently only PartDesign features are accepted as nextSolidFeatures + */ + App::DocumentObject *getNextSolidFeature(); + /// Return the shape of the feature preceding this feature const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); /// Return true if the feature belongs to this body const bool hasFeature(const App::DocumentObject *f); + /// Returns true if we are inserting into the feature tree instead of appending at the end + const bool insertMode(); + PyObject *getPyObject(void); + }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 31be55b6f450..473e6effc644 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -143,6 +144,7 @@ void CmdPartDesignBody::activated(int iMsg) doCommand(Doc,"import PartDesignGui"); doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); // Make the "Create sketch" prompt appear in the task panel + doCommand(Gui,"Gui.Selection.clearSelection()"); doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); updateActive(); @@ -153,6 +155,53 @@ bool CmdPartDesignBody::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_MoveTip +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMoveTip); + +CmdPartDesignMoveTip::CmdPartDesignMoveTip() + : Command("PartDesign_MoveTip") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Insert here"); + sToolTipText = QT_TR_NOOP("Move insert point to selected feature"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_MoveTip"; +} + +void CmdPartDesignMoveTip::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(pcActiveBody); + //ViewProviderBody* vpBody; + //if (vp != NULL) + // vpBody = static_cast(vp); + std::vector bodyChildren = vp->claimChildren(); + + openCommand("Move insert point to selected feature"); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),features.front()->getNameInDocument()); + + // Adjust visibility + for (std::vector::const_iterator f = bodyChildren.begin(); f != bodyChildren.end(); f++) { + if ((*f) == pcActiveBody->Tip.getValue()) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); + else + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); + } +} + +bool CmdPartDesignMoveTip::isActive(void) +{ + return hasActiveDocument(); +} + //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -227,11 +276,26 @@ void CmdPartDesignNewSketch::activated(int iMsg) // create Sketch on Face std::string FeatName = getUniqueObjectName("Sketch"); + App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a Sketch on Face"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + if (nextSolidFeature != NULL) { + // Insert mode + doCommand(Doc,"m = App.activeDocument().%s.Model; " + "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" + "App.activeDocument().%s.Model = m", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str(), + pcActiveBody->getNameInDocument()); + } else { + doCommand(Doc,"App.activeDocument().%s.Model = " + "App.activeDocument().%s.Model + [App.activeDocument().%s]", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str()); + } + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", + pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); @@ -294,13 +358,27 @@ void CmdPartDesignNewSketch::activated(int iMsg) std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; + App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + if (nextSolidFeature != NULL) { + // Insert mode + doCommand(Doc,"m = App.activeDocument().%s.Model; " + "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" + "App.activeDocument().%s.Model = m", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str(), + pcActiveBody->getNameInDocument()); + } else { + doCommand(Doc,"App.activeDocument().%s.Model = " + "App.activeDocument().%s.Model + [App.activeDocument().%s]", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str()); + } + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } } @@ -329,12 +407,13 @@ bool CmdPartDesignNewSketch::isActive(void) firstValidSketch = sketches.end(); for (std::vector::iterator s = sketches.begin(); s != sketches.end(); s++) { + //Base::Console().Error("Checking sketch %s\n", (*s)->getNameInDocument()); // Check whether this sketch is already being used by another feature // Body features don't count... std::vector inList = (*s)->getInList(); std::vector::iterator o = inList.begin(); while (o != inList.end()) { - Base::Console().Error("InList: %s\n", (*o)->getNameInDocument()); + //Base::Console().Error("Inlist: %s\n", (*o)->getNameInDocument()); if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) o = inList.erase(o); else @@ -417,15 +496,37 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, // Find valid Body feature to set as the base feature prevSolidFeature = pcActiveBody->getTipSolidFeature(); + App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); if (prevSolidFeature != NULL) - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s",FeatName.c_str(),prevSolidFeature->getNameInDocument()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + // Set Base property to previous feature + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s", + FeatName.c_str(),prevSolidFeature->getNameInDocument()); + if (nextSolidFeature != NULL) { + // Insert mode + cmd->doCommand(cmd->Doc,"m = App.activeDocument().%s.Model; " + "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" + "App.activeDocument().%s.Model = m", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str(), + pcActiveBody->getNameInDocument()); + // Reroute Base property of the next feature to this feature + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s", + nextSolidFeature->getNameInDocument(), FeatName.c_str()); + } else { + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = " + "App.activeDocument().%s.Model + [App.activeDocument().%s]", + pcActiveBody->getNameInDocument(), + pcActiveBody->getNameInDocument(),FeatName.c_str()); + } + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", + pcActiveBody->getNameInDocument(),FeatName.c_str()); + + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", + FeatName.c_str(),sketch->getNameInDocument()); } void finishSketchBased(const Gui::Command* cmd, @@ -448,6 +549,8 @@ void finishSketchBased(const Gui::Command* cmd, // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); + cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); PartDesign::Body *pcActiveBody = getBody(); if (pcActiveBody) { @@ -1355,4 +1458,5 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 8942fe356920..4d48ab309b20 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -132,7 +132,7 @@ std::vector ViewProviderBody::claimChildren(void)const std::vector ViewProviderBody::claimChildren3D(void)const { - std::vector children = static_cast(getObject())->Model.getValues(); + //std::vector children = static_cast(getObject())->Model.getValues(); //Base::Console().Error("Body 3D claimed children:\n"); //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) // Base::Console().Error("%s\n", (*o)->getNameInDocument()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 088cb1a0c939..85c547e32219 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -36,6 +36,7 @@ #include #include +#include using namespace PartDesignGui; @@ -60,6 +61,15 @@ Workbench::~Workbench() { } +void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const +{ + if (strcmp(recipient,"Tree") == 0) + { + if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) > 0 ) + *item << "PartDesign_MoveTip"; + } +} + void Workbench::activated() { Gui::Workbench::activated(); diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 02220f870ed3..f7cc4b97a46d 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -26,6 +26,12 @@ #include +namespace Gui { + +class MenuItem; + +} + namespace PartDesignGui { /** @@ -44,6 +50,9 @@ class PartDesignGuiExport Workbench : public Gui::StdWorkbench /** Run some actions when the workbench gets deactivated. */ virtual void deactivated(); + /// Add custom entries to the context menu + virtual void setupContextMenu(const char* recipient, Gui::MenuItem*) const; + protected: Gui::MenuItem* setupMenuBar() const; Gui::ToolBarItem* setupToolBars() const; From 10c8ba7e9bcff4c4686b4d228d5252ad310b5a73 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 5 Apr 2013 20:06:23 +0430 Subject: [PATCH 067/664] Moved ActivePartObject etc. to PartDesignGui namespace and added extern declaration to Workbench.h as suggested by logari81 --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 30 ++++++++++++++------------ src/Mod/PartDesign/Gui/Command.cpp | 7 +++--- src/Mod/PartDesign/Gui/Workbench.cpp | 6 ++---- src/Mod/PartDesign/Gui/Workbench.h | 14 ++++++++++++ 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index e048646e9e5f..7c0997d49b37 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -36,30 +36,32 @@ #include +namespace PartDesignGui { + // pointer to the active assembly object PartDesign::Body *ActivePartObject =0; Gui::Document *ActiveGuiDoc =0; App::Document *ActiveAppDoc =0; Gui::ViewProviderDocumentObject *ActiveVp =0; - +} static PyObject * setActivePart(PyObject *self, PyObject *args) { - if(ActivePartObject){ + if(PartDesignGui::ActivePartObject){ // check if the document not already closed std::vector docs = App::GetApplication().getDocuments(); for(std::vector::const_iterator it=docs.begin();it!=docs.end();++it) - if(*it == ActiveAppDoc){ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,false); + if(*it == PartDesignGui::ActiveAppDoc){ + PartDesignGui::ActiveGuiDoc->signalHighlightObject(*PartDesignGui::ActiveVp,Gui::Underlined,false); break; } - ActivePartObject->IsActive.setValue(false); - ActivePartObject = 0; - ActiveGuiDoc =0; - ActiveAppDoc =0; - ActiveVp =0; + PartDesignGui::ActivePartObject->IsActive.setValue(false); + PartDesignGui::ActivePartObject = 0; + PartDesignGui::ActiveGuiDoc =0; + PartDesignGui::ActiveAppDoc =0; + PartDesignGui::ActiveVp =0; } PyObject *object=0; @@ -69,11 +71,11 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) assert(Item); Item->IsActive.setValue(true); - ActivePartObject = Item; - ActiveAppDoc = Item->getDocument(); - ActiveGuiDoc = Gui::Application::Instance->getDocument(ActiveAppDoc); - ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Underlined,true); + PartDesignGui::ActivePartObject = Item; + PartDesignGui::ActiveAppDoc = Item->getDocument(); + PartDesignGui::ActiveGuiDoc = Gui::Application::Instance->getDocument(PartDesignGui::ActiveAppDoc); + PartDesignGui::ActiveVp = dynamic_cast (PartDesignGui::ActiveGuiDoc->getViewProvider(Item)) ; + PartDesignGui::ActiveGuiDoc->signalHighlightObject(*PartDesignGui::ActiveVp,Gui::Underlined,true); } diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 473e6effc644..dff0d12b7989 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -59,11 +59,10 @@ #include #include "FeaturePickDialog.h" +#include "Workbench.h" using namespace std; -extern PartDesign::Body *ActivePartObject; - //=========================================================================== // Helper for Body @@ -71,7 +70,7 @@ extern PartDesign::Body *ActivePartObject; PartDesign::Body *getBody(void) { - if(!ActivePartObject){ + if(!PartDesignGui::ActivePartObject){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), QObject::tr("In order to use PartDesign you need an active Body object in the document. " "Please make one active or create one. If you have a legacy document " @@ -79,7 +78,7 @@ PartDesign::Body *getBody(void) "PartDesign to put them into a Body." )); } - return ActivePartObject; + return PartDesignGui::ActivePartObject; } diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 85c547e32219..e98ba841f7e1 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -47,8 +47,6 @@ using namespace PartDesignGui; qApp->translate("Gui::TaskView::TaskWatcherCommands", "Create Geometry"); #endif -extern PartDesign::Body *ActivePartObject; - /// @namespace PartDesignGui @class Workbench TYPESYSTEM_SOURCE(PartDesignGui::Workbench, Gui::StdWorkbench) @@ -208,8 +206,8 @@ void Workbench::deactivated() removeTaskWatcher(); // remember the body for later activation // TODO: Remove this if the IsActive Property of Body works OK - if(ActivePartObject) - oldActive = ActivePartObject->getNameInDocument(); + if(PartDesignGui::ActivePartObject) + oldActive = PartDesignGui::ActivePartObject->getNameInDocument(); else oldActive = ""; // reset the active Body diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index f7cc4b97a46d..dea16e27d4fe 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -29,11 +29,25 @@ namespace Gui { class MenuItem; +class Document; +class ViewProviderDocumentObject; + +} + +namespace PartDesign { + +class Body; } namespace PartDesignGui { +// pointer to the active assembly object +extern PartDesign::Body *ActivePartObject; +extern Gui::Document *ActiveGuiDoc; +extern App::Document *ActiveAppDoc; +extern Gui::ViewProviderDocumentObject *ActiveVp; + /** * @author Werner Mayer */ From 339666adcfc837a8715f7e25aed3c749d319578f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 5 Apr 2013 20:07:18 +0430 Subject: [PATCH 068/664] Highlight current insert point (Tip feature) in blue --- src/Mod/PartDesign/Gui/Command.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index dff0d12b7989..9fea60778f5e 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -50,6 +50,9 @@ #include #include #include +#include +#include +#include #include #include @@ -179,19 +182,22 @@ void CmdPartDesignMoveTip::activated(int iMsg) std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); if (features.empty()) return; Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(pcActiveBody); - //ViewProviderBody* vpBody; - //if (vp != NULL) - // vpBody = static_cast(vp); std::vector bodyChildren = vp->claimChildren(); + App::DocumentObject* tipFeature = pcActiveBody->Tip.getValue(); + const Gui::ViewProviderDocumentObject* vpFeature = dynamic_cast(Gui::Application::Instance->getViewProvider(tipFeature)); + PartDesignGui::ActiveGuiDoc->signalHighlightObject(*vpFeature, Gui::Blue, false); + openCommand("Move insert point to selected feature"); doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),features.front()->getNameInDocument()); // Adjust visibility for (std::vector::const_iterator f = bodyChildren.begin(); f != bodyChildren.end(); f++) { - if ((*f) == pcActiveBody->Tip.getValue()) + if ((*f) == pcActiveBody->Tip.getValue()) { doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); - else + vpFeature = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); + PartDesignGui::ActiveGuiDoc->signalHighlightObject(*vpFeature,Gui::Blue,true); + } else doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); } } From c93d4253935d723b5d7da3ef2f7bfcfc4f7a5e3e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Apr 2013 08:06:53 +0430 Subject: [PATCH 069/664] Renamed SketchBased::Base property to BaseFeature because of name clash with Revolution::Base property --- src/Mod/PartDesign/App/Feature.cpp | 12 +----------- src/Mod/PartDesign/App/Feature.h | 7 ++----- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 7 ++++--- src/Mod/PartDesign/App/FeatureSketchBased.h | 2 +- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 3c08112d5af6..dfb1d050cddb 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -37,6 +37,7 @@ #include "Body.h" #include "Feature.h" +#include namespace PartDesign { @@ -61,17 +62,6 @@ TopoDS_Shape Feature::getSolid(const TopoDS_Shape& shape) return TopoDS_Shape(); } -PartDesign::Body* Feature::getBody() -{ - std::vector bodies = this->getDocument()->getObjectsOfType(PartDesign::Body::getClassTypeId()); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { - PartDesign::Body* body = static_cast(*b); - if (body->hasFeature(this)) - return body; - } - return NULL; -} - const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f) { if (!f.Infinite()) { diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 43e1be04c5b0..41125fb64c78 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -45,12 +45,9 @@ class PartDesignExport Feature : public Part::Feature PROPERTY_HEADER(PartDesign::Feature); public: - Feature(); - -protected: - /// Get the body feature which this feature belongs to - Body* getBody(); + Feature(); +protected: /** * Get a solid of the given shape. If no solid is found an exception is raised. */ diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 52b58c08401b..2d7c2db953bf 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -98,7 +98,7 @@ PROPERTY_SOURCE(PartDesign::SketchBased, PartDesign::Feature) SketchBased::SketchBased() { - ADD_PROPERTY(Base,(0)); + ADD_PROPERTY(BaseFeature,(0)); ADD_PROPERTY_TYPE(Sketch,(0),"SketchBased", App::Prop_None, "Reference to sketch"); ADD_PROPERTY_TYPE(Midplane,(0),"SketchBased", App::Prop_None, "Extrude symmetric to sketch face"); ADD_PROPERTY_TYPE(Reversed, (0),"SketchBased", App::Prop_None, "Reverse extrusion direction"); @@ -106,7 +106,8 @@ SketchBased::SketchBased() short SketchBased::mustExecute() const { - if (Sketch.isTouched() || + if (BaseFeature.isTouched() || + Sketch.isTouched() || Midplane.isTouched() || Reversed.isTouched()) return 1; @@ -233,7 +234,7 @@ const TopoDS_Shape& SketchBased::getSupportShape() const { } const TopoDS_Shape& SketchBased::getBaseShape() const { - App::DocumentObject* BaseLink = Base.getValue(); + App::DocumentObject* BaseLink = BaseFeature.getValue(); if (BaseLink == NULL) throw Base::Exception("Base property not set"); Part::Feature* BaseObject = NULL; if (BaseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 84269ef9fb13..b663fb125983 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -46,7 +46,7 @@ class PartDesignExport SketchBased : public PartDesign::Feature // Common properties for all sketch based features /// Base feature which this feature will be fused into or cut out of - App::PropertyLink Base; + App::PropertyLink BaseFeature; /// Sketch used to create this feature App::PropertyLink Sketch; /// Reverse extrusion direction From 7d84c7e6f03c9dedff8c2812ccf5ff25758b155c Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Apr 2013 08:09:00 +0430 Subject: [PATCH 070/664] Made Pocket, Revolution and Groove aware of the SketchBased::BaseFeature property --- src/Mod/PartDesign/App/FeatureGroove.cpp | 28 ++++++++++++++--- src/Mod/PartDesign/App/FeaturePad.cpp | 3 +- src/Mod/PartDesign/App/FeaturePocket.cpp | 32 ++++++++++++++++---- src/Mod/PartDesign/App/FeatureRevolution.cpp | 17 ++++++++--- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index e961fded4e3a..a126fcbd881c 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -87,15 +87,32 @@ App::DocumentObjectExecReturn *Groove::execute(void) angle *= (-1.0); std::vector wires; - TopoDS_Shape support; try { wires = getSketchWires(); - support = getSupportShape(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } - // update Axis from ReferenceAxis + // Get the sketch support + TopoDS_Shape support; + try { + support = getSupportShape(); + } catch (const Base::Exception&) { + // ignore, because support isn't mandatory any more + support = TopoDS_Shape(); + } + + // Get the base shape + TopoDS_Shape base; + try { + base = getBaseShape(); + } catch (const Base::Exception&) { + // fall back to support (for legacy features) + base = support; + if (base.IsNull()) + return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the groove!"); + } + updateAxis(); // get revolve axis @@ -122,6 +139,7 @@ App::DocumentObjectExecReturn *Groove::execute(void) pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); support.Move(invObjLoc); + base.Move(invObjLoc); sketchshape.Move(invObjLoc); // Check distance between sketchshape and axis - to avoid failures and crashes @@ -138,10 +156,10 @@ App::DocumentObjectExecReturn *Groove::execute(void) this->SubShape.setValue(result); // cut out groove to get one result object - BRepAlgoAPI_Cut mkCut(support, result); + BRepAlgoAPI_Cut mkCut(base, result); // Let's check if the fusion has been successful if (!mkCut.IsDone()) - throw Base::Exception("Cut out of support failed"); + throw Base::Exception("Cut out of base feature failed"); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(mkCut.Shape()); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index b1d053edbc78..ebc414eb96e7 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -47,7 +47,7 @@ #include #include -#include "Body.h" +//#include "Body.h" #include "FeaturePad.h" @@ -175,6 +175,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) BRep_Builder builder; builder.MakeCompound(comp); + // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { BRepFeat_MakePrism PrismMaker; PrismMaker.Init(support, xp.Current(), supportface, dir, 2, 1); diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 20d28cdf652b..35b7391179f3 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -89,15 +89,33 @@ App::DocumentObjectExecReturn *Pocket::execute(void) Part::Part2DObject* sketch = 0; std::vector wires; - TopoDS_Shape support; try { sketch = getVerifiedSketch(); wires = getSketchWires(); - support = getSupportShape(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); } + // Get the sketch support + TopoDS_Shape support; + try { + support = getSupportShape(); + } catch (const Base::Exception&) { + // ignore, because support isn't mandatory any more + support = TopoDS_Shape(); + } + + // Get the base shape + TopoDS_Shape base; + try { + base = getBaseShape(); + } catch (const Base::Exception&) { + // fall back to support (for legacy features) + base = support; + if (base.IsNull()) + return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the pocket!"); + } + // get the Sketch plane Base::Placement SketchPos = sketch->Placement.getValue(); Base::Rotation SketchOrientation = SketchPos.getRotation(); @@ -111,7 +129,8 @@ App::DocumentObjectExecReturn *Pocket::execute(void) TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { - support.Move(invObjLoc); + support.Move(invObjLoc); + base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); dir.Transform(invObjLoc.Transformation()); @@ -140,6 +159,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void) for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { // Special treatment because often the created stand-alone prism is invalid (empty) because // BRepFeat_MakePrism(..., 2, 1) is buggy + // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results BRepFeat_MakePrism PrismMaker; PrismMaker.Init(prism, xp.Current(), supportface, dir, 0, 1); PrismMaker.Perform(upToFace); @@ -170,10 +190,10 @@ App::DocumentObjectExecReturn *Pocket::execute(void) prism = refineShapeIfActive(prism); this->SubShape.setValue(prism); - // Cut the SubShape out of the support - BRepAlgoAPI_Cut mkCut(support, prism); + // Cut the SubShape out of the base feature + BRepAlgoAPI_Cut mkCut(base, prism); if (!mkCut.IsDone()) - return new App::DocumentObjectExecReturn("Pocket: Cut out of support failed"); + return new App::DocumentObjectExecReturn("Pocket: Cut out of base feature failed"); TopoDS_Shape result = mkCut.Shape(); // we have to get the solids (fuse sometimes creates compounds) TopoDS_Shape solRes = this->getSolid(result); diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 76bb61366a40..67b888685aa9 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -143,13 +143,22 @@ App::DocumentObjectExecReturn *Revolution::execute(void) // set the additive shape property for later usage in e.g. pattern this->AddShape.setValue(result); - // if the sketch has a support fuse them to get one result object (PAD!) - if (!support.IsNull()) { + // if the Base property has a valid shape, fuse the AddShape into it + TopoDS_Shape base; + try { + base = getBaseShape(); + base.Move(invObjLoc); + } catch (const Base::Exception&) { + // fall back to support (for legacy features) + base = support; + } + + if (!base.IsNull()) { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(support, result); + BRepAlgoAPI_Fuse mkFuse(base, result); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) - throw Base::Exception("Fusion with support failed"); + throw Base::Exception("Fusion with base feature failed"); result = mkFuse.Shape(); result = refineShapeIfActive(result); } From f7d9bf90c4972930718e27d769ce7b114ea28f16 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Apr 2013 08:10:00 +0430 Subject: [PATCH 071/664] Moved getBody() to PartDesign namespace in Workbench.cpp because ActivePartObject is also declared there now --- src/Mod/PartDesign/Gui/Command.cpp | 38 ++++++++-------------------- src/Mod/PartDesign/Gui/Workbench.cpp | 21 +++++++++++++++ src/Mod/PartDesign/Gui/Workbench.h | 3 +++ 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 9fea60778f5e..4ae302fff97d 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -67,24 +67,6 @@ using namespace std; -//=========================================================================== -// Helper for Body -//=========================================================================== - -PartDesign::Body *getBody(void) -{ - if(!PartDesignGui::ActivePartObject){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), - QObject::tr("In order to use PartDesign you need an active Body object in the document. " - "Please make one active or create one. If you have a legacy document " - "with PartDesign objects without Body, use the transfer function in " - "PartDesign to put them into a Body." - )); - } - return PartDesignGui::ActivePartObject; - -} - const char* BasePlaneNames[3] = {"Body_PlaneXY", "Body_PlaneYZ", "Body_PlaneXZ"}; //=========================================================================== @@ -176,7 +158,7 @@ CmdPartDesignMoveTip::CmdPartDesignMoveTip() void CmdPartDesignMoveTip::activated(int iMsg) { - PartDesign::Body *pcActiveBody = getBody(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if(!pcActiveBody) return; std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); @@ -229,7 +211,7 @@ CmdPartDesignNewSketch::CmdPartDesignNewSketch() void CmdPartDesignNewSketch::activated(int iMsg) { - PartDesign::Body *pcActiveBody = getBody(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); // No PartDesign feature without Body past FreeCAD 0.13 if(!pcActiveBody) return; @@ -330,7 +312,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (base) continue; // Check whether this plane belongs to the active body - PartDesign::Body* body = getBody(); + PartDesign::Body* body = PartDesignGui::getBody(); if (!body->hasFeature(*p)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; @@ -430,7 +412,7 @@ bool CmdPartDesignNewSketch::isActive(void) } // Check whether this sketch belongs to the active body - PartDesign::Body* body = getBody(); + PartDesign::Body* body = PartDesignGui::getBody(); if (!body->hasFeature(*s)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; @@ -468,7 +450,7 @@ bool CmdPartDesignNewSketch::isActive(void) void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevSolidFeature) { - PartDesign::Body *pcActiveBody = getBody(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (!pcActiveBody) return; // Get a valid sketch from the user @@ -507,8 +489,8 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, cmd->openCommand((std::string("Make ") + which).c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); if (prevSolidFeature != NULL) - // Set Base property to previous feature - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s", + // Set BaseFeature property to previous feature + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", FeatName.c_str(),prevSolidFeature->getNameInDocument()); if (nextSolidFeature != NULL) { // Insert mode @@ -518,8 +500,8 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, pcActiveBody->getNameInDocument(), pcActiveBody->getNameInDocument(),FeatName.c_str(), pcActiveBody->getNameInDocument()); - // Reroute Base property of the next feature to this feature - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = App.activeDocument().%s", + // Reroute BaseFeature property of the next feature to this feature + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", nextSolidFeature->getNameInDocument(), FeatName.c_str()); } else { cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = " @@ -557,7 +539,7 @@ void finishSketchBased(const Gui::Command* cmd, cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); - PartDesign::Body *pcActiveBody = getBody(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (pcActiveBody) { cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index e98ba841f7e1..d48ab0ddb340 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,26 @@ using namespace PartDesignGui; qApp->translate("Gui::TaskView::TaskWatcherCommands", "Create Geometry"); #endif +namespace PartDesignGui { +//=========================================================================== +// Helper for Body +//=========================================================================== + +PartDesign::Body *getBody(void) +{ + if(!PartDesignGui::ActivePartObject){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), + QObject::tr("In order to use PartDesign you need an active Body object in the document. " + "Please make one active or create one. If you have a legacy document " + "with PartDesign objects without Body, use the transfer function in " + "PartDesign to put them into a Body." + )); + } + return PartDesignGui::ActivePartObject; + +} + +} /// @namespace PartDesignGui @class Workbench TYPESYSTEM_SOURCE(PartDesignGui::Workbench, Gui::StdWorkbench) diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index dea16e27d4fe..0b042a91df68 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -48,6 +48,9 @@ extern Gui::Document *ActiveGuiDoc; extern App::Document *ActiveAppDoc; extern Gui::ViewProviderDocumentObject *ActiveVp; +/// Return active body or show a warning message +PartDesign::Body *getBody(void); + /** * @author Werner Mayer */ From df7983fe10ad7c62048b4bfd5ed2a5f9978cf8a6 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 8 Apr 2013 20:25:59 +0430 Subject: [PATCH 072/664] Moved BaseFeature Property from SketchBased to PartDesign::Feature because all PartDesign features need it --- src/Mod/PartDesign/App/Feature.cpp | 29 +++++++++++++++++++ src/Mod/PartDesign/App/Feature.h | 10 ++++++- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 26 ++--------------- src/Mod/PartDesign/App/FeatureSketchBased.h | 4 --- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index dfb1d050cddb..01247100b971 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -47,6 +47,15 @@ PROPERTY_SOURCE(PartDesign::Feature,Part::Feature) Feature::Feature() { + ADD_PROPERTY(BaseFeature,(0)); + +} + +short Feature::mustExecute() const +{ + if (BaseFeature.isTouched()) + return 1; + return Part::Feature::mustExecute(); } TopoDS_Shape Feature::getSolid(const TopoDS_Shape& shape) @@ -77,4 +86,24 @@ const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f) throw Base::Exception("getPointFromFace(): Not implemented yet for this case"); } +const TopoDS_Shape& Feature::getBaseShape() const { + App::DocumentObject* BaseLink = BaseFeature.getValue(); + if (BaseLink == NULL) throw Base::Exception("Base property not set"); + Part::Feature* BaseObject = NULL; + if (BaseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + BaseObject = static_cast(BaseLink); + + if (BaseObject == NULL) + throw Base::Exception("No base feature linked"); + + const TopoDS_Shape& result = BaseObject->Shape.getValue(); + if (result.IsNull()) + throw Base::Exception("Base feature's shape is invalid"); + TopExp_Explorer xp (result, TopAbs_SOLID); + if (!xp.More()) + throw Base::Exception("Base feature's shape is not a solid"); + + return result; +} + } diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 41125fb64c78..3fe92e7619ae 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -45,9 +45,17 @@ class PartDesignExport Feature : public Part::Feature PROPERTY_HEADER(PartDesign::Feature); public: - Feature(); + Feature(); + + /// Base feature which this feature will be fused into or cut out of + App::PropertyLink BaseFeature; + + short mustExecute() const; protected: + /// Returns the BaseFeature property's shape (if any) + const TopoDS_Shape& getBaseShape() const; + /** * Get a solid of the given shape. If no solid is found an exception is raised. */ diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 2d7c2db953bf..3a46b199443f 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -98,7 +98,6 @@ PROPERTY_SOURCE(PartDesign::SketchBased, PartDesign::Feature) SketchBased::SketchBased() { - ADD_PROPERTY(BaseFeature,(0)); ADD_PROPERTY_TYPE(Sketch,(0),"SketchBased", App::Prop_None, "Reference to sketch"); ADD_PROPERTY_TYPE(Midplane,(0),"SketchBased", App::Prop_None, "Extrude symmetric to sketch face"); ADD_PROPERTY_TYPE(Reversed, (0),"SketchBased", App::Prop_None, "Reverse extrusion direction"); @@ -106,12 +105,11 @@ SketchBased::SketchBased() short SketchBased::mustExecute() const { - if (BaseFeature.isTouched() || - Sketch.isTouched() || + if (Sketch.isTouched() || Midplane.isTouched() || Reversed.isTouched()) return 1; - return 0; // PartDesign::Feature::mustExecute(); + return PartDesign::Feature::mustExecute(); } void SketchBased::positionBySketch(void) @@ -233,26 +231,6 @@ const TopoDS_Shape& SketchBased::getSupportShape() const { return result; } -const TopoDS_Shape& SketchBased::getBaseShape() const { - App::DocumentObject* BaseLink = BaseFeature.getValue(); - if (BaseLink == NULL) throw Base::Exception("Base property not set"); - Part::Feature* BaseObject = NULL; - if (BaseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - BaseObject = static_cast(BaseLink); - - if (BaseObject == NULL) - throw Base::Exception("No base feature linked"); - - const TopoDS_Shape& result = BaseObject->Shape.getValue(); - if (result.IsNull()) - throw Base::Exception("Base feature's shape is invalid"); - TopExp_Explorer xp (result, TopAbs_SOLID); - if (!xp.More()) - throw Base::Exception("Base feature's shape is not a solid"); - - return result; -} - int SketchBased::getSketchAxisCount(void) const { Part::Part2DObject *sketch = static_cast(Sketch.getValue()); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index b663fb125983..7284df649165 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -45,8 +45,6 @@ class PartDesignExport SketchBased : public PartDesign::Feature SketchBased(); // Common properties for all sketch based features - /// Base feature which this feature will be fused into or cut out of - App::PropertyLink BaseFeature; /// Sketch used to create this feature App::PropertyLink Sketch; /// Reverse extrusion direction @@ -75,8 +73,6 @@ class PartDesignExport SketchBased : public PartDesign::Feature Part::Feature* getSupport() const; /// Returns the sketch support shape (if any) const TopoDS_Shape& getSupportShape() const; - /// Returns the base property's shape (if any) - const TopoDS_Shape& getBaseShape() const; /// retrieves the number of axes in the linked sketch (defined as construction lines) int getSketchAxisCount(void) const; From 1ec99c5d3280709d8cc222713d45ab9548bb9ac4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 10 Apr 2013 17:41:26 +0430 Subject: [PATCH 073/664] Work on inserting, removing, hiding and showing features in the body --- src/Gui/Tree.cpp | 6 + src/Gui/Tree.h | 3 +- src/Mod/Assembly/App/AppAssemblyPy.cpp | 31 ++-- src/Mod/Part/App/Part2DObject.cpp | 2 + src/Mod/PartDesign/App/Body.cpp | 185 ++++++++++++++++--- src/Mod/PartDesign/App/Body.h | 44 +++-- src/Mod/PartDesign/App/BodyPy.xml | 10 + src/Mod/PartDesign/App/BodyPyImp.cpp | 46 +++++ src/Mod/PartDesign/Gui/Command.cpp | 168 +++++++---------- src/Mod/PartDesign/Gui/FeaturePickDialog.cpp | 2 + src/Mod/PartDesign/Gui/FeaturePickDialog.h | 3 +- src/Mod/PartDesign/Gui/ViewProvider.cpp | 25 +++ src/Mod/PartDesign/Gui/ViewProvider.h | 2 + 13 files changed, 366 insertions(+), 161 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 37d29016216c..b267fd12bd75 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -1032,6 +1032,12 @@ void DocumentItem::slotHighlightObject (const Gui::ViewProviderDocumentObject& o else jt->second->setData(0, Qt::BackgroundColorRole,QVariant()); break; + case Gui::LightBlue: + if(set) + jt->second->setBackgroundColor(0,QColor(230,230,255)); + else + jt->second->setData(0, Qt::BackgroundColorRole,QVariant()); + break; default: break; } diff --git a/src/Gui/Tree.h b/src/Gui/Tree.h index 2a8fa840e6e3..fb3e3f3dbb2c 100644 --- a/src/Gui/Tree.h +++ b/src/Gui/Tree.h @@ -44,7 +44,8 @@ enum HighlightMode { Underlined, Italic , Overlined , Bold , - Blue + Blue , + LightBlue }; /// highlight modes for the tree items diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 7c0997d49b37..812d2cdec359 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -31,11 +31,12 @@ #include #include -#include #include #include +#include "ViewProviderBody.h" + namespace PartDesignGui { // pointer to the active assembly object @@ -48,35 +49,25 @@ Gui::ViewProviderDocumentObject *ActiveVp =0; static PyObject * setActivePart(PyObject *self, PyObject *args) { - if(PartDesignGui::ActivePartObject){ - // check if the document not already closed - std::vector docs = App::GetApplication().getDocuments(); - for(std::vector::const_iterator it=docs.begin();it!=docs.end();++it) - if(*it == PartDesignGui::ActiveAppDoc){ - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*PartDesignGui::ActiveVp,Gui::Underlined,false); - break; - } - - PartDesignGui::ActivePartObject->IsActive.setValue(false); - PartDesignGui::ActivePartObject = 0; - PartDesignGui::ActiveGuiDoc =0; - PartDesignGui::ActiveAppDoc =0; - PartDesignGui::ActiveVp =0; - } - PyObject *object=0; if (PyArg_ParseTuple(args,"|O!",&(PartDesign::BodyPy::Type), &object)&& object) { PartDesign::Body* Item = static_cast(object)->getBodyPtr(); // Should be set! assert(Item); - Item->IsActive.setValue(true); + if (PartDesignGui::ActivePartObject != NULL) + PartDesignGui::ActivePartObject->IsActive.setValue(false); PartDesignGui::ActivePartObject = Item; PartDesignGui::ActiveAppDoc = Item->getDocument(); PartDesignGui::ActiveGuiDoc = Gui::Application::Instance->getDocument(PartDesignGui::ActiveAppDoc); PartDesignGui::ActiveVp = dynamic_cast (PartDesignGui::ActiveGuiDoc->getViewProvider(Item)) ; - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*PartDesignGui::ActiveVp,Gui::Underlined,true); - + Item->IsActive.setValue(true); + } else { + // This handles the case of deactivating the workbench + PartDesignGui::ActivePartObject = 0; + PartDesignGui::ActiveGuiDoc =0; + PartDesignGui::ActiveAppDoc =0; + PartDesignGui::ActiveVp =0; } Py_Return; diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index 46f0635415d5..2a68c0018392 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -80,6 +80,8 @@ void Part2DObject::positionBySupport(void) bool Reverse = false; gp_Pln plane; App::DocumentObject* support = Support.getValue(); + if (support == NULL) + throw Base::Exception("Sketch support has been deleted"); if (support->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { Place = static_cast(support)->Placement.getValue(); diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index d6b4b948911c..6c58a58f41a1 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -28,10 +28,14 @@ #include #include "Feature.h" +#include "DatumFeature.h" #include "Body.h" #include "BodyPy.h" +#include +#include #include +#include "FeatureSketchBased.h" using namespace PartDesign; @@ -46,6 +50,26 @@ Body::Body() ADD_PROPERTY(IsActive,(0)); } +void Body::onChanged(const App::Property *prop) +{ + Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); + App::DocumentObject* tip = Tip.getValue(); + Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); + std::vector model = Model.getValues(); + Base::Console().Error(" Model:\n"); + for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { + Base::Console().Error(" %s", (*m)->getNameInDocument()); + if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { + App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); + Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); + } else { + Base::Console().Error("\n"); + } + } + + return Part::Feature::onChanged(prop); +} + short Body::mustExecute() const { if (Tip.isTouched() ) @@ -66,7 +90,7 @@ const Part::TopoShape Body::getTipShape() // get the shape of the tip return static_cast(link)->Shape.getShape(); } - +/* const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) { std::vector features = Model.getValues(); @@ -76,8 +100,9 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return Part::TopoShape(); // move to previous feature it--; - // Skip sketches - while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + // Skip sketches and datum features + while ((*it)->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) || + (*it)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { if (it == features.begin()) return Part::TopoShape(); it--; @@ -85,38 +110,47 @@ const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) return static_cast(*it)->Shape.getShape(); } - -App::DocumentObject* Body::getTipSolidFeature() +*/ +App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start, const bool inclusive) { std::vector features = Model.getValues(); if (features.empty()) return NULL; - std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); + + if (inclusive && isSolidFeature(st)) + return st; + + std::vector::iterator it = std::find(features.begin(), features.end(), st); + if (it == features.end()) return NULL; // Invalid start object - // Skip sketches - while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + // Skip sketches and datum features + do { if (it == features.begin()) return NULL; it--; - } + } while (!isSolidFeature(*it)); return *it; } -App::DocumentObject* Body::getNextSolidFeature() +App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const bool inclusive) { std::vector features = Model.getValues(); if (features.empty()) return NULL; - if (Tip.getValue() == features.back()) return NULL; + App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); + + if (inclusive && isSolidFeature(st)) + return st; - std::vector::const_iterator it = std::find(features.begin(), features.end(), Tip.getValue()); - it++; // Move beyond the Tip + std::vector::iterator it = std::find(features.begin(), features.end(), st); + if (it == features.end()) return NULL; // Invalid start object - // Skip sketches - while (!(*it)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + // Skip sketches and datum features + do { it++; if (it == features.end()) return NULL; - } + } while (!isSolidFeature(*it)); return *it; } @@ -127,19 +161,122 @@ const bool Body::hasFeature(const App::DocumentObject* f) return std::find(features.begin(), features.end(), f) != features.end(); } -const bool Body::insertMode() { +const bool Body::isAfterTip(const App::DocumentObject *f) { std::vector features = Model.getValues(); - if (features.empty()) return false; - return Tip.getValue() != features.back(); + std::vector::const_iterator it = std::find(features.begin(), features.end(), f); + std::vector::const_iterator tip = std::find(features.begin(), features.end(), Tip.getValue()); + return (it > tip); } -App::DocumentObjectExecReturn *Body::execute(void) +const bool Body::isSolidFeature(const App::DocumentObject* f) +{ + return (!f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) && + !f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); +} + +Body* Body::findBodyOf(const App::DocumentObject* f) { - std::vector children = Model.getValues(); - //Base::Console().Error("Body exec children:\n"); - //for (std::vector::const_iterator o = children.begin(); o != children.end(); o++) - // Base::Console().Error("%s\n", (*o)->getNameInDocument()); + App::Document* doc = App::GetApplication().getActiveDocument(); + if (doc != NULL) { + std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->hasFeature(f)) + return body; + } + } + return NULL; +} + +void Body::insertFeature(App::DocumentObject *feature) +{ + // Set the BaseFeature property + // Note: This is not strictly necessary for Datum features + if (feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + App::DocumentObject* prevSolidFeature = getPrevSolidFeature(NULL, true); + if (prevSolidFeature != NULL) + // Set BaseFeature property to previous feature (this might be the Tip feature) + static_cast(feature)->BaseFeature.setValue(prevSolidFeature); + } + + if (Body::isSolidFeature(feature)) { + // Reroute the next solid feature's BaseFeature property to this feature + App::DocumentObject* nextSolidFeature = getNextSolidFeature(NULL, false); + if (nextSolidFeature != NULL) + static_cast(nextSolidFeature)->BaseFeature.setValue(feature); + } + + // Insert the new feature after the current Tip feature + App::DocumentObject* tipFeature = Tip.getValue(); + std::vector model = Model.getValues(); + if (tipFeature == NULL) { + if (model.empty()) + // First feature in the body + model.push_back(feature); + else + throw Base::Exception("Body has features, but Tip is not valid"); + } else { + // Insert after Tip + std::vector::iterator it = std::find(model.begin(), model.end(), tipFeature); + if (it == model.end()) + throw Base::Exception("Body: Tip is not contained in model"); + + it++; + if (it == model.end()) + model.push_back(feature); + else + model.insert(it, feature); + } + Model.setValues(model); + + // Move the Tip + Tip.setValue(feature); +} + +void Body::removeFeature(App::DocumentObject* feature) +{ + if (isSolidFeature(feature)) { + // This is a solid feature + // If the next feature is solid, reroute its BaseFeature property to the previous solid feature + App::DocumentObject* nextSolidFeature = getNextSolidFeature(feature, false); + if (nextSolidFeature != NULL) { + App::DocumentObject* prevSolidFeature = getPrevSolidFeature(feature, false); + PartDesign::Feature* nextFeature = static_cast(nextSolidFeature); + if ((prevSolidFeature == NULL) && (nextFeature->BaseFeature.getValue() != NULL)) + // sanity check + throw Base::Exception((std::string("Body: Base feature of ") + nextFeature->getNameInDocument() + " was removed!").c_str()); + nextFeature->BaseFeature.setValue(prevSolidFeature); + } + } + + // Adjust Tip feature if it is pointing to the deleted object + App::DocumentObject* tipFeature = Tip.getValue(); + std::vector model = Model.getValues(); + std::vector::iterator it = std::find(model.begin(), model.end(), feature); + if (tipFeature == feature) { + // Set the Tip to the previous feature if possible, otherwise to the next feature + std::vector::const_iterator prev = it, next = it; + prev--; + next++; + + if (prev != model.end()) { + Tip.setValue(*prev); + } else { + if (next != model.end()) + Tip.setValue(*next); + else + Tip.setValue(NULL); + } + } + + // Erase feature from Model + model.erase(it); + Model.setValues(model); +} + +App::DocumentObjectExecReturn *Body::execute(void) +{ const Part::TopoShape& TipShape = getTipShape(); if (TipShape._Shape.IsNull()) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 49f22d4bea3a..26391ba17de1 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -49,6 +49,8 @@ class Body : public Part::BodyBase /// recalculate the feature App::DocumentObjectExecReturn *execute(void); short mustExecute() const; + /// Just for debugging, remove when Body functionality is stable + void onChanged(const App::Property* prop); /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderBody"; @@ -59,28 +61,44 @@ class Body : public Part::BodyBase const Part::TopoShape getTipShape(); /** - * Return Tip feature if it is a solid. Otherwise, go backwards in the Model and - * find the first feature that is a solid (i.e. Sketches are skipped) - * This is used by SketchBased features to determine the shape they should fuse with or cut out off - * NOTE: Currently only PartDesign features are accepted as TipSolidFeatures + * Return the solid feature before the given feature, or before the Tip feature + * That is, sketches and datum features are skipped + * If inclusive is true, start or the Tip is returned if it is a solid feature */ - App::DocumentObject *getTipSolidFeature(); + App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true); /** - * Return the next solid feature after the Tip feature (so this only makes sense in insert mode) - * This is used by Sketchbased features in insert mode to re-route the Base property - * NOTE: Currently only PartDesign features are accepted as nextSolidFeatures + * Return the next solid feature after the given feature, or after the Tip feature + * That is, sketches and datum features are skipped + * If inclusive is true, start or the Tip is returned if it is a solid feature */ - App::DocumentObject *getNextSolidFeature(); + App::DocumentObject *getNextSolidFeature(App::DocumentObject* start = NULL, const bool inclusive = true); - /// Return the shape of the feature preceding this feature - const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); + // Return the shape of the feature preceding this feature + //const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); /// Return true if the feature belongs to this body const bool hasFeature(const App::DocumentObject *f); - /// Returns true if we are inserting into the feature tree instead of appending at the end - const bool insertMode(); + /// Return true if the feature is located after the current Tip feature + const bool isAfterTip(const App::DocumentObject *f); + + /// Insert the feature into the body at the current insert point (Tip feature) + void insertFeature(App::DocumentObject* feature); + + /// Remove the feature from the body + void removeFeature(App::DocumentObject* feature); + + + /** + * Return true if the given feature is a solid feature allowed in a Body. Currently this is only valid + * for features derived from PartDesign::Feature with the exception of PartDesign::Datum features + * Return false if the given feature is a Sketch or a PartDesign::Datum feature + */ + static const bool isSolidFeature(const App::DocumentObject* f); + + /// Return the body which this feature belongs too, or NULL + static Body* findBodyOf(const App::DocumentObject* f); PyObject *getPyObject(void); diff --git a/src/Mod/PartDesign/App/BodyPy.xml b/src/Mod/PartDesign/App/BodyPy.xml index ab251ac73e9e..2903e2a582a6 100644 --- a/src/Mod/PartDesign/App/BodyPy.xml +++ b/src/Mod/PartDesign/App/BodyPy.xml @@ -13,5 +13,15 @@ PartDesign body class + + + insertFeature(feat) - Insert the given feature after the current Tip feature + + + + + removeFeature(feat) - Remove the given feature from the Body + + diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp index aa592537ae56..cce3db236c99 100644 --- a/src/Mod/PartDesign/App/BodyPyImp.cpp +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -1,7 +1,9 @@ #include "PreCompiled.h" +#include "Mod/Part/App/Part2DObject.h" #include "Mod/PartDesign/App/Body.h" +#include "Mod/PartDesign/App/DatumFeature.h" // inclusion of the generated files (generated out of ItemPy.xml) #include "BodyPy.h" @@ -27,4 +29,48 @@ int BodyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) return 0; } +PyObject* BodyPy::insertFeature(PyObject *args) +{ + PyObject* featurePy; + if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) + return 0; + + Part::Feature* feature = static_cast(featurePy)->getFeaturePtr(); + + if (!feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) && + !feature->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { + PyErr_SetString(PyExc_SystemError, "Only PartDesign features and sketches can be inserted into a Body"); + return 0; + } + Body* body = this->getBodyPtr(); + + try { + body->insertFeature(feature); + } catch (Base::Exception& e) { + PyErr_SetString(PyExc_SystemError, e.what()); + return 0; + } + + Py_Return; +} + +PyObject* BodyPy::removeFeature(PyObject *args) +{ + PyObject* featurePy; + if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) + return 0; + + Part::Feature* feature = static_cast(featurePy)->getFeaturePtr(); + Body* body = this->getBodyPtr(); + + try { + body->removeFeature(feature); + } catch (Base::Exception& e) { + PyErr_SetString(PyExc_SystemError, e.what()); + return 0; + } + + Py_Return; +} + diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 4ae302fff97d..21c15d917eae 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -125,6 +126,7 @@ void CmdPartDesignBody::activated(int iMsg) // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); doCommand(Doc,"import PartDesignGui"); doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); // Make the "Create sketch" prompt appear in the task panel @@ -163,25 +165,30 @@ void CmdPartDesignMoveTip::activated(int iMsg) std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); if (features.empty()) return; - Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(pcActiveBody); - std::vector bodyChildren = vp->claimChildren(); + App::DocumentObject* selFeature = features.front(); + + if (!pcActiveBody->hasFeature(selFeature)) { + // Switch to other body + pcActiveBody = PartDesign::Body::findBodyOf(selFeature); + if (pcActiveBody != NULL) + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", + pcActiveBody->getNameInDocument()); + } - App::DocumentObject* tipFeature = pcActiveBody->Tip.getValue(); - const Gui::ViewProviderDocumentObject* vpFeature = dynamic_cast(Gui::Application::Instance->getViewProvider(tipFeature)); - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*vpFeature, Gui::Blue, false); + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if (prevSolidFeature != NULL) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); openCommand("Move insert point to selected feature"); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),features.front()->getNameInDocument()); - - // Adjust visibility - for (std::vector::const_iterator f = bodyChildren.begin(); f != bodyChildren.end(); f++) { - if ((*f) == pcActiveBody->Tip.getValue()) { - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); - vpFeature = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); - PartDesignGui::ActiveGuiDoc->signalHighlightObject(*vpFeature,Gui::Blue,true); - } else - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); - } + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); + + // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); + prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); } bool CmdPartDesignMoveTip::isActive(void) @@ -218,19 +225,22 @@ void CmdPartDesignNewSketch::activated(int iMsg) Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); - Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter1 ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); openCommand("Edit Sketch"); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); } - else if (FaceFilter.match() || PlaneFilter.match()) { + else if (FaceFilter.match() || PlaneFilter1.match() || PlaneFilter2.match()) { // get the selected object std::string supportString; if (FaceFilter.match()) { Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + // FIXME: Reject or warn about feature that is outside of active body, and feature + // that comes after the current insert point (Tip) const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); if (sub.size() > 1){ // No assert for wrong user input! @@ -258,32 +268,20 @@ void CmdPartDesignNewSketch::activated(int iMsg) supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); } else { - supportString = PlaneFilter.Result[0][0].getAsPropertyLinkSubString(); + if (PlaneFilter1.match()) + supportString = PlaneFilter1.Result[0][0].getAsPropertyLinkSubString(); + else + supportString = PlaneFilter2.Result[0][0].getAsPropertyLinkSubString(); } // create Sketch on Face std::string FeatName = getUniqueObjectName("Sketch"); - App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - if (nextSolidFeature != NULL) { - // Insert mode - doCommand(Doc,"m = App.activeDocument().%s.Model; " - "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" - "App.activeDocument().%s.Model = m", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str(), - pcActiveBody->getNameInDocument()); - } else { - doCommand(Doc,"App.activeDocument().%s.Model = " - "App.activeDocument().%s.Model + [App.activeDocument().%s]", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str()); - } - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", - pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -292,6 +290,8 @@ void CmdPartDesignNewSketch::activated(int iMsg) // Get a valid plane from the user std::vector status; std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + std::vector planestmp = getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId()); + planes.insert(planes.end(), planestmp.begin(), planestmp.end()); unsigned validPlanes = 0; std::vector::const_iterator firstValidPlane = planes.end(); @@ -316,6 +316,10 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (!body->hasFeature(*p)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; + } else { + if (body->isAfterTip(*p)) + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + continue; } // All checks passed - found a valid plane @@ -345,27 +349,14 @@ void CmdPartDesignNewSketch::activated(int iMsg) std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; - App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - if (nextSolidFeature != NULL) { - // Insert mode - doCommand(Doc,"m = App.activeDocument().%s.Model; " - "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" - "App.activeDocument().%s.Model = m", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str(), - pcActiveBody->getNameInDocument()); - } else { - doCommand(Doc,"App.activeDocument().%s.Model = " - "App.activeDocument().%s.Model + [App.activeDocument().%s]", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str()); - } - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } } @@ -447,8 +438,7 @@ bool CmdPartDesignNewSketch::isActive(void) return validSketches; } -void prepareSketchBased(Gui::Command* cmd, const std::string& which, - Part::Part2DObject*& sketch, std::string& FeatName, App::DocumentObject*& prevSolidFeature) +void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2DObject*& sketch, std::string& FeatName) { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (!pcActiveBody) return; @@ -481,43 +471,18 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, sketch = static_cast(*firstValidSketch); - // Find valid Body feature to set as the base feature - prevSolidFeature = pcActiveBody->getTipSolidFeature(); - App::DocumentObject* nextSolidFeature = pcActiveBody->getNextSolidFeature(); FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); - if (prevSolidFeature != NULL) - // Set BaseFeature property to previous feature - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", - FeatName.c_str(),prevSolidFeature->getNameInDocument()); - if (nextSolidFeature != NULL) { - // Insert mode - cmd->doCommand(cmd->Doc,"m = App.activeDocument().%s.Model; " - "m.insert(m.index(App.activeDocument().%s.Tip) + 1, App.activeDocument().%s);" - "App.activeDocument().%s.Model = m", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str(), - pcActiveBody->getNameInDocument()); - // Reroute BaseFeature property of the next feature to this feature - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", - nextSolidFeature->getNameInDocument(), FeatName.c_str()); - } else { - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = " - "App.activeDocument().%s.Model + [App.activeDocument().%s]", - pcActiveBody->getNameInDocument(), - pcActiveBody->getNameInDocument(),FeatName.c_str()); - } - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", - pcActiveBody->getNameInDocument(),FeatName.c_str()); - + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")", + which.c_str(), FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", - FeatName.c_str(),sketch->getNameInDocument()); + FeatName.c_str(), sketch->getNameInDocument()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); } -void finishSketchBased(const Gui::Command* cmd, - const Part::Part2DObject* sketch, const std::string& FeatName, const App::DocumentObject* prevSolidFeature) +void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { App::DocumentObjectGroup* grp = sketch->getGroup(); if (grp) { @@ -528,10 +493,14 @@ void finishSketchBased(const Gui::Command* cmd, } cmd->updateActive(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - if (prevSolidFeature != NULL) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + if (pcActiveBody != NULL) { + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); + if (prevSolidFeature != NULL) + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + } } // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer @@ -539,7 +508,6 @@ void finishSketchBased(const Gui::Command* cmd, cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); - PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (pcActiveBody) { cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); @@ -568,14 +536,13 @@ void CmdPartDesignPad::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Pad", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Pad", sketch, FeatName); if (FeatName.empty()) return; // specific parameters for Pad doCommand(Doc,"App.activeDocument().%s.Length = 10.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } @@ -605,13 +572,12 @@ void CmdPartDesignPocket::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Pocket", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Pocket", sketch, FeatName); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.Length = 5.0",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } @@ -641,8 +607,7 @@ void CmdPartDesignRevolution::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Revolution", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Revolution", sketch, FeatName); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -652,7 +617,7 @@ void CmdPartDesignRevolution::activated(int iMsg) if (pcRevolution && pcRevolution->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } @@ -682,8 +647,7 @@ void CmdPartDesignGroove::activated(int iMsg) { Part::Part2DObject* sketch; std::string FeatName; - App::DocumentObject* prevSolidFeature; - prepareSketchBased(this, "Groove", sketch, FeatName, prevSolidFeature); + prepareSketchBased(this, "Groove", sketch, FeatName); if (FeatName.empty()) return; doCommand(Doc,"App.activeDocument().%s.ReferenceAxis = (App.activeDocument().%s,['V_Axis'])", @@ -693,7 +657,7 @@ void CmdPartDesignGroove::activated(int iMsg) if (pcGroove && pcGroove->suggestReversed()) doCommand(Doc,"App.activeDocument().%s.Reversed = 1",FeatName.c_str()); - finishSketchBased(this, sketch, FeatName, prevSolidFeature); + finishSketchBased(this, sketch, FeatName); adjustCameraPosition(); } diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp index a2003b666c02..dc53a3f0c9d1 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp @@ -48,6 +48,7 @@ const QString FeaturePickDialog::getFeatureStatusString(const featureStatus st) case isUsed: return tr("Sketch already used by other feature"); case otherBody: return tr("Sketch belongs to another Body feature"); case basePlane: return tr("Base plane"); + case afterTip: return tr("Feature is located after the Tip feature"); } return tr(""); @@ -106,6 +107,7 @@ void FeaturePickDialog::updateList() case isUsed: item->setFlags(ui->checkOtherFeature->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; case otherBody: item->setFlags(ui->checkOtherBody->isChecked() ? Qt::ItemIsSelectable | Qt::ItemIsEnabled : Qt::NoItemFlags); break; case basePlane: item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); break; + case afterTip: item->setFlags(Qt::NoItemFlags); break; } index++; diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.h b/src/Mod/PartDesign/Gui/FeaturePickDialog.h index e70c0422924d..87f0140a66a0 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.h +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.h @@ -41,7 +41,8 @@ class FeaturePickDialog : public QDialog noWire, isUsed, otherBody, - basePlane + basePlane, + afterTip }; FeaturePickDialog(std::vector &objects, const std::vector &status); diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 6f16333e9950..076a11c85e49 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -27,8 +27,11 @@ #endif #include "ViewProvider.h" +#include "Workbench.h" +#include #include #include +#include #include using namespace PartDesignGui; @@ -69,3 +72,25 @@ void ViewProvider::updateData(const App::Property* prop) } inherited::updateData(prop); } + +bool ViewProvider::onDelete(const std::vector &) +{ + // Body feature housekeeping + PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); + if (body != NULL) { + body->removeFeature(getObject()); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = body->Tip.getValue(); + App::DocumentObject* prev = body->getPrevSolidFeature(); + Gui::Application::Instance->getViewProvider(tip)->show(); + if (tip != prev) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + + // TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support + // 1. Delete + // 2. Suppress + // 3. Re-route + + return true; +} diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 792b300df296..955910b2a6c2 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -41,6 +41,8 @@ class PartDesignGuiExport ViewProvider : public PartGui::ViewProviderPart { virtual bool doubleClicked(void); void updateData(const App::Property*); + + virtual bool onDelete(const std::vector &); }; From e184c9f22973c47717f4d7e613d73ae56a912b07 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 10 Apr 2013 17:42:46 +0430 Subject: [PATCH 074/664] More work on highlighting and hiding/showing --- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 40 +++++++++++++++++++ src/Mod/PartDesign/Gui/ViewProviderBody.h | 7 ++++ src/Mod/PartDesign/Gui/ViewProviderGroove.cpp | 15 +++---- src/Mod/PartDesign/Gui/ViewProviderPad.cpp | 22 +++++----- src/Mod/PartDesign/Gui/ViewProviderPocket.cpp | 17 +++----- .../PartDesign/Gui/ViewProviderRevolution.cpp | 17 +++----- 6 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 4d48ab309b20..b869008119db 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -28,7 +28,10 @@ #endif #include "ViewProviderBody.h" +#include "Workbench.h" #include +#include +#include #include #include #include @@ -139,3 +142,40 @@ std::vector ViewProviderBody::claimChildren3D(void)const return static_cast(getObject())->Model.getValues(); } + +void ViewProviderBody::updateTree() +{ + // Highlight active body and all its features + //Base::Console().Error("ViewProviderBody::updateTree()\n"); + PartDesign::Body* body = static_cast(getObject()); + bool active = body->IsActive.getValue(); + //Base::Console().Error("Body is %s\n", active ? "active" : "inactive"); + ActiveGuiDoc->signalHighlightObject(*this, Gui::Blue, active); + std::vector features = body->Model.getValues(); + bool highlight = true; + App::DocumentObject* tip = body->Tip.getValue(); + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + //Base::Console().Error("Highlighting %s: %s\n", (*f)->getNameInDocument(), highlight ? "true" : "false"); + Gui::ViewProviderDocumentObject* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); + ActiveGuiDoc->signalHighlightObject(*vp, Gui::LightBlue, active ? highlight : false); + if (highlight && (tip == *f)) + highlight = false; + } +} + +void ViewProviderBody::updateData(const App::Property* prop) +{ + //Base::Console().Error("ViewProviderBody::updateData for %s\n", getObject()->getNameInDocument()); + if (ActiveGuiDoc == NULL) + // PartDesign workbench not active + return PartGui::ViewProviderPart::updateData(prop); + + if (prop->getTypeId() == App::PropertyBool::getClassTypeId() && strcmp(prop->getName(),"IsActive") == 0) { + updateTree(); + } else if (prop->getTypeId() == App::PropertyLink::getClassTypeId() && strcmp(prop->getName(),"Tip") == 0) { + updateTree(); + } + // Note: The Model property only changes by itself (without the Tip also changing) if a feature is deleted somewhere + + PartGui::ViewProviderPart::updateData(prop); +} diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index 667baf7522a9..34aa9b5a2b70 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -57,12 +57,19 @@ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart virtual SoGroup* getChildRoot(void) const {return pcBodyChildren;} std::vector claimChildren3D(void)const; + /// Update the children's highlighting when triggered + void updateData(const App::Property* prop); + private: /// group used to store children collected by claimChildren3D() SoGroup *pcBodyChildren; /// group used to show the tip element in "edit" mode SoGroup *pcBodyTip; + /// Update the children's highlighting + void updateTree(); + + }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp index 1d210af009c3..fbe733e5c5c8 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp @@ -132,24 +132,19 @@ void ViewProviderGroove::unsetEdit(int ModNum) } } -bool ViewProviderGroove::onDelete(const std::vector &) +bool ViewProviderGroove::onDelete(const std::vector &s) { - // get the support and Sketch + // get the Sketch PartDesign::Groove* pcGroove = static_cast(getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; - if (pcGroove->Sketch.getValue()){ + if (pcGroove->Sketch.getValue()) pcSketch = static_cast(pcGroove->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); - } - // if abort command deleted the object the support is visible again + // if abort command deleted the object the Sketch is visible again if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - return true; + return ViewProvider::onDelete(s); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp index dc6c71a90028..0ff00ad0554d 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp @@ -31,6 +31,8 @@ #include "ViewProviderPad.h" #include "TaskPadParameters.h" +#include "Workbench.h" +#include #include #include #include @@ -125,23 +127,19 @@ void ViewProviderPad::unsetEdit(int ModNum) } } -bool ViewProviderPad::onDelete(const std::vector &) +bool ViewProviderPad::onDelete(const std::vector &s) { - // get the support and Sketch - PartDesign::Pad* pcPad = static_cast(getObject()); + PartDesign::Pad* pcPad = static_cast(getObject()); + + // get the Sketch Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; - if (pcPad->Sketch.getValue()){ - pcSketch = static_cast(pcPad->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); - } + if (pcPad->Sketch.getValue()) + pcSketch = static_cast(pcPad->Sketch.getValue()); - // if abort command deleted the object the support is visible again + // if abort command deleted the object the sketch is visible again if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - return true; + return ViewProvider::onDelete(s); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp index 7c8dbd19f47d..e21cf00bde9f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp @@ -122,24 +122,19 @@ void ViewProviderPocket::unsetEdit(int ModNum) } } -bool ViewProviderPocket::onDelete(const std::vector &) +bool ViewProviderPocket::onDelete(const std::vector &s) { - // get the support and Sketch + // get the Sketch PartDesign::Pocket* pcPocket = static_cast(getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; - if (pcPocket->Sketch.getValue()){ - pcSketch = static_cast(pcPocket->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); - } + if (pcPocket->Sketch.getValue()) + pcSketch = static_cast(pcPocket->Sketch.getValue()); - // if abort command deleted the object the support is visible again + // if abort command deleted the object the sketch is visible again if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - return true; + return ViewProvider::onDelete(s); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp index 0d27812d76b5..398f8aeae7e9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp @@ -132,24 +132,19 @@ void ViewProviderRevolution::unsetEdit(int ModNum) } } -bool ViewProviderRevolution::onDelete(const std::vector &) +bool ViewProviderRevolution::onDelete(const std::vector &s) { - // get the support and Sketch + // get the Sketch PartDesign::Revolution* pcRevolution = static_cast(getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; - if (pcRevolution->Sketch.getValue()){ - pcSketch = static_cast(pcRevolution->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); - } + if (pcRevolution->Sketch.getValue()) + pcSketch = static_cast(pcRevolution->Sketch.getValue()); - // if abort command deleted the object the support is visible again + // if abort command deleted the object the Sketch is visible again if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - return true; + return ViewProvider::onDelete(s); } From 3e4986f163d10c550d979af056bbe56f0de46055 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 10 Apr 2013 17:43:28 +0430 Subject: [PATCH 075/664] Add skeleton support for datum features --- src/Mod/PartDesign/App/CMakeLists.txt | 7 + src/Mod/PartDesign/App/DatumFeature.cpp | 189 ++++++++++++++++++++++++ src/Mod/PartDesign/App/DatumFeature.h | 109 ++++++++++++++ src/Mod/PartDesign/Gui/Workbench.cpp | 23 +-- src/Mod/PartDesign/Gui/Workbench.h | 2 - 5 files changed, 319 insertions(+), 11 deletions(-) create mode 100644 src/Mod/PartDesign/App/DatumFeature.cpp create mode 100644 src/Mod/PartDesign/App/DatumFeature.h diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index fce91a4760c5..725c2cc8a913 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -38,6 +38,12 @@ SET(Features_SRCS ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) +SET(DatumFeatures_SRCS + DatumFeature.cpp + DatumFeature.h +) +SOURCE_GROUP("DatumFeatures" FILES ${DatumFeatures_SRCS}) + SET(FeaturesTransformed_SRCS FeatureTransformed.h FeatureTransformed.cpp @@ -105,6 +111,7 @@ SOURCE_GROUP("Python" FILES ${Python_SRCS}) SET(PartDesign_SRCS ${Features_SRCS} + ${DatumFeatures_SRCS} ${FeaturesTransformed_SRCS} ${FeaturesSketchBased_SRCS} ${FeaturesDressUp_SRCS} diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp new file mode 100644 index 000000000000..9eb9fa89927f --- /dev/null +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + + +#include "DatumFeature.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +namespace PartDesign { + const App::PropertyFloatConstraint::Constraints angleRange = {0.0f,360.0f,1.0f}; +} + +using namespace PartDesign; + + +PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, PartDesign::Feature) + +Datum::Datum(void) +{ + ADD_PROPERTY_TYPE(References,(0,0),"Vertex",(App::PropertyType)(App::Prop_None),"References defining the vertex"); + touch(); +} + +Datum::~Datum() +{ +} + +short Datum::mustExecute(void) const +{ + if (References.isTouched()) + return 1; + return Feature::mustExecute(); +} + +void Datum::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + try { + App::DocumentObjectExecReturn *ret = recompute(); + delete ret; + } + catch (...) { + } + } + PartDesign::Feature::onChanged(prop); +} + +PROPERTY_SOURCE(PartDesign::Vertex, PartDesign::Datum) + +Vertex::Vertex() +{ +} + +Vertex::~Vertex() +{ +} + +short Vertex::mustExecute() const +{ + return PartDesign::Datum::mustExecute(); +} + +App::DocumentObjectExecReturn *Vertex::execute(void) +{ + gp_Pnt point(0,0,0); + // TODO: Find the point + + BRepBuilderAPI_MakeVertex MakeVertex(point); + const TopoDS_Vertex& vertex = MakeVertex.Vertex(); + this->Shape.setValue(vertex); + + return App::DocumentObject::StdReturn; +} + + +PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) + +Line::Line() +{ +} + +Line::~Line() +{ +} + +short Line::mustExecute() const +{ + return PartDesign::Datum::mustExecute(); +} + +App::DocumentObjectExecReturn *Line::execute(void) +{ + gp_Pnt point1(0,0,0); + + gp_Pnt point2(10,10,10); + + BRepBuilderAPI_MakeEdge mkEdge(point1, point2); + if (!mkEdge.IsDone()) + return new App::DocumentObjectExecReturn("Failed to create edge"); + const TopoDS_Edge& edge = mkEdge.Edge(); + this->Shape.setValue(edge); + + return App::DocumentObject::StdReturn; +} + + +PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) + +Plane::Plane() +{ + ADD_PROPERTY_TYPE(Offset,(10.0),"Plane",App::Prop_None,"The offset from the reference"); + ADD_PROPERTY_TYPE(Angle ,(0.0),"Plane",App::Prop_None,"The angle to the reference"); +} + +short Plane::mustExecute() const +{ + if (Offset.isTouched() || + Angle.isTouched() ) + return 1; + return PartDesign::Datum::mustExecute(); +} + +App::DocumentObjectExecReturn *Plane::execute(void) +{ + double O = this->Offset.getValue(); + double A = this->Angle.getValue(); + + if (fabs(A) > 360.0) + return new App::DocumentObjectExecReturn("Angle too large (please use -360.0 .. +360.0)"); + + gp_Pnt pnt(0.0,0.0,0.0); + gp_Dir dir(0.0,0.0,1.0); + Handle_Geom_Plane aPlane = new Geom_Plane(pnt, dir); + BRepBuilderAPI_MakeFace mkFace(aPlane, 0.0, 100.0, 0.0, 100.0 +#if OCC_VERSION_HEX >= 0x060502 + , Precision::Confusion() +#endif + ); + + TopoDS_Shape ResultShape = mkFace.Shape(); + this->Shape.setValue(ResultShape); + + return App::DocumentObject::StdReturn; +} diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h new file mode 100644 index 000000000000..6053abeae25b --- /dev/null +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -0,0 +1,109 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 PARTDESIGN_DATUMFEATURE_H +#define PARTDESIGN_DATUMFEATURE_H + +//#include +#include +#include "Feature.h" + +namespace PartDesign +{ + +class PartDesignExport Datum : public PartDesign::Feature +{ + PROPERTY_HEADER(PartDesign::Datum); + +public: + Datum(); + virtual ~Datum(); + + /// The references defining the datum object, e.g. three planes for a point, two planes for a line + App::PropertyLinkSubList References; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void) = 0; + short mustExecute() const; + //@} + +protected: + void onChanged (const App::Property* prop); +}; + +class PartDesignExport Vertex : public PartDesign::Datum +{ + PROPERTY_HEADER(PartDesign::Vertex); + +public: + Vertex(); + virtual ~Vertex(); + + /** @name methods override feature */ + //@{ + /// recalculate the Feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + //@} +}; + +class PartDesignExport Line : public PartDesign::Datum +{ + PROPERTY_HEADER(PartDesign::Line); + +public: + Line(); + virtual ~Line(); + + /** @name methods override feature */ + //@{ + /// recalculate the Feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + //@} +}; + +class PartDesignExport Plane : public PartDesign::Datum +{ + PROPERTY_HEADER(PartDesign::Plane); + +public: + Plane(); + + App::PropertyFloat Offset; + App::PropertyFloatConstraint Angle; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + //@} +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_DATUMFEATURE_H diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index d48ab0ddb340..5208ab97f668 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -84,7 +85,8 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con { if (strcmp(recipient,"Tree") == 0) { - if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) > 0 ) + if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveTip"; } } @@ -131,12 +133,21 @@ void Workbench::activated() "Part_Box" )); - const char* Plane[] = { + const char* Plane1[] = { "PartDesign_NewSketch", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT App::Plane COUNT 1", - Plane, + Plane1, + "Start Part", + "Part_Box" + )); + const char* Plane2[] = { + "PartDesign_NewSketch", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::Plane COUNT 1", + Plane2, "Start Part", "Part_Box" )); @@ -225,12 +236,6 @@ void Workbench::activated() void Workbench::deactivated() { removeTaskWatcher(); - // remember the body for later activation - // TODO: Remove this if the IsActive Property of Body works OK - if(PartDesignGui::ActivePartObject) - oldActive = PartDesignGui::ActivePartObject->getNameInDocument(); - else - oldActive = ""; // reset the active Body Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(None)"); diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 0b042a91df68..c2e3d0f28559 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -74,8 +74,6 @@ class PartDesignGuiExport Workbench : public Gui::StdWorkbench Gui::MenuItem* setupMenuBar() const; Gui::ToolBarItem* setupToolBars() const; Gui::ToolBarItem* setupCommandBars() const; - - std::string oldActive; }; } // namespace PartDesignGui From ee47c53339738dc53c19ccd552c61a001bc3df92 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 11 Apr 2013 19:46:53 +0430 Subject: [PATCH 076/664] Bug fixes for Body feature insert/remove functionality --- src/Mod/PartDesign/App/Body.cpp | 22 +++++++++++-------- .../PartDesign/Gui/TaskGrooveParameters.cpp | 16 +++++++++++++- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 15 +++++++++++++ .../PartDesign/Gui/TaskPocketParameters.cpp | 15 +++++++++++++ .../Gui/TaskRevolutionParameters.cpp | 15 +++++++++++++ src/Mod/PartDesign/Gui/ViewProvider.cpp | 8 ++++--- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 3 ++- 7 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 6c58a58f41a1..5d80d34d052b 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -257,16 +257,20 @@ void Body::removeFeature(App::DocumentObject* feature) if (tipFeature == feature) { // Set the Tip to the previous feature if possible, otherwise to the next feature std::vector::const_iterator prev = it, next = it; - prev--; - next++; - - if (prev != model.end()) { - Tip.setValue(*prev); + if (it != model.begin()) { + prev--; + next++; + + if (prev != model.end()) { + Tip.setValue(*prev); + } else { + if (next != model.end()) + Tip.setValue(*next); + else + Tip.setValue(NULL); + } } else { - if (next != model.end()) - Tip.setValue(*next); - else - Tip.setValue(NULL); + Tip.setValue(NULL); } } diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index 30f30b12182e..50699fb465d1 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -41,7 +41,8 @@ #include #include #include - +#include +#include "Workbench.h" using namespace PartDesignGui; using namespace Gui; @@ -336,6 +337,19 @@ bool TaskDlgGrooveParameters::reject() pcSupport = pcSketch->Support.getValue(); } + // Body housekeeping + if (ActivePartObject != NULL) { + ActivePartObject->removeFeature(pcGroove); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + // role back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 39641b39a17f..dd00f657b0ec 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -45,7 +45,9 @@ #include #include #include +#include #include "ReferenceSelection.h" +#include "Workbench.h" using namespace PartDesignGui; using namespace Gui; @@ -553,6 +555,19 @@ bool TaskDlgPadParameters::reject() pcSketch = static_cast(pcPad->Sketch.getValue()); } + // Body housekeeping + if (ActivePartObject != NULL) { + ActivePartObject->removeFeature(pcPad); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + // roll back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 2a273edd46c4..8163f8dfbd07 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -46,7 +46,9 @@ #include #include #include +#include #include "ReferenceSelection.h" +#include "Workbench.h" using namespace PartDesignGui; using namespace Gui; @@ -499,6 +501,19 @@ bool TaskDlgPocketParameters::reject() pcSupport = pcSketch->Support.getValue(); } + // Body housekeeping + if (ActivePartObject != NULL) { + ActivePartObject->removeFeature(pcPocket); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + // roll back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 911a071f9edc..3454ab93b0e8 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include "Workbench.h" using namespace PartDesignGui; @@ -336,6 +338,19 @@ bool TaskDlgRevolutionParameters::reject() pcSupport = pcSketch->Support.getValue(); } + // Body housekeeping + if (ActivePartObject != NULL) { + ActivePartObject->removeFeature(pcRevolution); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + // role back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 076a11c85e49..7dc15728e1cc 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -82,9 +82,11 @@ bool ViewProvider::onDelete(const std::vector &) // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = body->Tip.getValue(); App::DocumentObject* prev = body->getPrevSolidFeature(); - Gui::Application::Instance->getViewProvider(tip)->show(); - if (tip != prev) - Gui::Application::Instance->getViewProvider(prev)->show(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } } // TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index b869008119db..f7629efb5a0c 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -157,7 +157,8 @@ void ViewProviderBody::updateTree() for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { //Base::Console().Error("Highlighting %s: %s\n", (*f)->getNameInDocument(), highlight ? "true" : "false"); Gui::ViewProviderDocumentObject* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); - ActiveGuiDoc->signalHighlightObject(*vp, Gui::LightBlue, active ? highlight : false); + if (vp != NULL) + ActiveGuiDoc->signalHighlightObject(*vp, Gui::LightBlue, active ? highlight : false); if (highlight && (tip == *f)) highlight = false; } From 63f782d8f081f8ed1ba0e6d1b1f47117e438dfb3 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 12 Apr 2013 16:16:34 +0430 Subject: [PATCH 077/664] More bug fixes for Body insertion/deletion of features --- src/Mod/PartDesign/App/Body.cpp | 83 +++++++++++++++---- src/Mod/PartDesign/App/Body.h | 11 ++- src/Mod/PartDesign/App/BodyPy.xml | 4 +- src/Mod/PartDesign/App/BodyPyImp.cpp | 4 +- src/Mod/PartDesign/Gui/Command.cpp | 6 +- .../PartDesign/Gui/TaskGrooveParameters.cpp | 28 +++---- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 21 +++-- .../PartDesign/Gui/TaskPocketParameters.cpp | 30 +++---- .../Gui/TaskRevolutionParameters.cpp | 28 +++---- 9 files changed, 121 insertions(+), 94 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 5d80d34d052b..9278ef825672 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -50,25 +50,55 @@ Body::Body() ADD_PROPERTY(IsActive,(0)); } +/* +// Note: The following code will catch Python Document::removeObject() modifications. If the object removed is +// a member of the Body::Model, then it will be automatically removed from the Model property which triggers the +// following two methods +// But since we require the Python user to call both Document::addObject() and Body::addFeature(), we should +// also require calling both Document::removeObject and Body::removeFeature() in order to be consistent +void Body::onBeforeChange(const App::Property *prop) +{ + // Remember the feature before the current Tip. If the Tip is already at the first feature, remember the next feature + if (prop == &Model) { + std::vector features = Model.getValues(); + if (features.empty()) { + rememberTip = NULL; + } else { + std::vector::iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + if (it == features.begin()) { + it++; + if (it == features.end()) + rememberTip = NULL; + else + rememberTip = *it; + } else { + it--; + rememberTip = *it; + } + } + } + + return Part::Feature::onBeforeChange(prop); +} + void Body::onChanged(const App::Property *prop) { - Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); - App::DocumentObject* tip = Tip.getValue(); - Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); - std::vector model = Model.getValues(); - Base::Console().Error(" Model:\n"); - for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { - Base::Console().Error(" %s", (*m)->getNameInDocument()); - if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { - App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); - Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); + if (prop == &Model) { + std::vector features = Model.getValues(); + if (features.empty()) { + Tip.setValue(NULL); } else { - Base::Console().Error("\n"); + std::vector::iterator it = std::find(features.begin(), features.end(), Tip.getValue()); + if (it == features.end()) { + // Tip feature was deleted + Tip.setValue(rememberTip); + } } } return Part::Feature::onChanged(prop); } +*/ short Body::mustExecute() const { @@ -189,7 +219,7 @@ Body* Body::findBodyOf(const App::DocumentObject* f) return NULL; } -void Body::insertFeature(App::DocumentObject *feature) +void Body::addFeature(App::DocumentObject *feature) { // Set the BaseFeature property // Note: This is not strictly necessary for Datum features @@ -236,6 +266,8 @@ void Body::insertFeature(App::DocumentObject *feature) void Body::removeFeature(App::DocumentObject* feature) { + // This method must be called BEFORE the feature is removed from the Document! + if (isSolidFeature(feature)) { // This is a solid feature // If the next feature is solid, reroute its BaseFeature property to the previous solid feature @@ -250,10 +282,11 @@ void Body::removeFeature(App::DocumentObject* feature) } } - // Adjust Tip feature if it is pointing to the deleted object - App::DocumentObject* tipFeature = Tip.getValue(); std::vector model = Model.getValues(); std::vector::iterator it = std::find(model.begin(), model.end(), feature); + + // Adjust Tip feature if it is pointing to the deleted object + App::DocumentObject* tipFeature = Tip.getValue(); if (tipFeature == feature) { // Set the Tip to the previous feature if possible, otherwise to the next feature std::vector::const_iterator prev = it, next = it; @@ -270,7 +303,11 @@ void Body::removeFeature(App::DocumentObject* feature) Tip.setValue(NULL); } } else { - Tip.setValue(NULL); + next++; + if (next != model.end()) + Tip.setValue(*next); + else + Tip.setValue(NULL); } } @@ -281,6 +318,22 @@ void Body::removeFeature(App::DocumentObject* feature) App::DocumentObjectExecReturn *Body::execute(void) { + Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); + App::DocumentObject* tip = Tip.getValue(); + Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); + std::vector model = Model.getValues(); + Base::Console().Error(" Model:\n"); + for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { + if (*m == NULL) continue; + Base::Console().Error(" %s", (*m)->getNameInDocument()); + if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { + App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); + Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); + } else { + Base::Console().Error("\n"); + } + } + const Part::TopoShape& TipShape = getTipShape(); if (TipShape._Shape.IsNull()) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 26391ba17de1..763fe6ef17ba 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -48,9 +48,7 @@ class Body : public Part::BodyBase //@{ /// recalculate the feature App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// Just for debugging, remove when Body functionality is stable - void onChanged(const App::Property* prop); + short mustExecute() const; /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderBody"; @@ -83,8 +81,8 @@ class Body : public Part::BodyBase /// Return true if the feature is located after the current Tip feature const bool isAfterTip(const App::DocumentObject *f); - /// Insert the feature into the body at the current insert point (Tip feature) - void insertFeature(App::DocumentObject* feature); + /// Add the feature into the body at the current insert point (Tip feature) + void addFeature(App::DocumentObject* feature); /// Remove the feature from the body void removeFeature(App::DocumentObject* feature); @@ -102,7 +100,8 @@ class Body : public Part::BodyBase PyObject *getPyObject(void); - +private: + App::DocumentObject* rememberTip; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/BodyPy.xml b/src/Mod/PartDesign/App/BodyPy.xml index 2903e2a582a6..9d86dd0cb5ba 100644 --- a/src/Mod/PartDesign/App/BodyPy.xml +++ b/src/Mod/PartDesign/App/BodyPy.xml @@ -13,9 +13,9 @@ PartDesign body class - + - insertFeature(feat) - Insert the given feature after the current Tip feature + addFeature(feat) - Add the given feature after the current Tip feature diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp index cce3db236c99..8bc88ca600a7 100644 --- a/src/Mod/PartDesign/App/BodyPyImp.cpp +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -29,7 +29,7 @@ int BodyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) return 0; } -PyObject* BodyPy::insertFeature(PyObject *args) +PyObject* BodyPy::addFeature(PyObject *args) { PyObject* featurePy; if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) @@ -45,7 +45,7 @@ PyObject* BodyPy::insertFeature(PyObject *args) Body* body = this->getBodyPtr(); try { - body->insertFeature(feature); + body->addFeature(feature); } catch (Base::Exception& e) { PyErr_SetString(PyExc_SystemError, e.what()); return 0; diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 21c15d917eae..f7246ceabf75 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -280,7 +280,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) openCommand("Create a Sketch on Face"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); @@ -354,7 +354,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); @@ -478,7 +478,7 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2 which.c_str(), FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", FeatName.c_str(), sketch->getNameInDocument()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.insertFeature(App.activeDocument().%s)", + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); } diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index 50699fb465d1..38f9eabe212b 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -331,15 +331,22 @@ bool TaskDlgGrooveParameters::reject() // get the support and Sketch PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcGroove->Sketch.getValue()) { pcSketch = static_cast(pcGroove->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); + } + + // role back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the support is visible again + if (!Gui::Application::Instance->getViewProvider(pcGroove)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); } // Body housekeeping if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcGroove); // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = ActivePartObject->Tip.getValue(); App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); @@ -350,21 +357,6 @@ bool TaskDlgGrooveParameters::reject() } } - // role back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcGroove)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - } - - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); - return true; } diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index dd00f657b0ec..b19314705532 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -553,11 +553,20 @@ bool TaskDlgPadParameters::reject() Sketcher::SketchObject *pcSketch = 0; if (pcPad->Sketch.getValue()) { pcSketch = static_cast(pcPad->Sketch.getValue()); + } + + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the support is visible again + if (!Gui::Application::Instance->getViewProvider(pcPad)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); } // Body housekeeping if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcPad); // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = ActivePartObject->Tip.getValue(); App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); @@ -568,16 +577,6 @@ bool TaskDlgPadParameters::reject() } } - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcPad)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - } - return true; } diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 8163f8dfbd07..4e9bce7f8017 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -495,15 +495,22 @@ bool TaskDlgPocketParameters::reject() // get the support and Sketch PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcPocket->Sketch.getValue()) { - pcSketch = static_cast(pcPocket->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); + pcSketch = static_cast(pcPocket->Sketch.getValue()); + } + + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the sketch is visible again + if (!Gui::Application::Instance->getViewProvider(pcPocket)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); } // Body housekeeping if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcPocket); // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = ActivePartObject->Tip.getValue(); App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); @@ -514,21 +521,6 @@ bool TaskDlgPocketParameters::reject() } } - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcPocket)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - } - - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); - return true; } diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 3454ab93b0e8..838a1c0375ba 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -332,15 +332,22 @@ bool TaskDlgRevolutionParameters::reject() // get the support and Sketch PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); Sketcher::SketchObject *pcSketch = 0; - App::DocumentObject *pcSupport = 0; if (pcRevolution->Sketch.getValue()) { pcSketch = static_cast(pcRevolution->Sketch.getValue()); - pcSupport = pcSketch->Support.getValue(); + } + + // role back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the support is visible again + if (!Gui::Application::Instance->getViewProvider(pcRevolution)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); } // Body housekeeping if (ActivePartObject != NULL) { - ActivePartObject->removeFeature(pcRevolution); // Make the new Tip and the previous solid feature visible again App::DocumentObject* tip = ActivePartObject->Tip.getValue(); App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); @@ -351,21 +358,6 @@ bool TaskDlgRevolutionParameters::reject() } } - // role back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcRevolution)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - } - - //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - //Gui::Command::commitCommand(); - return true; } From 3b81168e41f87165387fa03ed69a9dc548fe6a32 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 12 Apr 2013 16:24:08 +0430 Subject: [PATCH 078/664] Second step for implementing datum features --- src/Mod/PartDesign/App/AppPartDesign.cpp | 7 +- src/Mod/PartDesign/App/AppPartDesign.cpp.orig | 113 ++++ src/Mod/PartDesign/App/DatumFeature.cpp | 39 +- src/Mod/PartDesign/App/DatumFeature.h | 17 +- src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 2 + src/Mod/PartDesign/Gui/CMakeLists.txt | 7 + src/Mod/PartDesign/Gui/Command.cpp | 266 ++++++++- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 3 + src/Mod/PartDesign/Gui/ReferenceSelection.h | 5 +- .../PartDesign/Gui/TaskDatumParameters.cpp | 503 ++++++++++++++++++ src/Mod/PartDesign/Gui/TaskDatumParameters.h | 124 +++++ src/Mod/PartDesign/Gui/TaskDatumParameters.ui | 97 ++++ src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 118 ++++ src/Mod/PartDesign/Gui/ViewProviderDatum.h | 59 ++ src/Mod/PartDesign/Gui/Workbench.cpp | 57 +- 15 files changed, 1376 insertions(+), 41 deletions(-) create mode 100644 src/Mod/PartDesign/App/AppPartDesign.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/TaskDatumParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskDatumParameters.h create mode 100644 src/Mod/PartDesign/Gui/TaskDatumParameters.ui create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatum.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatum.h diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index dbd6b0dbdfcf..0922ad5eacc9 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -49,6 +49,7 @@ #include "FeatureScaled.h" #include "FeatureMultiTransform.h" #include "FeatureHole.h" +#include "DatumFeature.h" namespace PartDesign { extern PyObject* initModule(); @@ -95,5 +96,9 @@ PyMODINIT_FUNC init_PartDesign() PartDesign::Revolution ::init(); PartDesign::Groove ::init(); PartDesign::Chamfer ::init(); - PartDesign::Draft ::init(); + PartDesign::Draft ::init(); + PartDesign::Datum ::init(); + PartDesign::Plane ::init(); + PartDesign::Line ::init(); + PartDesign::Point ::init(); } diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp.orig b/src/Mod/PartDesign/App/AppPartDesign.cpp.orig new file mode 100644 index 000000000000..b18162c07adf --- /dev/null +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp.orig @@ -0,0 +1,113 @@ +/*************************************************************************** + * Copyright (c) 2008 Jürgen Riegel (juergen.riegel@web.de) * + * * + * 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 +#endif + +#include +#include + +#include "FeaturePad.h" +#include "FeatureSolid.h" +#include "FeaturePocket.h" +#include "FeatureFillet.h" +#include "FeatureSketchBased.h" +#include "FeatureRevolution.h" +#include "FeatureGroove.h" +#include "Body.h" +#include "FeatureDressUp.h" +#include "FeatureChamfer.h" +#include "FeatureDraft.h" +#include "FeatureSubtractive.h" +#include "FeatureAdditive.h" +#include "FeatureTransformed.h" +#include "FeatureMirrored.h" +#include "FeatureLinearPattern.h" +#include "FeaturePolarPattern.h" +#include "FeatureScaled.h" +#include "FeatureMultiTransform.h" +#include "FeatureHole.h" +#include "DatumFeature.h" + +extern struct PyMethodDef PartDesign_methods[]; + +PyDoc_STRVAR(module_PartDesign_doc, +"This module is the PartDesign module."); + + +/* Python entry */ +extern "C" { +void PartDesignExport init_PartDesign() +{ + // load dependent module + try { + Base::Interpreter().runString("import Part"); + Base::Interpreter().runString("import Sketcher"); + } + catch(const Base::Exception& e) { + PyErr_SetString(PyExc_ImportError, e.what()); + return; + } + Py_InitModule3("_PartDesign", PartDesign_methods, module_PartDesign_doc); /* mod name, table ptr */ + Base::Console().Log("Loading PartDesign module... done\n"); + + + // NOTE: To finish the initialization of our own type objects we must + // call PyType_Ready, otherwise we run into a segmentation fault, later on. + // This function is responsible for adding inherited slots from a type's base class. + + PartDesign::Feature ::init(); + PartDesign::Solid ::init(); + PartDesign::DressUp ::init(); + PartDesign::SketchBased ::init(); + PartDesign::Subtractive ::init(); + PartDesign::Additive ::init(); + PartDesign::Transformed ::init(); + PartDesign::Mirrored ::init(); + PartDesign::LinearPattern ::init(); + PartDesign::PolarPattern ::init(); + PartDesign::Scaled ::init(); + PartDesign::MultiTransform ::init(); + PartDesign::Hole ::init(); + PartDesign::Body ::init(); + PartDesign::Pad ::init(); + PartDesign::Pocket ::init(); + PartDesign::Fillet ::init(); + PartDesign::Revolution ::init(); + PartDesign::Groove ::init(); + PartDesign::Chamfer ::init(); +<<<<<<< b1f11745d3f535813e5dea41f7a12b14fbd6389f + PartDesign::Draft ::init(); +======= + PartDesign::Face ::init(); + PartDesign::Draft ::init(); + PartDesign::Datum ::init(); + PartDesign::Plane ::init(); + PartDesign::Line ::init(); + PartDesign::Point ::init(); +>>>>>>> Second step for implementing datum features +} + +} // extern "C" diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp index 9eb9fa89927f..0d4148f59d9d 100644 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -50,11 +50,6 @@ #define M_PI 3.14159265358979323846 #endif - -namespace PartDesign { - const App::PropertyFloatConstraint::Constraints angleRange = {0.0f,360.0f,1.0f}; -} - using namespace PartDesign; @@ -62,7 +57,8 @@ PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, PartDesign::Feature) Datum::Datum(void) { - ADD_PROPERTY_TYPE(References,(0,0),"Vertex",(App::PropertyType)(App::Prop_None),"References defining the vertex"); + ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); + ADD_PROPERTY(Values,(0.0)); touch(); } @@ -72,40 +68,34 @@ Datum::~Datum() short Datum::mustExecute(void) const { - if (References.isTouched()) + if (References.isTouched() || + Values.isTouched()) return 1; return Feature::mustExecute(); } void Datum::onChanged(const App::Property* prop) { - if (!isRestoring()) { - try { - App::DocumentObjectExecReturn *ret = recompute(); - delete ret; - } - catch (...) { - } - } + PartDesign::Feature::onChanged(prop); } -PROPERTY_SOURCE(PartDesign::Vertex, PartDesign::Datum) +PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) -Vertex::Vertex() +Point::Point() { } -Vertex::~Vertex() +Point::~Point() { } -short Vertex::mustExecute() const +short Point::mustExecute() const { return PartDesign::Datum::mustExecute(); } -App::DocumentObjectExecReturn *Vertex::execute(void) +App::DocumentObjectExecReturn *Point::execute(void) { gp_Pnt point(0,0,0); // TODO: Find the point @@ -153,22 +143,17 @@ PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) Plane::Plane() { - ADD_PROPERTY_TYPE(Offset,(10.0),"Plane",App::Prop_None,"The offset from the reference"); - ADD_PROPERTY_TYPE(Angle ,(0.0),"Plane",App::Prop_None,"The angle to the reference"); } short Plane::mustExecute() const { - if (Offset.isTouched() || - Angle.isTouched() ) - return 1; return PartDesign::Datum::mustExecute(); } App::DocumentObjectExecReturn *Plane::execute(void) { - double O = this->Offset.getValue(); - double A = this->Angle.getValue(); + double O = 10.0; //this->Offset.getValue(); + double A = 45.0; //this->Angle.getValue(); if (fabs(A) > 360.0) return new App::DocumentObjectExecReturn("Angle too large (please use -360.0 .. +360.0)"); diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index 6053abeae25b..e0c26a62c4f3 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -41,25 +41,31 @@ class PartDesignExport Datum : public PartDesign::Feature /// The references defining the datum object, e.g. three planes for a point, two planes for a line App::PropertyLinkSubList References; + /// The values defining the datum object, e.g. the offset from a Reference plane + App::PropertyFloatList Values; /** @name methods override feature */ //@{ /// recalculate the feature App::DocumentObjectExecReturn *execute(void) = 0; short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatum"; + } //@} protected: void onChanged (const App::Property* prop); }; -class PartDesignExport Vertex : public PartDesign::Datum +class PartDesignExport Point : public PartDesign::Datum { - PROPERTY_HEADER(PartDesign::Vertex); + PROPERTY_HEADER(PartDesign::Point); public: - Vertex(); - virtual ~Vertex(); + Point(); + virtual ~Point(); /** @name methods override feature */ //@{ @@ -92,9 +98,6 @@ class PartDesignExport Plane : public PartDesign::Datum public: Plane(); - App::PropertyFloat Offset; - App::PropertyFloatConstraint Angle; - /** @name methods override feature */ //@{ /// recalculate the feature diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index af942d95f491..bec1ad5d8da4 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -48,6 +48,7 @@ #include "ViewProviderPolarPattern.h" #include "ViewProviderScaled.h" #include "ViewProviderMultiTransform.h" +#include "ViewProviderDatum.h" // use a different name to CreateCommand() void CreatePartDesignCommands(void); @@ -119,6 +120,7 @@ PyMODINIT_FUNC initPartDesignGui() PartDesignGui::ViewProviderPolarPattern ::init(); PartDesignGui::ViewProviderScaled ::init(); PartDesignGui::ViewProviderMultiTransform::init(); + PartDesignGui::ViewProviderDatum ::init(); // add resources and reloads the translators loadPartDesignResource(); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index bb951f6cc523..f3a67b09b9f3 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -44,6 +44,7 @@ set(PartDesignGui_MOC_HDRS TaskPolarPatternParameters.h TaskScaledParameters.h TaskMultiTransformParameters.h + TaskDatumParameters.h ) fc_wrap_cpp(PartDesignGui_MOC_SRCS ${PartDesignGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartDesignGui_MOC_SRCS}) @@ -66,6 +67,7 @@ set(PartDesignGui_UIC_SRCS TaskPolarPatternParameters.ui TaskScaledParameters.ui TaskMultiTransformParameters.ui + TaskDatumParameters.ui ) qt4_wrap_ui(PartDesignGui_UIC_HDRS ${PartDesignGui_UIC_SRCS}) @@ -102,6 +104,8 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderScaled.h ViewProviderMultiTransform.cpp ViewProviderMultiTransform.h + ViewProviderDatum.cpp + ViewProviderDatum.h ) SOURCE_GROUP("ViewProvider" FILES ${PartDesignGuiViewProvider_SRCS}) @@ -155,6 +159,9 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskHoleParameters.ui TaskHoleParameters.cpp TaskHoleParameters.h + TaskDatumParameters.ui + TaskDatumParameters.cpp + TaskDatumParameters.h ) SOURCE_GROUP("TaskDialogs" FILES ${PartDesignGuiTaskDlgs_SRCS}) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index f7246ceabf75..9c9fbc4e065d 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -196,6 +196,263 @@ bool CmdPartDesignMoveTip::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_Datum +//=========================================================================== + +const QString getReferenceString(Gui::Command* cmd) +{ + QString referenceString; + + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return QString::fromAscii(""); + + Gui::SelectionFilter GeometryFilter("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter EdgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1"); + Gui::SelectionFilter VertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 1"); + Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); + + if (EdgeFilter.match()) + GeometryFilter = EdgeFilter; + else if (VertexFilter.match()) + GeometryFilter = VertexFilter; + if (PlaneFilter2.match()) + PlaneFilter = PlaneFilter2; + + if (GeometryFilter.match() || PlaneFilter.match()) { + // get the selected object + if (GeometryFilter.match()) { + Part::Feature *part = static_cast(GeometryFilter.Result[0][0].getObject()); + // FIXME: Reject or warn about feature that is outside of active body, and feature + // that comes after the current insert point (Tip) + const std::vector &sub = GeometryFilter.Result[0][0].getSubNames(); + referenceString = QString::fromAscii("["); + + for (int r = 0; r != sub.size(); r++) { + // get the selected sub shape + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[r].c_str()); + if (sh.IsNull()) { + referenceString += QString::fromAscii(r == 0 ? "" : ",") + + QString::fromAscii("(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + + QString::fromAscii(",") + QString::fromStdString(sub[r]) + QString::fromAscii(")"); + } + } + + referenceString += QString::fromAscii("]"); + if (referenceString.length() == 2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No sub shape selected"), + QObject::tr("You have to select a face, edge, vertex or plane to define a datum feature!")); + return QString::fromAscii(""); + } + + return referenceString; + } else { + Part::Feature *part = static_cast(PlaneFilter.Result[0][0].getObject()); + return QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + + QString::fromAscii(",'')]"); + } + } + else { + // Get a valid datum feature from the user + std::vector status; + std::vector refs = cmd->getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + std::vector refstmp = cmd->getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId()); + refs.insert(refs.end(), refstmp.begin(), refstmp.end()); + refstmp = cmd->getDocument()->getObjectsOfType(PartDesign::Line::getClassTypeId()); + refs.insert(refs.end(), refstmp.begin(), refstmp.end()); + refstmp = cmd->getDocument()->getObjectsOfType(PartDesign::Point::getClassTypeId()); + refs.insert(refs.end(), refstmp.begin(), refstmp.end()); + + unsigned validRefs = 0; + std::vector chosenRefs; + + for (std::vector::iterator r = refs.begin(); r != refs.end(); r++) { + // Check whether this reference is a base plane + bool base = false; + for (unsigned i = 0; i < 3; i++) { + if (strcmp(BasePlaneNames[i], (*r)->getNameInDocument()) == 0) { + status.push_back(PartDesignGui::FeaturePickDialog::basePlane); + if (chosenRefs.empty()) + chosenRefs.push_back(*r); + validRefs++; + base = true; + break; + } + } + if (base) continue; + + // Check whether this reference belongs to the active body + PartDesign::Body* body = PartDesignGui::getBody(); + if (!body->hasFeature(*r)) { + status.push_back(PartDesignGui::FeaturePickDialog::otherBody); + continue; + } else { + if (body->isAfterTip(*r)) + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + continue; + } + + // All checks passed - found a valid reference + if (chosenRefs.empty()) + chosenRefs.push_back(*r); + validRefs++; + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); + } + + if (validRefs == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid references in this document"), + QObject::tr("Please select a face, edge or vertex")); + return QString::fromAscii(""); + } + + // If there is more than one possibility, show dialog and let user pick references + if (validRefs > 1) { + PartDesignGui::FeaturePickDialog Dlg(refs, status); + if ((Dlg.exec() != QDialog::Accepted) || (chosenRefs = Dlg.getFeatures()).empty()) + return QString::fromAscii(""); // Cancelled or nothing selected + if (chosenRefs.size() > 3) + Base::Console().Warning("You have chosen more than three references for a datum feature. The extra references are being ignored"); + } + + referenceString = QString::fromAscii("["); + for (int i = 0; i < chosenRefs.size(); i++) { + referenceString += QString::fromAscii(i == 0 ? "" : ",") + + QString::fromAscii("(App.activeDocument().") + QString::fromUtf8(chosenRefs[i]->getNameInDocument()) + + QString::fromAscii(",'')"); + } + + referenceString += QString::fromAscii("]"); + return referenceString; + } +} + +/* Datum feature commands =======================================================*/ + +DEF_STD_CMD_A(CmdPartDesignPlane); + +CmdPartDesignPlane::CmdPartDesignPlane() + :Command("PartDesign_Plane") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a datum plane"); + sToolTipText = QT_TR_NOOP("Create a new datum plane"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Plane"; +} + +void CmdPartDesignPlane::activated(int iMsg) +{ + // create Datum plane + std::string FeatName = getUniqueObjectName("DatumPlane"); + QString refStr = getReferenceString(this); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + openCommand("Create a datum plane"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",FeatName.c_str()); + if (refStr.length() > 0) + doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + +} + +bool CmdPartDesignPlane::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +DEF_STD_CMD_A(CmdPartDesignLine); + +CmdPartDesignLine::CmdPartDesignLine() + :Command("PartDesign_Line") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a datum line"); + sToolTipText = QT_TR_NOOP("Create a new datum line"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Line"; +} + +void CmdPartDesignLine::activated(int iMsg) +{ + // create Datum line + std::string FeatName = getUniqueObjectName("DatumLine"); + QString refStr = getReferenceString(this); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + openCommand("Create a datum line"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Line','%s')",FeatName.c_str()); + if (refStr.length() > 0) + doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + +} + +bool CmdPartDesignLine::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +DEF_STD_CMD_A(CmdPartDesignPoint); + +CmdPartDesignPoint::CmdPartDesignPoint() + :Command("PartDesign_Point") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a datum point"); + sToolTipText = QT_TR_NOOP("Create a new datum point"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Point"; +} + +void CmdPartDesignPoint::activated(int iMsg) +{ + // create Datum point + std::string FeatName = getUniqueObjectName("DatumPoint"); + QString refStr = getReferenceString(this); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + openCommand("Create a datum plane"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Point','%s')",FeatName.c_str()); + if (refStr.length() > 0) + doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + +} + +bool CmdPartDesignPoint::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -1396,18 +1653,21 @@ void CreatePartDesignCommands(void) Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdPartDesignBody()); + rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); + rcCmdMgr.addCommand(new CmdPartDesignPlane()); + rcCmdMgr.addCommand(new CmdPartDesignLine()); + rcCmdMgr.addCommand(new CmdPartDesignPoint()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); rcCmdMgr.addCommand(new CmdPartDesignGroove()); rcCmdMgr.addCommand(new CmdPartDesignFillet()); - rcCmdMgr.addCommand(new CmdPartDesignDraft()); - rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignDraft()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); rcCmdMgr.addCommand(new CmdPartDesignMirrored()); rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); - rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); } diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index f2bfcd42e093..93880e81e23c 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -74,5 +74,8 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } } } + if (point && subName.size() > 6 && subName.substr(0,6) == "Vertex") { + return true; + } return false; } diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index 03b6340122a3..efdf6242290f 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -32,11 +32,12 @@ class ReferenceSelection : public Gui::SelectionFilterGate const App::DocumentObject* support; bool edge, plane; bool planar; + bool point; public: ReferenceSelection(const App::DocumentObject* support_, - const bool edge_, const bool plane_, const bool planar_) + const bool edge_, const bool plane_, const bool planar_, const bool point_ = false) : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), - support(support_), edge(edge_), plane(plane_), planar(planar_) + support(support_), edge(edge_), plane(plane_), planar(planar_), point(point_) { } /** diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp new file mode 100644 index 000000000000..21fe6751a726 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -0,0 +1,503 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 +# include +# include +# include +# include +#endif + +#include "ui_TaskDatumParameters.h" +#include "TaskDatumParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ReferenceSelection.h" +#include "Workbench.h" + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskDatumParameters */ + +// Create reference name from PropertyLinkSub values in a translatable fashion +const QString makeRefString(const QString& obj, const std::string& sub) +{ + if ((sub.size() > 4) && (sub.substr(4) == "Face")) { + int subId = std::atoi(&sub[4]); + return obj + QObject::tr(":Face") + QString::number(subId); + } else if ((sub.size() > 4) && (sub.substr(4) == "Edge")) { + int subId = std::atoi(&sub[4]); + return obj + QObject::tr(":Edge") + QString::number(subId); + } if ((sub.size() > 6) && (sub.substr(6) == "Vertex")) { + int subId = std::atoi(&sub[6]); + return obj + QObject::tr(":Vertex") + QString::number(subId); + } else { + return QObject::tr("No reference selected"); + } +} + +TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *parent) + : TaskBox(Gui::BitmapFactory().pixmap("iconName"),tr("Datum parameters"),true, parent),DatumView(DatumView) +{ + TaskBox(Gui::BitmapFactory().pixmap((QString::fromAscii("PartDesign_") + DatumView->datumType).toAscii()), DatumView->datumType + tr(" parameters"), true, parent); + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskDatumParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->spinValue1, SIGNAL(valueChanged(double)), + this, SLOT(onValue1Changed(double))); + connect(ui->checkBox1, SIGNAL(toggled(bool)), + this, SLOT(onCheckBox1(bool))); + connect(ui->buttonRef1, SIGNAL(pressed()), + this, SLOT(onButtonRef1())); + connect(ui->lineRef1, SIGNAL(textEdited(QString)), + this, SLOT(onRefName(QString))); + connect(ui->buttonRef2, SIGNAL(pressed()), + this, SLOT(onButtonRef2())); + connect(ui->lineRef2, SIGNAL(textEdited(QString)), + this, SLOT(onRefName(QString))); + connect(ui->buttonRef3, SIGNAL(pressed()), + this, SLOT(onButtonRef3())); + connect(ui->lineRef3, SIGNAL(textEdited(QString)), + this, SLOT(onRefName(QString))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->spinValue1->blockSignals(true); + ui->checkBox1->blockSignals(true); + ui->buttonRef1->blockSignals(true); + ui->lineRef1->blockSignals(true); + ui->buttonRef2->blockSignals(true); + ui->lineRef2->blockSignals(true); + ui->buttonRef3->blockSignals(true); + ui->lineRef3->blockSignals(true); + + // Get the feature data + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); + std::vector refnames = pcDatum->References.getSubValues(); + std::vector refstrings; + for (int r = 0; r < 3; r++) + if ((r < refs.size()) && (refs[r] != NULL)) { + refstrings.push_back(makeRefString(QString::fromAscii(refs[r]->getNameInDocument()), refnames[r])); + } else { + refstrings.push_back(tr("No reference selected")); + refnames.push_back(""); + } + + //bool checked1 = pcDatum->Checked.getValue(); + std::vector vals = pcDatum->Values.getValues(); + + // Fill data into dialog elements + ui->spinValue1->setValue(vals[0]); + //ui->checkBox1->setChecked(checked1); + ui->lineRef1->setText(refstrings[0]); + ui->lineRef1->setProperty("RefName", QByteArray(refnames[0].c_str())); + ui->lineRef2->setText(refstrings[1]); + ui->lineRef2->setProperty("RefName", QByteArray(refnames[1].c_str())); + ui->lineRef3->setText(refstrings[2]); + ui->lineRef3->setProperty("RefName", QByteArray(refnames[2].c_str())); + + // activate and de-activate dialog elements as appropriate + ui->spinValue1->blockSignals(false); + ui->checkBox1->blockSignals(false); + ui->buttonRef1->blockSignals(false); + ui->lineRef1->blockSignals(false); + ui->buttonRef2->blockSignals(false); + ui->lineRef2->blockSignals(false); + ui->buttonRef3->blockSignals(false); + ui->lineRef3->blockSignals(false); + updateUI(); +} + +QLineEdit* TaskDatumParameters::getCurrentLine() +{ + if (refSelectionMode == 0) + return ui->lineRef1; + else if (refSelectionMode == 1) + return ui->lineRef2; + else if (refSelectionMode == 2) + return ui->lineRef3; + else + return NULL; +} + +void TaskDatumParameters::updateUI() +{ + ui->checkBox1->setEnabled(false); + onButtonRef1(true); +} + +void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (refSelectionMode < 0) + return; + // Don't allow selection in other document + if (strcmp(msg.pDocName, DatumView->getObject()->getDocument()->getName()) != 0) + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string subName(msg.pSubName); + if (((subName.size() > 4) && (subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge")) || + ((subName.size() > 6) && (subName.substr(0,6) != "Vertex"))) + return; + + // Don't allow selection outside Tip solid feature + App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); + if (solid == NULL) { + // There is no solid feature yet, so we can't select from it... + // Turn off reference selection mode + onButtonRef1(false); + return; + } + if (strcmp(msg.pObjectName, solid->getNameInDocument()) != 0) + return; + + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); + std::vector refnames = pcDatum->References.getSubValues(); + if (refSelectionMode < refs.size()) { + refs[refSelectionMode] = solid; + refnames[refSelectionMode] = subName; + } else { + refs.push_back(solid); + refnames.push_back(subName); + } + pcDatum->References.setValues(refs, refnames); + pcDatum->getDocument()->recomputeFeature(pcDatum); + + QLineEdit* line = getCurrentLine(); + if (line != NULL) { + line->blockSignals(true); + line->setText(makeRefString(QString::fromAscii(solid->getNameInDocument()), subName)); + line->setProperty("RefName", QByteArray(subName.c_str())); + line->blockSignals(false); + } + + // Turn off reference selection mode + onButtonRef1(false); + } + else if (msg.Type == Gui::SelectionChanges::ClrSelection) { + QLineEdit* line = getCurrentLine(); + if (line != NULL) { + line->blockSignals(true); + line->setText(tr("No reference selected")); + line->setProperty("RefName", QByteArray()); + line->blockSignals(false); + } + } +} + +void TaskDatumParameters::onValue1Changed(double val) +{ + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector vals = pcDatum->Values.getValues(); + vals[0] = val; + pcDatum->Values.setValues(vals); + pcDatum->getDocument()->recomputeFeature(pcDatum); +} + +void TaskDatumParameters::onCheckBox1(bool on) +{ + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + //pcDatum->Reversed.setValue(on); + pcDatum->getDocument()->recomputeFeature(pcDatum); +} + +void TaskDatumParameters::onButtonRef(const bool pressed, const int idx) +{ + App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); + if (solid == NULL) { + // There is no solid feature, so we can't select from it... + return; + } + + if (pressed) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc) { + doc->setHide(DatumView->getObject()->getNameInDocument()); + doc->setShow(solid->getNameInDocument()); + } + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate + (new ReferenceSelection(solid, true, true, false, true)); + refSelectionMode = idx; + } else { + Gui::Selection().rmvSelectionGate(); + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc) { + doc->setShow(DatumView->getObject()->getNameInDocument()); + doc->setHide(solid->getNameInDocument()); + } + + refSelectionMode = -1; + } +} + +void TaskDatumParameters::onButtonRef1(const bool pressed) { + onButtonRef(pressed, 0); + // Update button if onButtonRef1() is called explicitly + ui->buttonRef1->setChecked(pressed); +} +void TaskDatumParameters::onButtonRef2(const bool pressed) { + onButtonRef(pressed, 1); + // Update button if onButtonRef1() is called explicitly + ui->buttonRef2->setChecked(pressed); +} +void TaskDatumParameters::onButtonRef3(const bool pressed) { + onButtonRef(pressed, 2); + // Update button if onButtonRef1() is called explicitly + ui->buttonRef3->setChecked(pressed); +} + +void TaskDatumParameters::onRefName(const QString& text) +{ + // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. + QString name; + QTextStream str(&name); + QRegExp rx(name); + std::stringstream ss; + QLineEdit* line = getCurrentLine(); + if (line == NULL) return; + + str << "^" << tr("Face") << "(\\d+)$"; + if (text.indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int faceId = rx.cap(1).toInt(); + ss << "Face" << faceId; + } + str << "^" << tr("Edge") << "(\\d+)$"; + if (text.indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int lineId = rx.cap(1).toInt(); + ss << "Edge" << lineId; + } + str << "^" << tr("Vertex") << "(\\d+)$"; + if (text.indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int vertexId = rx.cap(1).toInt(); + ss << "Vertex" << vertexId; + } + line->setProperty("RefName", QByteArray(ss.str().c_str())); + + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); + if (solid == NULL) { + // There is no solid, so we can't select from it... + return; + } + std::vector refs = pcDatum->References.getValues(); + std::vector refnames = pcDatum->References.getSubValues(); + if (refSelectionMode < refs.size()) { + refs[refSelectionMode] = solid; + refnames[refSelectionMode] = ss.str(); + } else { + refs.push_back(solid); + refnames.push_back(ss.str()); + } + pcDatum->References.setValues(refs, refnames); + pcDatum->getDocument()->recomputeFeature(pcDatum); +} + +double TaskDatumParameters::getValue1() const +{ + return ui->spinValue1->value(); +} + +bool TaskDatumParameters::getCheck1() const +{ + return ui->checkBox1->isChecked(); +} + +QString TaskDatumParameters::getRefName(const int idx) const +{ + if (idx == 0) + return ui->lineRef1->property("RefName").toString(); + else if (idx == 1) + return ui->lineRef2->property("RefName").toString(); + else if (idx == 2) + return ui->lineRef3->property("RefName").toString(); +} + +TaskDatumParameters::~TaskDatumParameters() +{ + delete ui; +} + +void TaskDatumParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->spinValue1->blockSignals(true); + ui->checkBox1->blockSignals(true); + ui->buttonRef1->blockSignals(true); + ui->lineRef1->blockSignals(true); + ui->buttonRef2->blockSignals(true); + ui->lineRef2->blockSignals(true); + ui->buttonRef3->blockSignals(true); + ui->lineRef3->blockSignals(true); + ui->retranslateUi(proxy); + + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); + std::vector refnames = pcDatum->References.getSubValues(); + std::vector refstrings; + for (int r = 0; r < 3; r++) + if ((r < refs.size()) && (refs[r] != NULL)) + refstrings.push_back(makeRefString(QString::fromAscii(refs[r]->getNameInDocument()), refnames[r])); + else + refstrings.push_back(tr("No reference selected")); + + ui->lineRef1->setText(refstrings[0]); + ui->lineRef2->setText(refstrings[1]); + ui->lineRef3->setText(refstrings[2]); + + ui->spinValue1->blockSignals(false); + ui->checkBox1->blockSignals(false); + ui->buttonRef1->blockSignals(false); + ui->lineRef1->blockSignals(false); + ui->buttonRef2->blockSignals(false); + ui->lineRef2->blockSignals(false); + ui->buttonRef3->blockSignals(false); + ui->lineRef3->blockSignals(false); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgDatumParameters::TaskDlgDatumParameters(ViewProviderDatum *DatumView) + : TaskDialog(),DatumView(DatumView) +{ + assert(DatumView); + parameter = new TaskDatumParameters(DatumView); + + Content.push_back(parameter); +} + +TaskDlgDatumParameters::~TaskDlgDatumParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgDatumParameters::open() +{ + +} + +void TaskDlgDatumParameters::clicked(int) +{ + +} + +bool TaskDlgDatumParameters::accept() +{ + std::string name = DatumView->getObject()->getNameInDocument(); + + try { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Values = [%f]",name.c_str(),parameter->getValue1()); + //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Checked = %i",name.c_str(),parameter->getCheckBox1()?1:0); + + App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); + if (solid != NULL) { + QString buf = QString::fromAscii("["); + for (int r = 0; r < 3; r++) { + QString refname = parameter->getRefName(r); + if (refname != tr("No reference selected")) + buf += QString::fromAscii(r == 0 ? "" : ",") + + QString::fromAscii("App.activeDocument().") + QString::fromUtf8(solid->getNameInDocument()) + + QString::fromAscii(",") + refname + QString::fromAscii(")"); + } + buf += QString::fromAscii("]"); + if (buf.size() > 2) + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.References = %s", name.c_str(), buf.toStdString().c_str()); + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!DatumView->getObject()->isValid()) + throw Base::Exception(DatumView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Datum dialog: Input error"), QString::fromAscii(e.what())); + return false; + } + + return true; +} + +bool TaskDlgDatumParameters::reject() +{ + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + return true; +} + + + +#include "moc_TaskDatumParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.h b/src/Mod/PartDesign/Gui/TaskDatumParameters.h new file mode 100644 index 000000000000..1ab65b860cd0 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.h @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 GUI_TASKVIEW_TaskDatumParameters_H +#define GUI_TASKVIEW_TaskDatumParameters_H + +#include +#include +#include + +#include "ViewProviderDatum.h" + +class Ui_TaskDatumParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartDesignGui { + + + +class TaskDatumParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *parent = 0); + ~TaskDatumParameters(); + + QString getRefName(const int idx) const; + double getValue1(void) const; + bool getCheck1(void) const; + +private Q_SLOTS: + void onValue1Changed(double); + void onCheckBox1(bool); + void onRefName(const QString& text); + void onButtonRef1(const bool pressed = true); + void onButtonRef2(const bool pressed = true); + void onButtonRef3(const bool pressed = true); + +protected: + void changeEvent(QEvent *e); + +private: + void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(); + +private: + QWidget* proxy; + Ui_TaskDatumParameters* ui; + ViewProviderDatum *DatumView; + + int refSelectionMode; + + QLineEdit* getCurrentLine(); + void onButtonRef(const bool pressed, const int idx); + +}; + +/// simulation dialog for the TaskView +class TaskDlgDatumParameters : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgDatumParameters(ViewProviderDatum *DatumView); + ~TaskDlgDatumParameters(); + + ViewProviderDatum* getDatumView() const + { return DatumView; } + + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderDatum *DatumView; + + TaskDatumParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui b/src/Mod/PartDesign/Gui/TaskDatumParameters.ui new file mode 100644 index 000000000000..b8987e098fb5 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.ui @@ -0,0 +1,97 @@ + + + PartDesignGui::TaskDatumParameters + + + + 0 + 0 + 272 + 192 + + + + Form + + + + + + + + Reference 1 + + + + + + + + + + + + + + Reference 2 + + + + + + + + + + + + + + Reference 3 + + + + + + + + + + + + + + Offset + + + + + + + 0.000000000000000 + + + 999999999.000000000000000 + + + 5.000000000000000 + + + 10.000000000000000 + + + + + + + + + Flip sides + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp new file mode 100644 index 000000000000..133919389b0f --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 "ViewProviderDatum.h" +#include "TaskDatumParameters.h" +#include "Workbench.h" +#include +#include + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatum,PartDesignGui::ViewProvider) + +ViewProviderDatum::ViewProviderDatum() +{ +} + +ViewProviderDatum::~ViewProviderDatum() +{ +} + +void ViewProviderDatum::attach(App::DocumentObject *obj) +{ + ViewProvider::attach(obj); + + PartDesign::Datum* pcDatum = static_cast(getObject()); + if (pcDatum->getClassTypeId() == PartDesign::Plane::getClassTypeId()) + datumType = QObject::tr("Plane"); + else if (pcDatum->getClassTypeId() == PartDesign::Line::getClassTypeId()) + datumType = QObject::tr("Line"); + else if (pcDatum->getClassTypeId() == PartDesign::Point::getClassTypeId()) + datumType = QObject::tr("Point"); +} + +void ViewProviderDatum::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit datum ") + datumType, receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderDatum::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this datum feature the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgDatumParameters *datumDlg = qobject_cast(dlg); + if (datumDlg && datumDlg->getDatumView() != this) + datumDlg = 0; // another datum feature left open its task panel + if (dlg && !datumDlg) { + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (datumDlg) + Gui::Control().showDialog(datumDlg); + else + Gui::Control().showDialog(new TaskDlgDatumParameters(this)); + + return true; + } + else { + return ViewProviderPart::setEdit(ModNum); + } +} + +void ViewProviderDatum::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + } + else { + PartGui::ViewProviderPart::unsetEdit(ModNum); + } +} + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.h b/src/Mod/PartDesign/Gui/ViewProviderDatum.h new file mode 100644 index 000000000000..acb4a89b3d41 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 "ViewProvider.h" + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderDatum : public ViewProvider +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatum); + +public: + /// constructor + ViewProviderDatum(); + /// destructor + virtual ~ViewProviderDatum(); + + /// grouping handling + void setupContextMenu(QMenu*, QObject*, const char*); + + virtual void attach(App::DocumentObject *); + + /// The datum type (Plane, Line or Point) + QString datumType; + +protected: + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + +}; + + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderPad_H diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 5208ab97f668..d1905c709d13 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -98,10 +98,24 @@ void Workbench::activated() std::vector Watcher; + const char* Vertex[] = { + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT Part::Feature SUBELEMENT Vertex COUNT 1..", + Vertex, + "Vertex tools", + "Part_Box" + )); const char* Edge[] = { "PartDesign_Fillet", "PartDesign_Chamfer", + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Edge COUNT 1..", @@ -111,10 +125,13 @@ void Workbench::activated() )); const char* Face[] = { - "PartDesign_NewSketch", + "PartDesign_NewSketch", "PartDesign_Fillet", "PartDesign_Chamfer", "PartDesign_Draft", + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT Part::Feature SUBELEMENT Face COUNT 1", @@ -135,6 +152,9 @@ void Workbench::activated() const char* Plane1[] = { "PartDesign_NewSketch", + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT App::Plane COUNT 1", @@ -144,6 +164,9 @@ void Workbench::activated() )); const char* Plane2[] = { "PartDesign_NewSketch", + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", 0}; Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( "SELECT PartDesign::Plane COUNT 1", @@ -152,6 +175,30 @@ void Workbench::activated() "Part_Box" )); + const char* Line[] = { + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::Line COUNT 1", + Line, + "Start Part", + "Part_Box" + )); + + const char* Point[] = { + "PartDesign_Plane", + "PartDesign_Line", + "PartDesign_Point", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::Point COUNT 1", + Point, + "Start Part", + "Part_Box" + )); + const char* NoSel[] = { "PartDesign_Body", 0}; @@ -276,6 +323,10 @@ Gui::MenuItem* Workbench::setupMenuBar() const << cons << consaccel << "Separator" + << "PartDesign_Plane" + << "PartDesign_Line" + << "PartDesign_Point" + << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" @@ -313,6 +364,10 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "Sketcher_MapSketch" << "Sketcher_LeaveSketch" << "Separator" + << "PartDesign_Plane" + << "PartDesign_Line" + << "PartDesign_Point" + << "Separator" << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" From d8d945a8b6c6d2116f1b335f27e11a069fe81883 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 13 Apr 2013 15:55:13 +0430 Subject: [PATCH 079/664] Work on reference selection for Datum features --- src/Mod/PartDesign/App/Body.cpp | 4 +- src/Mod/PartDesign/App/Body.h | 2 +- src/Mod/PartDesign/Gui/Command.cpp | 4 +- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 29 ++ .../PartDesign/Gui/TaskDatumParameters.cpp | 339 ++++++++++-------- src/Mod/PartDesign/Gui/TaskDatumParameters.h | 15 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 9 +- src/Mod/PartDesign/Gui/Workbench.cpp | 2 - 8 files changed, 246 insertions(+), 158 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 9278ef825672..9421be8c8c7a 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -185,9 +185,9 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const return *it; } -const bool Body::hasFeature(const App::DocumentObject* f) +const bool Body::hasFeature(const App::DocumentObject* f) const { - std::vector features = Model.getValues(); + const std::vector features = Model.getValues(); return std::find(features.begin(), features.end(), f) != features.end(); } diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 763fe6ef17ba..3ce3d159bf71 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -76,7 +76,7 @@ class Body : public Part::BodyBase //const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); /// Return true if the feature belongs to this body - const bool hasFeature(const App::DocumentObject *f); + const bool hasFeature(const App::DocumentObject *f) const; /// Return true if the feature is located after the current Tip feature const bool isAfterTip(const App::DocumentObject *f); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 9c9fbc4e065d..bd564aad2c15 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -233,10 +233,10 @@ const QString getReferenceString(Gui::Command* cmd) // get the selected sub shape const Part::TopoShape &shape = part->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(sub[r].c_str()); - if (sh.IsNull()) { + if (!sh.IsNull()) { referenceString += QString::fromAscii(r == 0 ? "" : ",") + QString::fromAscii("(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + - QString::fromAscii(",") + QString::fromStdString(sub[r]) + QString::fromAscii(")"); + QString::fromAscii(",'") + QString::fromStdString(sub[r]) + QString::fromAscii("')"); } } diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 93880e81e23c..6bec9ac3992d 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -30,9 +30,13 @@ # include #endif +#include #include #include +#include +#include #include "ReferenceSelection.h" +#include "Workbench.h" using namespace PartDesignGui; using namespace Gui; @@ -41,6 +45,31 @@ using namespace Gui; bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName) { + if (plane && (pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()))) + // Note: It is assumed that a Part has exactly 3 App::Plane objects at the root of the feature tree + return true; + + if (pObj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) { + // Allow selecting PartDesign::Datum features + if (!ActivePartObject->hasFeature(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; + } + + // Handle selection of geometry elements + if (support == NULL) + return false; + // Don't allow selection in other document + if (pDoc != support->getDocument()) + return false; if (!sSubName || sSubName[0] == '\0') return false; if (pObj != support) diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 21fe6751a726..d4637ae86de8 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -35,6 +35,7 @@ #include "TaskDatumParameters.h" #include #include +#include #include #include #include @@ -54,19 +55,42 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskDatumParameters */ // Create reference name from PropertyLinkSub values in a translatable fashion -const QString makeRefString(const QString& obj, const std::string& sub) +const QString makeRefString(const App::DocumentObject* obj, const std::string& sub) { - if ((sub.size() > 4) && (sub.substr(4) == "Face")) { + if (obj == NULL) + return QObject::tr("No reference selected"); + + if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + obj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) + // App::Plane or Datum feature + return QString::fromAscii(obj->getNameInDocument()); + + if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) { int subId = std::atoi(&sub[4]); - return obj + QObject::tr(":Face") + QString::number(subId); - } else if ((sub.size() > 4) && (sub.substr(4) == "Edge")) { + return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Face") + QString::number(subId); + } else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) { int subId = std::atoi(&sub[4]); - return obj + QObject::tr(":Edge") + QString::number(subId); - } if ((sub.size() > 6) && (sub.substr(6) == "Vertex")) { + return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Edge") + QString::number(subId); + } if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) { int subId = std::atoi(&sub[6]); - return obj + QObject::tr(":Vertex") + QString::number(subId); - } else { - return QObject::tr("No reference selected"); + return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Vertex") + QString::number(subId); + } + + return QObject::tr("No reference selected"); +} + +void TaskDatumParameters::makeRefStrings(std::vector& refstrings, std::vector& refnames) { + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); + refnames = pcDatum->References.getSubValues(); + + for (int r = 0; r < 3; r++) { + if ((r < refs.size()) && (refs[r] != NULL)) { + refstrings.push_back(makeRefString(refs[r], refnames[r])); + } else { + refstrings.push_back(QObject::tr("No reference selected")); + refnames.push_back(""); + } } } @@ -87,15 +111,15 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p connect(ui->buttonRef1, SIGNAL(pressed()), this, SLOT(onButtonRef1())); connect(ui->lineRef1, SIGNAL(textEdited(QString)), - this, SLOT(onRefName(QString))); + this, SLOT(onRefName1(QString))); connect(ui->buttonRef2, SIGNAL(pressed()), this, SLOT(onButtonRef2())); connect(ui->lineRef2, SIGNAL(textEdited(QString)), - this, SLOT(onRefName(QString))); + this, SLOT(onRefName2(QString))); connect(ui->buttonRef3, SIGNAL(pressed()), this, SLOT(onButtonRef3())); connect(ui->lineRef3, SIGNAL(textEdited(QString)), - this, SLOT(onRefName(QString))); + this, SLOT(onRefName3(QString))); this->groupLayout()->addWidget(proxy); @@ -111,16 +135,9 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p // Get the feature data PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); std::vector refstrings; - for (int r = 0; r < 3; r++) - if ((r < refs.size()) && (refs[r] != NULL)) { - refstrings.push_back(makeRefString(QString::fromAscii(refs[r]->getNameInDocument()), refnames[r])); - } else { - refstrings.push_back(tr("No reference selected")); - refnames.push_back(""); - } + makeRefStrings(refstrings, refnames); //bool checked1 = pcDatum->Checked.getValue(); std::vector vals = pcDatum->Values.getValues(); @@ -147,83 +164,68 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p updateUI(); } -QLineEdit* TaskDatumParameters::getCurrentLine() +void TaskDatumParameters::updateUI() { - if (refSelectionMode == 0) + ui->checkBox1->setEnabled(false); + onButtonRef1(true); +} + +QLineEdit* TaskDatumParameters::getLine(const int idx) +{ + if (idx == 0) return ui->lineRef1; - else if (refSelectionMode == 1) + else if (idx == 1) return ui->lineRef2; - else if (refSelectionMode == 2) + else if (idx == 2) return ui->lineRef3; else return NULL; } -void TaskDatumParameters::updateUI() -{ - ui->checkBox1->setEnabled(false); - onButtonRef1(true); -} - void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { if (refSelectionMode < 0) return; - // Don't allow selection in other document - if (strcmp(msg.pDocName, DatumView->getObject()->getDocument()->getName()) != 0) - return; - - if (!msg.pSubName || msg.pSubName[0] == '\0') - return; - std::string subName(msg.pSubName); - if (((subName.size() > 4) && (subName.substr(0,4) != "Face") && (subName.substr(0,4) != "Edge")) || - ((subName.size() > 6) && (subName.substr(0,6) != "Vertex"))) - return; - - // Don't allow selection outside Tip solid feature - App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); - if (solid == NULL) { - // There is no solid feature yet, so we can't select from it... - // Turn off reference selection mode - onButtonRef1(false); - return; - } - if (strcmp(msg.pObjectName, solid->getNameInDocument()) != 0) - return; + // Note: The validity checking has already been done in ReferenceSelection.cpp PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); + App::DocumentObject* selObj = pcDatum->getDocument()->getObject(msg.pObjectName); + if (selObj == pcDatum) return; + std::string subname = msg.pSubName; + + // Remove subname for planes + if (selObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + selObj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) + subname = ""; + + // eliminate duplicate selections + for (int r = 0; r < refs.size(); r++) + if ((refs[r] == selObj) && (refnames[r] == subname)) + return; + if (refSelectionMode < refs.size()) { - refs[refSelectionMode] = solid; - refnames[refSelectionMode] = subName; + refs[refSelectionMode] = selObj; + refnames[refSelectionMode] = subname; } else { - refs.push_back(solid); - refnames.push_back(subName); + refs.push_back(selObj); + refnames.push_back(subname); } pcDatum->References.setValues(refs, refnames); - pcDatum->getDocument()->recomputeFeature(pcDatum); + //pcDatum->getDocument()->recomputeFeature(pcDatum); - QLineEdit* line = getCurrentLine(); + QLineEdit* line = getLine(refSelectionMode); if (line != NULL) { line->blockSignals(true); - line->setText(makeRefString(QString::fromAscii(solid->getNameInDocument()), subName)); - line->setProperty("RefName", QByteArray(subName.c_str())); + line->setText(makeRefString(selObj, subname)); + line->setProperty("RefName", QByteArray(subname.c_str())); line->blockSignals(false); } // Turn off reference selection mode - onButtonRef1(false); - } - else if (msg.Type == Gui::SelectionChanges::ClrSelection) { - QLineEdit* line = getCurrentLine(); - if (line != NULL) { - line->blockSignals(true); - line->setText(tr("No reference selected")); - line->setProperty("RefName", QByteArray()); - line->blockSignals(false); - } + onButtonRef1(false); // Note: It doesn't matter whether we call onButtonRef1 or onButtonRef2 etc. } } @@ -245,30 +247,16 @@ void TaskDatumParameters::onCheckBox1(bool on) void TaskDatumParameters::onButtonRef(const bool pressed, const int idx) { + // Note: Even if there is no solid, App::Plane and PartDesign::Datum can still be selected App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); - if (solid == NULL) { - // There is no solid feature, so we can't select from it... - return; - } if (pressed) { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setHide(DatumView->getObject()->getNameInDocument()); - doc->setShow(solid->getNameInDocument()); - } Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate (new ReferenceSelection(solid, true, true, false, true)); refSelectionMode = idx; } else { Gui::Selection().rmvSelectionGate(); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setShow(DatumView->getObject()->getNameInDocument()); - doc->setHide(solid->getNameInDocument()); - } - refSelectionMode = -1; } } @@ -289,59 +277,120 @@ void TaskDatumParameters::onButtonRef3(const bool pressed) { ui->buttonRef3->setChecked(pressed); } -void TaskDatumParameters::onRefName(const QString& text) +void TaskDatumParameters::onRefName(const QString& text, const int idx) { - // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. - QString name; - QTextStream str(&name); - QRegExp rx(name); - std::stringstream ss; - QLineEdit* line = getCurrentLine(); + QLineEdit* line = getLine(idx); if (line == NULL) return; - str << "^" << tr("Face") << "(\\d+)$"; - if (text.indexOf(rx) < 0) { - line->setProperty("RefName", QByteArray()); - return; - } else { - int faceId = rx.cap(1).toInt(); - ss << "Face" << faceId; - } - str << "^" << tr("Edge") << "(\\d+)$"; - if (text.indexOf(rx) < 0) { - line->setProperty("RefName", QByteArray()); + if (text.length() == 0) { + // Reference was removed + // Update the reference list + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); + std::vector refnames = pcDatum->References.getSubValues(); + std::vector newrefs; + std::vector newrefnames; + for (int r = 0; r < refs.size(); r++) { + if (r != idx) { + newrefs.push_back(refs[r]); + newrefnames.push_back(refnames[r]); + } + } + pcDatum->References.setValues(newrefs, newrefnames); + + // Update the UI + std::vector refstrings; + makeRefStrings(refstrings, newrefnames); + ui->lineRef1->setText(refstrings[0]); + ui->lineRef1->setProperty("RefName", QByteArray(newrefnames[0].c_str())); + ui->lineRef2->setText(refstrings[1]); + ui->lineRef2->setProperty("RefName", QByteArray(newrefnames[1].c_str())); + ui->lineRef3->setText(refstrings[2]); + ui->lineRef3->setProperty("RefName", QByteArray(newrefnames[2].c_str())); return; - } else { - int lineId = rx.cap(1).toInt(); - ss << "Edge" << lineId; } - str << "^" << tr("Vertex") << "(\\d+)$"; - if (text.indexOf(rx) < 0) { - line->setProperty("RefName", QByteArray()); - return; + + // Check whether this is the name of an App::Plane or PartDesign::Datum feature + App::DocumentObject* obj = DatumView->getObject()->getDocument()->getObject(text.toAscii()); + std::string subElement = ""; + + if (obj != NULL) { + if (!obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + if (!obj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) + return; + + if (!PartDesignGui::ActivePartObject->hasFeature(obj)) + return; + } // else everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) } else { - int vertexId = rx.cap(1).toInt(); - ss << "Vertex" << vertexId; + // This is the name of a subelement of the visible solid (Face, Edge, Vertex) + App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); + if (solid == NULL) { + // There is no solid, so we can't select from it... + return; + } + + // TODO: check validity of the text that was entered: Does it actually reference an element on the solid? + + // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. + QString name; + QTextStream str(&name); + QRegExp rx(name); + std::stringstream ss; + + str << "^" << tr("Face") << "(\\d+)$"; + if (text.indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int faceId = rx.cap(1).toInt(); + ss << "Face" << faceId; + } + str << "^" << tr("Edge") << "(\\d+)$"; + if (text.indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int lineId = rx.cap(1).toInt(); + ss << "Edge" << lineId; + } + str << "^" << tr("Vertex") << "(\\d+)$"; + if (text.indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int vertexId = rx.cap(1).toInt(); + ss << "Vertex" << vertexId; + } + line->setProperty("RefName", QByteArray(ss.str().c_str())); + subElement = ss.str(); } - line->setProperty("RefName", QByteArray(ss.str().c_str())); PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); - App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); - if (solid == NULL) { - // There is no solid, so we can't select from it... - return; - } std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); if (refSelectionMode < refs.size()) { - refs[refSelectionMode] = solid; - refnames[refSelectionMode] = ss.str(); + refs[refSelectionMode] = obj; + refnames[refSelectionMode] = subElement.c_str(); } else { - refs.push_back(solid); - refnames.push_back(ss.str()); + refs.push_back(obj); + refnames.push_back(subElement.c_str()); } pcDatum->References.setValues(refs, refnames); - pcDatum->getDocument()->recomputeFeature(pcDatum); + //pcDatum->getDocument()->recomputeFeature(pcDatum); +} + +void TaskDatumParameters::onRefName1(const QString& text) +{ + onRefName(text, 0); +} +void TaskDatumParameters::onRefName2(const QString& text) +{ + onRefName(text, 1); +} +void TaskDatumParameters::onRefName3(const QString& text) +{ + onRefName(text, 2); } double TaskDatumParameters::getValue1() const @@ -354,14 +403,27 @@ bool TaskDatumParameters::getCheck1() const return ui->checkBox1->isChecked(); } -QString TaskDatumParameters::getRefName(const int idx) const +QString TaskDatumParameters::getReference(const int idx) const { - if (idx == 0) - return ui->lineRef1->property("RefName").toString(); - else if (idx == 1) - return ui->lineRef2->property("RefName").toString(); - else if (idx == 2) - return ui->lineRef3->property("RefName").toString(); + QString obj, sub; + + if (idx == 0) { + obj = ui->lineRef1->text(); + sub = ui->lineRef1->property("RefName").toString(); + } else if (idx == 1) { + obj = ui->lineRef2->text(); + sub = ui->lineRef2->property("RefName").toString(); + } else if (idx == 2) { + obj = ui->lineRef3->text(); + sub = ui->lineRef3->property("RefName").toString(); + } + + obj = obj.left(obj.indexOf(QString::fromAscii(":"))); + + if (obj == tr("No reference selected")) + return QString::fromAscii(""); + else + return QString::fromAscii("(App.activeDocument().") + obj + QString::fromAscii(", '") + sub + QString::fromAscii("')"); } TaskDatumParameters::~TaskDatumParameters() @@ -383,16 +445,9 @@ void TaskDatumParameters::changeEvent(QEvent *e) ui->lineRef3->blockSignals(true); ui->retranslateUi(proxy); - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->References.getValues(); - std::vector refnames = pcDatum->References.getSubValues(); + std::vector refnames; std::vector refstrings; - for (int r = 0; r < 3; r++) - if ((r < refs.size()) && (refs[r] != NULL)) - refstrings.push_back(makeRefString(QString::fromAscii(refs[r]->getNameInDocument()), refnames[r])); - else - refstrings.push_back(tr("No reference selected")); - + makeRefStrings(refstrings, refnames); ui->lineRef1->setText(refstrings[0]); ui->lineRef2->setText(refstrings[1]); ui->lineRef3->setText(refstrings[2]); @@ -452,11 +507,9 @@ bool TaskDlgDatumParameters::accept() if (solid != NULL) { QString buf = QString::fromAscii("["); for (int r = 0; r < 3; r++) { - QString refname = parameter->getRefName(r); - if (refname != tr("No reference selected")) - buf += QString::fromAscii(r == 0 ? "" : ",") + - QString::fromAscii("App.activeDocument().") + QString::fromUtf8(solid->getNameInDocument()) + - QString::fromAscii(",") + refname + QString::fromAscii(")"); + QString ref = parameter->getReference(r); + if (ref != QString::fromAscii("")) + buf += QString::fromAscii(r == 0 ? "" : ",") + ref; } buf += QString::fromAscii("]"); if (buf.size() > 2) diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.h b/src/Mod/PartDesign/Gui/TaskDatumParameters.h index 1ab65b860cd0..9936172d482e 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.h @@ -31,6 +31,7 @@ #include "ViewProviderDatum.h" class Ui_TaskDatumParameters; +class QLineEdit; namespace App { class Property; @@ -52,14 +53,16 @@ class TaskDatumParameters : public Gui::TaskView::TaskBox, public Gui::Selection TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *parent = 0); ~TaskDatumParameters(); - QString getRefName(const int idx) const; + QString getReference(const int idx) const; double getValue1(void) const; bool getCheck1(void) const; private Q_SLOTS: void onValue1Changed(double); void onCheckBox1(bool); - void onRefName(const QString& text); + void onRefName1(const QString& text); + void onRefName2(const QString& text); + void onRefName3(const QString& text); void onButtonRef1(const bool pressed = true); void onButtonRef2(const bool pressed = true); void onButtonRef3(const bool pressed = true); @@ -71,6 +74,11 @@ private Q_SLOTS: void onSelectionChanged(const Gui::SelectionChanges& msg); void updateUI(); + void makeRefStrings(std::vector& refstrings, std::vector& refnames); + QLineEdit* getLine(const int idx); + void onButtonRef(const bool pressed, const int idx); + void onRefName(const QString& text, const int idx); + private: QWidget* proxy; Ui_TaskDatumParameters* ui; @@ -78,9 +86,6 @@ private Q_SLOTS: int refSelectionMode; - QLineEdit* getCurrentLine(); - void onButtonRef(const bool pressed, const int idx); - }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 133919389b0f..3275075691ea 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -24,6 +24,9 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include #endif #include "ViewProviderDatum.h" @@ -49,11 +52,11 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) ViewProvider::attach(obj); PartDesign::Datum* pcDatum = static_cast(getObject()); - if (pcDatum->getClassTypeId() == PartDesign::Plane::getClassTypeId()) + if (pcDatum->getTypeId() == PartDesign::Plane::getClassTypeId()) datumType = QObject::tr("Plane"); - else if (pcDatum->getClassTypeId() == PartDesign::Line::getClassTypeId()) + else if (pcDatum->getTypeId() == PartDesign::Line::getClassTypeId()) datumType = QObject::tr("Line"); - else if (pcDatum->getClassTypeId() == PartDesign::Point::getClassTypeId()) + else if (pcDatum->getTypeId() == PartDesign::Point::getClassTypeId()) datumType = QObject::tr("Point"); } diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index d1905c709d13..b4a0538f84d9 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -270,8 +270,6 @@ void Workbench::activated() if (activeBody != NULL) { Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); - // Move selection to the Tip feature so that the user can start creating new features right away - Gui::Command::doCommand(Gui::Command::Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s.Tip)", activeBody->getNameInDocument()); } addTaskWatcher(Watcher); From 4f80b72508477d64adb510a3edf71118e038a362 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 15 Apr 2013 21:04:27 +0430 Subject: [PATCH 080/664] Work on Gui of Datum features --- src/Mod/PartDesign/App/AppPartDesign.cpp | 4 + src/Mod/PartDesign/App/DatumFeature.cpp | 231 +++++++++++++++++- src/Mod/PartDesign/App/DatumFeature.h | 31 ++- src/Mod/PartDesign/Gui/Command.cpp | 2 +- .../PartDesign/Gui/TaskDatumParameters.cpp | 156 +++++++++--- src/Mod/PartDesign/Gui/TaskDatumParameters.h | 2 + 6 files changed, 390 insertions(+), 36 deletions(-) diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 0922ad5eacc9..98782e7a2733 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -101,4 +101,8 @@ PyMODINIT_FUNC init_PartDesign() PartDesign::Plane ::init(); PartDesign::Line ::init(); PartDesign::Point ::init(); + + PartDesign::Point::initHints(); + PartDesign::Line ::initHints(); + PartDesign::Plane::initHints(); } diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp index 0d4148f59d9d..75a95ca53d51 100644 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -43,8 +43,11 @@ #endif +#include #include "DatumFeature.h" #include +#include +#include "Mod/Part/App/PrimitiveFeature.h" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -52,7 +55,6 @@ using namespace PartDesign; - PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, PartDesign::Feature) Datum::Datum(void) @@ -77,13 +79,174 @@ short Datum::mustExecute(void) const void Datum::onChanged(const App::Property* prop) { + if (prop == &References) { + refTypes.clear(); + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + + for (int r = 0; r < refs.size(); r++) + refTypes.insert(getRefType(refs[r], refnames[r])); + } + PartDesign::Feature::onChanged(prop); } +// Note: We don't distinguish between e.g. datum lines and edges here +// These values are just markers so it doesn't matter that they are Part features +#define PLANE Part::Plane::getClassTypeId() +#define LINE Part::Line::getClassTypeId() +#define POINT Part::Vertex::getClassTypeId() + +const Base::Type Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) +{ + Base::Type type = obj->getTypeId(); + + if ((type == App::Plane::getClassTypeId()) || (type == PartDesign::Plane::getClassTypeId())) + return PLANE; + else if (type == PartDesign::Line::getClassTypeId()) + return LINE; + else if (type == PartDesign::Point::getClassTypeId()) + return POINT; + else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { + // Note: For now, only planar references are possible + if (subname.size() > 4 && subname.substr(0,4) == "Face") + return PLANE; + else if (subname.size() > 4 && subname.substr(0,4) == "Edge") + return LINE; + else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") + return POINT; + } + + throw Base::Exception("PartDesign::Datum::getRefType(): Illegal object type"); +} + +// ================================ Initialize the hints ===================== + +std::map, std::set > Point::hints = std::map, std::set >(); + +void Point::initHints() +{ + std::set DONE; + DONE.insert(PartDesign::Point::getClassTypeId()); + + std::multiset key; + std::set value; + key.insert(POINT); + hints[key] = DONE; // POINT -> DONE. Point from another point or vertex + + key.clear(); value.clear(); + key.insert(LINE); + value.insert(LINE); value.insert(PLANE); + hints[key] = value; // LINE -> LINE or PLANE + + key.clear(); value.clear(); + key.insert(LINE); key.insert(LINE); + hints[key] = DONE; // {LINE, LINE} -> DONE. Point from two lines or edges + + key.clear(); value.clear(); + key.insert(LINE); key.insert(PLANE); + hints[key] = DONE; // {LINE, PLANE} -> DONE. Point from line and plane + + key.clear(); value.clear(); + key.insert(PLANE); + value.insert(PLANE); value.insert(LINE); + hints[key] = value; // PLANE -> PLANE or LINE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); + value.insert(PLANE); + hints[key] = value; // {PLANE, PLANE} -> PLANE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); key.insert(PLANE); + hints[key] = DONE; // {PLANE, PLANE, PLANE} -> DONE. Point from three planes + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +std::map, std::set > Line::hints = std::map, std::set >(); + +void Line::initHints() +{ + std::set DONE; + DONE.insert(PartDesign::Line::getClassTypeId()); + + std::multiset key; + std::set value; + key.insert(LINE); + hints[key] = DONE; // LINE -> DONE. Line from another line or edge + + key.clear(); value.clear(); + key.insert(POINT); + value.insert(POINT); + hints[key] = value; // POINT -> POINT + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); + hints[key] = DONE; // {POINT, POINT} -> DONE. Line from two points or vertices + + key.clear(); value.clear(); + key.insert(PLANE); + value.insert(PLANE); + hints[key] = value; // PLANE -> PLANE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); + hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +std::map, std::set > Plane::hints = std::map, std::set >(); + +void Plane::initHints() +{ + std::set DONE; + DONE.insert(PartDesign::Plane::getClassTypeId()); + + std::multiset key; + std::set value; + key.insert(PLANE); + hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face + + key.clear(); value.clear(); + key.insert(POINT); + value.insert(POINT); value.insert(LINE); + hints[key] = value; // POINT -> POINT or LINE + + key.clear(); value.clear(); + key.insert(POINT); key.insert(LINE); + hints[key] = DONE; // {POINT, LINE} -> DONE. Plane from point/vertex and line/edge + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); + value.insert(POINT); + hints[key] = value; // {POINT, POINT} -> POINT + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); key.insert(POINT); + hints[key] = DONE; // {POINT, POINT, POINT} -> DONE. Plane from 3 points or vertices + + key.clear(); value.clear(); + key.insert(LINE); + value.insert(POINT); + hints[key] = value; // LINE -> POINT + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +// ============================================================================ + PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) Point::Point() -{ +{ } Point::~Point() @@ -97,8 +260,43 @@ short Point::mustExecute() const App::DocumentObjectExecReturn *Point::execute(void) { + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(PartDesign::Point::getClassTypeId()) != hint.end()))) + return App::DocumentObject::StdReturn; // incomplete references + + // Extract the shapes of the references + std::vector shapes; + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + for (int i = 0; i < refs.size(); i++) { + if (!refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("PartDesign::Point: Invalid reference type"); + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return new App::DocumentObjectExecReturn("PartDesign::Point: Reference has NULL shape"); + if (refnames[i].empty()) { + // Datum feature or App::Plane + shapes.push_back(sh); + } else { + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return new App::DocumentObjectExecReturn("PartDesign::Point: Reference has NULL subshape"); + shapes.push_back(subshape); + } + } + + // Find the point gp_Pnt point(0,0,0); - // TODO: Find the point + + if (shapes.size() == 1) { + // Point from vertex or other point + if (shapes[0].ShapeType() != TopAbs_VERTEX) + return new App::DocumentObjectExecReturn("PartDesign::Point::execute(): Internal error, unexpected ShapeType"); + TopoDS_Vertex v = TopoDS::Vertex(shapes[0]); + //point.X = v. + } BRepBuilderAPI_MakeVertex MakeVertex(point); const TopoDS_Vertex& vertex = MakeVertex.Vertex(); @@ -108,6 +306,15 @@ App::DocumentObjectExecReturn *Point::execute(void) } +const std::set Point::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + + PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) Line::Line() @@ -139,6 +346,15 @@ App::DocumentObjectExecReturn *Line::execute(void) } +const std::set Line::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + + PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) Plane::Plane() @@ -172,3 +388,12 @@ App::DocumentObjectExecReturn *Plane::execute(void) return App::DocumentObject::StdReturn; } + + +const std::set Plane::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index e0c26a62c4f3..7e4f6d7a8511 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -53,10 +53,18 @@ class PartDesignExport Datum : public PartDesign::Feature const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderDatum"; } - //@} + //@} + + virtual const std::set getHint() = 0; protected: void onChanged (const App::Property* prop); + +protected: + std::multiset refTypes; + + static const Base::Type getRefType(const App::DocumentObject* obj, const std::string& subname); + }; class PartDesignExport Point : public PartDesign::Datum @@ -73,6 +81,13 @@ class PartDesignExport Point : public PartDesign::Datum App::DocumentObjectExecReturn *execute(void); short mustExecute() const; //@} + + static void initHints(); + const std::set getHint(); + +private: + // Hints on what further references are required/possible on this feature for a given set of references + static std::map, std::set > hints; }; class PartDesignExport Line : public PartDesign::Datum @@ -89,6 +104,13 @@ class PartDesignExport Line : public PartDesign::Datum App::DocumentObjectExecReturn *execute(void); short mustExecute() const; //@} + + static void initHints(); + const std::set getHint(); + +private: + // Hints on what further references are required/possible on this feature for a given set of references + static std::map, std::set > hints; }; class PartDesignExport Plane : public PartDesign::Datum @@ -104,6 +126,13 @@ class PartDesignExport Plane : public PartDesign::Datum App::DocumentObjectExecReturn *execute(void); short mustExecute() const; //@} + + static void initHints(); + const std::set getHint(); + +private: + // Hints on what further references are required/possible on this feature for a given set of references + static std::map, std::set > hints; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index bd564aad2c15..ca74c343c273 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -433,7 +433,7 @@ void CmdPartDesignPoint::activated(int iMsg) QString refStr = getReferenceString(this); PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); - openCommand("Create a datum plane"); + openCommand("Create a datum point"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Point','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index d4637ae86de8..46e114f56e95 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include "ReferenceSelection.h" @@ -95,9 +96,10 @@ void TaskDatumParameters::makeRefStrings(std::vector& refstrings, std:: } TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("iconName"),tr("Datum parameters"),true, parent),DatumView(DatumView) -{ - TaskBox(Gui::BitmapFactory().pixmap((QString::fromAscii("PartDesign_") + DatumView->datumType).toAscii()), DatumView->datumType + tr(" parameters"), true, parent); + : TaskBox(Gui::BitmapFactory().pixmap((QString::fromAscii("PartDesign_") + DatumView->datumType).toAscii()), + DatumView->datumType + tr(" parameters"), true, parent), + DatumView(DatumView) +{ // we need a separate container widget to add all controls to proxy = new QWidget(this); ui = new Ui_TaskDatumParameters(); @@ -135,16 +137,18 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p // Get the feature data PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); - std::vector refstrings; - makeRefStrings(refstrings, refnames); + //bool checked1 = pcDatum->Checked.getValue(); - std::vector vals = pcDatum->Values.getValues(); + std::vector vals = pcDatum->Values.getValues(); // Fill data into dialog elements ui->spinValue1->setValue(vals[0]); //ui->checkBox1->setChecked(checked1); + std::vector refstrings; + makeRefStrings(refstrings, refnames); ui->lineRef1->setText(refstrings[0]); ui->lineRef1->setProperty("RefName", QByteArray(refnames[0].c_str())); ui->lineRef2->setText(refstrings[1]); @@ -164,10 +168,96 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p updateUI(); } +const QString makeRefText(std::set hint) +{ + QString result; + for (std::set::const_iterator t = hint.begin(); t != hint.end(); t++) { + QString tText; + if (((*t) == Part::Plane::getClassTypeId()) || ((*t) == PartDesign::Plane::getClassTypeId())) + tText = QObject::tr("Plane"); + else if (((*t) == Part::Line::getClassTypeId()) || ((*t) == PartDesign::Line::getClassTypeId())) + tText = QObject::tr("Line"); + else if (((*t) == Part::Vertex::getClassTypeId()) || ((*t) == PartDesign::Point::getClassTypeId())) + tText = QObject::tr("Point"); + result += QString::fromAscii(result.size() == 0 ? "" : "/") + tText; + } + + return result; +} + void TaskDatumParameters::updateUI() { ui->checkBox1->setEnabled(false); - onButtonRef1(true); + + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + std::vector refs = pcDatum->References.getValues(); + completed = false; + + if (refs.size() == 3) { + onButtonRef1(false); // No more references required + completed = true; + return; + } + + // Get hints for further required references + std::set hint = pcDatum->getHint(); + if (hint == std::set()) { + QMessageBox::warning(this, tr("Illegal selection"), tr("This feature cannot be created with this combination of references")); + if (refs.size() == 1) { + onButtonRef1(true); + } else if (refs.size() == 2) { + onButtonRef2(true); + } else if (refs.size() == 3) { + onButtonRef3(true); + } + return; + } + + // Enable the next reference button + if (refs.size() == 0) { + ui->buttonRef2->setEnabled(false); + ui->lineRef2->setEnabled(false); + ui->buttonRef3->setEnabled(false); + ui->lineRef3->setEnabled(false); + } else if (refs.size() == 1) { + ui->buttonRef2->setEnabled(true); + ui->lineRef2->setEnabled(true); + ui->buttonRef3->setEnabled(false); + ui->lineRef3->setEnabled(false); + } else if (refs.size() == 2) { + ui->buttonRef2->setEnabled(true); + ui->lineRef2->setEnabled(true); + ui->buttonRef3->setEnabled(true); + ui->lineRef3->setEnabled(true); + } + + QString refText = makeRefText(hint); + + // Check if we have all required references + if (refText == DatumView->datumType) { + if (refs.size() == 1) { + ui->buttonRef2->setEnabled(false); + ui->lineRef2->setEnabled(false); + ui->buttonRef3->setEnabled(false); + ui->lineRef3->setEnabled(false); + } else if (refs.size() == 2) { + ui->buttonRef3->setEnabled(false); + ui->lineRef3->setEnabled(false); + } + onButtonRef1(false); // No more references required + completed = true; + return; + } + + if (refs.size() == 0) { + onButtonRef1(true); + } else if (refs.size() == 1) { + ui->buttonRef2->setText(refText); + onButtonRef2(true); + } else if (refs.size() == 2) { + ui->buttonRef3->setText(refText); + onButtonRef3(true); + } } QLineEdit* TaskDatumParameters::getLine(const int idx) @@ -196,7 +286,7 @@ void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) if (selObj == pcDatum) return; std::string subname = msg.pSubName; - // Remove subname for planes + // Remove subname for planes and datum features if (selObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || selObj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) subname = ""; @@ -224,15 +314,14 @@ void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) line->blockSignals(false); } - // Turn off reference selection mode - onButtonRef1(false); // Note: It doesn't matter whether we call onButtonRef1 or onButtonRef2 etc. + updateUI(); } } void TaskDatumParameters::onValue1Changed(double val) { PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector vals = pcDatum->Values.getValues(); + std::vector vals = pcDatum->Values.getValues(); vals[0] = val; pcDatum->Values.setValues(vals); pcDatum->getDocument()->recomputeFeature(pcDatum); @@ -307,30 +396,28 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) ui->lineRef2->setProperty("RefName", QByteArray(newrefnames[1].c_str())); ui->lineRef3->setText(refstrings[2]); ui->lineRef3->setProperty("RefName", QByteArray(newrefnames[2].c_str())); + updateUI(); return; } + QStringList parts = text.split(QChar::fromAscii(':')); + if (parts.length() < 2) + parts.push_back(QString::fromAscii("")); // Check whether this is the name of an App::Plane or PartDesign::Datum feature - App::DocumentObject* obj = DatumView->getObject()->getDocument()->getObject(text.toAscii()); - std::string subElement = ""; + App::DocumentObject* obj = DatumView->getObject()->getDocument()->getObject(parts[0].toAscii()); + if (obj == NULL) return; - if (obj != NULL) { - if (!obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - if (!obj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) - return; + std::string subElement; - if (!PartDesignGui::ActivePartObject->hasFeature(obj)) - return; - } // else everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) - } else { - // This is the name of a subelement of the visible solid (Face, Edge, Vertex) - App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); - if (solid == NULL) { - // There is no solid, so we can't select from it... + if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + // everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) + subElement = ""; + } else if (obj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) { + if (!PartDesignGui::ActivePartObject->hasFeature(obj)) return; - } - - // TODO: check validity of the text that was entered: Does it actually reference an element on the solid? + subElement = ""; + } else { + // TODO: check validity of the text that was entered: Does subElement actually reference to an element on the obj? // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. QString name; @@ -339,7 +426,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) std::stringstream ss; str << "^" << tr("Face") << "(\\d+)$"; - if (text.indexOf(rx) < 0) { + if (parts[1].indexOf(rx) < 0) { line->setProperty("RefName", QByteArray()); return; } else { @@ -347,7 +434,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) ss << "Face" << faceId; } str << "^" << tr("Edge") << "(\\d+)$"; - if (text.indexOf(rx) < 0) { + if (parts[1].indexOf(rx) < 0) { line->setProperty("RefName", QByteArray()); return; } else { @@ -355,7 +442,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) ss << "Edge" << lineId; } str << "^" << tr("Vertex") << "(\\d+)$"; - if (text.indexOf(rx) < 0) { + if (parts[1].indexOf(rx) < 0) { line->setProperty("RefName", QByteArray()); return; } else { @@ -377,6 +464,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) refnames.push_back(subElement.c_str()); } pcDatum->References.setValues(refs, refnames); + updateUI(); //pcDatum->getDocument()->recomputeFeature(pcDatum); } @@ -451,6 +539,7 @@ void TaskDatumParameters::changeEvent(QEvent *e) ui->lineRef1->setText(refstrings[0]); ui->lineRef2->setText(refstrings[1]); ui->lineRef3->setText(refstrings[2]); + // TODO: Translate DatumView->datumType ? ui->spinValue1->blockSignals(false); ui->checkBox1->blockSignals(false); @@ -497,6 +586,11 @@ void TaskDlgDatumParameters::clicked(int) bool TaskDlgDatumParameters::accept() { + if (!parameter->isCompleted()) { + QMessageBox::warning(parameter, tr("Not enough references"), tr("Please select further references to complete this feature")); + return false; + } + std::string name = DatumView->getObject()->getNameInDocument(); try { diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.h b/src/Mod/PartDesign/Gui/TaskDatumParameters.h index 9936172d482e..c2ea01ba5e3e 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.h @@ -56,6 +56,7 @@ class TaskDatumParameters : public Gui::TaskView::TaskBox, public Gui::Selection QString getReference(const int idx) const; double getValue1(void) const; bool getCheck1(void) const; + const bool isCompleted() const { return completed; } private Q_SLOTS: void onValue1Changed(double); @@ -85,6 +86,7 @@ private Q_SLOTS: ViewProviderDatum *DatumView; int refSelectionMode; + bool completed; }; From efd33c846505f29de2376d2128a0eb5f0731df80 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 17 Apr 2013 19:49:55 +0430 Subject: [PATCH 081/664] Added check in Tree.cpp DocumentItem::slotChangeObject to check for invalid pointers returned by claimChildren() --- src/App/Document.cpp | 10 ++++++++++ src/App/Document.h | 2 ++ src/Gui/Tree.cpp | 44 +++++++++++++++++++++++++------------------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index f1cf43b00d9e..8238964c4e51 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -2294,6 +2294,16 @@ DocumentObject * Document::getObject(const char *Name) const return 0; } +// Note: This method is only used in Tree.cpp slotChangeObject(), see explanation there +const bool Document::isIn(const DocumentObject *pFeat) const +{ + for (std::map::const_iterator o = d->objectMap.begin(); o != d->objectMap.end(); o++) + if (o->second == pFeat) + return true; + + return false; +} + const char * Document::getObjectName(DocumentObject *pFeat) const { std::map::const_iterator pos; diff --git a/src/App/Document.h b/src/App/Document.h index 1402f7cc41bf..7d1b1d921a6c 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -192,6 +192,8 @@ class AppExport Document : public App::PropertyContainer DocumentObject *getActiveObject(void) const; /// Returns a Object of this document DocumentObject *getObject(const char *Name) const; + /// Returns true if the DocumentObject is contained in this document + const bool isIn(const DocumentObject *pFeat) const; /// Returns a Name of an Object or 0 const char *getObjectName(DocumentObject *pFeat) const; /// Returns a Name of an Object or 0 diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index b267fd12bd75..44fb602660d4 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -943,25 +943,31 @@ void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view) std::string objectName = obj->getNameInDocument(); std::map::iterator it = ObjectMap.find(objectName); if (it != ObjectMap.end()) { - // use new grouping style - std::set children; - std::vector group = view.claimChildren(); - for (std::vector::iterator jt = group.begin(); jt != group.end(); ++jt) { - if (*jt) { - const char* internalName = (*jt)->getNameInDocument(); - if (internalName) { - std::map::iterator kt = ObjectMap.find(internalName); - if (kt != ObjectMap.end()) { - children.insert(kt->second); - QTreeWidgetItem* parent = kt->second->parent(); - if (parent && parent != it->second) { - if (it->second != kt->second) { - int index = parent->indexOfChild(kt->second); - parent->takeChild(index); - it->second->addChild(kt->second); - } - else { - Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Object references to itself.\n"); + // use new grouping style + std::set children; + std::vector group = view.claimChildren(); + for (std::vector::iterator jt = group.begin(); jt != group.end(); ++jt) { + if ((*jt) && view.getObject()->getDocument()->isIn(*jt)){ + // Note: It is possible that we receive an invalid pointer from claimChildren(), e.g. if multiple properties + // were changed in a transaction and slotChangedObject() is triggered by one property being reset + // before the invalid pointer has been removed from another. Currently this happens for PartDesign::Body + // when cancelling a new feature in the dialog. First the new feature is deleted, then the Tip property is + // reset, but claimChildren() accesses the Model property which still contains the pointer to the deleted feature + const char* internalName = (*jt)->getNameInDocument(); + if (internalName) { + std::map::iterator kt = ObjectMap.find(internalName); + if (kt != ObjectMap.end()) { + children.insert(kt->second); + QTreeWidgetItem* parent = kt->second->parent(); + if (parent && parent != it->second) { + if (it->second != kt->second) { + int index = parent->indexOfChild(kt->second); + parent->takeChild(index); + it->second->addChild(kt->second); + } + else { + Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Object references to itself.\n"); + } } } } From 1b7fbeb622f6a9231b50451f2db216ab1defd2a1 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 18 Apr 2013 17:24:33 +0430 Subject: [PATCH 082/664] Update ActivePartObject etc. on switching documents, creating new documents, and loading documents in the PartDesign workbench --- src/Mod/PartDesign/Gui/Command.cpp | 2 +- src/Mod/PartDesign/Gui/Workbench.cpp | 74 ++++++++++++++++++--------- src/Mod/PartDesign/Gui/Workbench.h | 5 ++ src/Mod/Start/StartPage/PartDesign.py | 1 - 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index ca74c343c273..8430d0fed27f 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -749,7 +749,6 @@ void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch ,grp->getNameInDocument(),sketch->getNameInDocument()); } - cmd->updateActive(); PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (cmd->isActiveObjectValid()) { cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); @@ -759,6 +758,7 @@ void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); } } + cmd->updateActive(); // #0001721: use '0' as edit value to avoid switching off selection in // ViewProviderGeometryObject::setEditViewer cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index b4a0538f84d9..eb4bead40d7f 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -25,17 +25,20 @@ #ifndef _PreComp_ # include +# include #endif #include "Workbench.h" -#include +#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -75,12 +78,57 @@ TYPESYSTEM_SOURCE(PartDesignGui::Workbench, Gui::StdWorkbench) Workbench::Workbench() { + // Let us be notified when a document is activated, so that we can update the ActivePartObject + Gui::Application::Instance->signalActiveDocument.connect(boost::bind(&Workbench::slotActiveDocument, this, _1)); + App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, _1)); + App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); } Workbench::~Workbench() { } +void switchToDocument(const App::Document* doc) +{ + if (doc == NULL) return; + + PartDesign::Body* activeBody = NULL; + std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); + + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->IsActive.getValue()) { + activeBody = body; + break; + } + } + + // If there is only one body, make it active + if ((activeBody == NULL) && (bodies.size() == 1)) + activeBody = static_cast(bodies.front()); + + if (activeBody != NULL) { + Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); + } +} + +void Workbench::slotActiveDocument(const Gui::Document& Doc) +{ + switchToDocument(Doc.getDocument()); +} + +void Workbench::slotNewDocument(const App::Document& Doc) +{ + Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); + switchToDocument(&Doc); +} + +void Workbench::slotFinishRestoreDocument(const App::Document& Doc) +{ + switchToDocument(&Doc); +} + void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const { if (strcmp(recipient,"Tree") == 0) @@ -249,28 +297,7 @@ void Workbench::activated() )); // make the previously used active Body active again - PartDesign::Body* activeBody = NULL; - App::Document* activeDocument = App::GetApplication().getActiveDocument(); - if (activeDocument != NULL) { - std::vector bodies = activeDocument->getObjectsOfType(PartDesign::Body::getClassTypeId()); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { - PartDesign::Body* body = static_cast(*b); - if (body->IsActive.getValue()) { - activeBody = body; - break; - } - } - - // If there is only one body, make it active - if ((activeBody == NULL) && (bodies.size() == 1)) - activeBody = static_cast(bodies.front()); - } - - - if (activeBody != NULL) { - Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); - Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); - } + switchToDocument(App::GetApplication().getActiveDocument()); addTaskWatcher(Watcher); Gui::Control().showTaskView(); @@ -287,7 +314,6 @@ void Workbench::deactivated() Gui::Workbench::deactivated(); - } Gui::MenuItem* Workbench::setupMenuBar() const diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index c2e3d0f28559..51d1c5b3d0fc 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -74,6 +74,11 @@ class PartDesignGuiExport Workbench : public Gui::StdWorkbench Gui::MenuItem* setupMenuBar() const; Gui::ToolBarItem* setupToolBars() const; Gui::ToolBarItem* setupCommandBars() const; + +private: + void slotActiveDocument(const Gui::Document&); + void slotFinishRestoreDocument(const App::Document&); + void slotNewDocument(const App::Document&); }; } // namespace PartDesignGui diff --git a/src/Mod/Start/StartPage/PartDesign.py b/src/Mod/Start/StartPage/PartDesign.py index bf59c27db1d2..fc77976f6dd6 100644 --- a/src/Mod/Start/StartPage/PartDesign.py +++ b/src/Mod/Start/StartPage/PartDesign.py @@ -24,7 +24,6 @@ import FreeCADGui FreeCADGui.activateWorkbench("PartDesignWorkbench") App.newDocument() -FreeCADGui.runCommand('PartDesign_Body') # Make the planes properly visible FreeCADGui.activeDocument().activeView().viewAxometric() FreeCADGui.SendMsgToActiveView("ViewFit") From 4bb14de504a07deec611d1f7ca53347ee59c165e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 19 Apr 2013 14:41:40 +0430 Subject: [PATCH 083/664] Honour the ordering of the children returned by claimChildren() in the TreeWidget --- src/Gui/Tree.cpp | 49 +++++++++++++-------- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 15 +++---- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 44fb602660d4..6b80f63b184f 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -944,8 +944,10 @@ void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view) std::map::iterator it = ObjectMap.find(objectName); if (it != ObjectMap.end()) { // use new grouping style + DocumentObjectItem* parent_of_group = it->second; std::set children; std::vector group = view.claimChildren(); + int group_index = 0; for (std::vector::iterator jt = group.begin(); jt != group.end(); ++jt) { if ((*jt) && view.getObject()->getDocument()->isIn(*jt)){ // Note: It is possible that we receive an invalid pointer from claimChildren(), e.g. if multiple properties @@ -957,13 +959,20 @@ void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view) if (internalName) { std::map::iterator kt = ObjectMap.find(internalName); if (kt != ObjectMap.end()) { - children.insert(kt->second); - QTreeWidgetItem* parent = kt->second->parent(); - if (parent && parent != it->second) { - if (it->second != kt->second) { - int index = parent->indexOfChild(kt->second); - parent->takeChild(index); - it->second->addChild(kt->second); + DocumentObjectItem* child_of_group = kt->second; + children.insert(child_of_group); + QTreeWidgetItem* parent_of_child = child_of_group->parent(); + if (parent_of_child && parent_of_child != parent_of_group) { + if (parent_of_group != child_of_group) { + // This child's parent must be adjusted + int index = parent_of_child->indexOfChild(child_of_group); + parent_of_child->takeChild(index); + // Insert the child at the correct position according to the order of the children returned + // by claimChildren + if (group_index <= parent_of_group->childCount()) + parent_of_group->insertChild(group_index, child_of_group); + else + parent_of_group->addChild(child_of_group); } else { Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Object references to itself.\n"); @@ -978,21 +987,23 @@ void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view) else { Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Group references unknown object.\n"); } + + group_index++; } - } - // move all children which are not part of the group anymore to this item - int count = it->second->childCount(); - for (int i=0; i < count; i++) { - QTreeWidgetItem* child = it->second->child(i); - if (children.find(child) == children.end()) { - it->second->takeChild(i); - this->addChild(child); + + // move all children which are not part of the group anymore to this item + int count = parent_of_group->childCount(); + for (int i=0; i < count; i++) { + QTreeWidgetItem* child = parent_of_group->child(i); + if (children.find(child) == children.end()) { + parent_of_group->takeChild(i); + this->addChild(child); + } } - } - // set the text label - std::string displayName = obj->Label.getValue(); - it->second->setText(0, QString::fromUtf8(displayName.c_str())); + // set the text label + std::string displayName = obj->Label.getValue(); + parent_of_group->setText(0, QString::fromUtf8(displayName.c_str())); } else { Base::Console().Warning("Gui::DocumentItem::slotChangedObject(): Cannot change unknown object.\n"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index f7629efb5a0c..d92e135a377b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -120,16 +120,15 @@ std::vector ViewProviderBody::claimChildren(void)const } } - // remove the otherwise handled objects - std::vector Result(Model.size()); - sort (Model.begin(), Model.end()); - std::vector::iterator it = set_difference (Model.begin(), Model.end(), OutSet.begin(),OutSet.end(), Result.begin()); + // remove the otherwise handled objects, preserving their order so the order in the TreeWidget is correct + std::vector Result; + for (std::vector::const_iterator it = Model.begin();it!=Model.end();++it) { + if (OutSet.find(*it) == OutSet.end()) + Result.push_back(*it); + } - //Base::Console().Error("Body claimed children:\n"); - //for (std::vector::const_iterator o = Result.begin(); o != it; o++) - // Base::Console().Error("%s\n", (*o)->getNameInDocument()); // return the rest as claim set of the Body - return std::vector(Result.begin(),it); + return Result; } From 7330d4357e68b2bdf4e7973c66de6eff44fef1f4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 21 Apr 2013 09:24:12 +0430 Subject: [PATCH 084/664] Made the rest of the PartDesign features aware of the Body --- src/Mod/PartDesign/App/FeatureChamfer.cpp | 12 +- src/Mod/PartDesign/App/FeatureDraft.cpp | 8 +- src/Mod/PartDesign/App/FeatureDressUp.cpp | 8 +- .../PartDesign/App/FeatureDressUp.cpp.orig | 73 ++ src/Mod/PartDesign/App/FeatureDressUp.h | 4 +- src/Mod/PartDesign/App/FeatureFillet.cpp | 9 +- src/Mod/PartDesign/App/FeatureTransformed.cpp | 17 +- src/Mod/PartDesign/Gui/Command.cpp | 380 +++---- src/Mod/PartDesign/Gui/Command.cpp.orig | 999 +++++++++++------- .../PartDesign/Gui/TaskChamferParameters.cpp | 21 +- .../PartDesign/Gui/TaskDraftParameters.cpp | 21 +- .../PartDesign/Gui/TaskFilletParameters.cpp | 21 +- .../Gui/TaskMultiTransformParameters.cpp | 13 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 2 +- .../Gui/TaskTransformedParameters.cpp | 22 +- .../PartDesign/Gui/ViewProviderChamfer.cpp | 15 +- src/Mod/PartDesign/Gui/ViewProviderDraft.cpp | 15 +- src/Mod/PartDesign/Gui/ViewProviderFillet.cpp | 15 +- .../Gui/ViewProviderTransformed.cpp | 14 +- 19 files changed, 923 insertions(+), 746 deletions(-) create mode 100644 src/Mod/PartDesign/App/FeatureDressUp.cpp.orig diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp index 4b489affa98c..77d3bb10e0d4 100644 --- a/src/Mod/PartDesign/App/FeatureChamfer.cpp +++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp @@ -64,12 +64,16 @@ short Chamfer::mustExecute() const App::DocumentObjectExecReturn *Chamfer::execute(void) { - App::DocumentObject* link = Base.getValue(); + // NOTE: Normally the Base property and the BaseFeature property should point to the same object. + // The only difference is that the Base property also stores the edges that are to be chamfered + App::DocumentObject* link = BaseFeature.getValue(); + if (!link) + link = Base.getValue(); // For legacy features if (!link) return new App::DocumentObjectExecReturn("No object linked"); if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a Part object"); - Part::Feature *base = static_cast(Base.getValue()); + Part::Feature *base = static_cast(link); const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()) return new App::DocumentObjectExecReturn("Cannot chamfer invalid shape"); @@ -80,8 +84,8 @@ App::DocumentObjectExecReturn *Chamfer::execute(void) double size = Size.getValue(); - this->positionByBase(); - // create an untransformed copy of the base shape + this->positionByBaseFeature(); + // create an untransformed copy of the basefeature shape Part::TopoShape baseShape(TopShape); baseShape.setTransform(Base::Matrix4D()); try { diff --git a/src/Mod/PartDesign/App/FeatureDraft.cpp b/src/Mod/PartDesign/App/FeatureDraft.cpp index 81e8fd63c7bf..eda4e4bf2efa 100644 --- a/src/Mod/PartDesign/App/FeatureDraft.cpp +++ b/src/Mod/PartDesign/App/FeatureDraft.cpp @@ -87,12 +87,14 @@ App::DocumentObjectExecReturn *Draft::execute(void) { // Get parameters // Base shape - App::DocumentObject* link = Base.getValue(); + App::DocumentObject* link = BaseFeature.getValue(); + if (!link) + link = Base.getValue(); // For legacy features if (!link) return new App::DocumentObjectExecReturn("No object linked"); if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a Part object"); - Part::Feature *base = static_cast(Base.getValue()); + Part::Feature *base = static_cast(link); const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()) return new App::DocumentObjectExecReturn("Cannot draft invalid shape"); @@ -239,7 +241,7 @@ App::DocumentObjectExecReturn *Draft::execute(void) if (reversed) angle *= -1.0; - this->positionByBase(); + this->positionByBaseFeature(); // create an untransformed copy of the base shape Part::TopoShape baseShape(TopShape); baseShape.setTransform(Base::Matrix4D()); diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp b/src/Mod/PartDesign/App/FeatureDressUp.cpp index 4abaedf53d5d..b6f92218f583 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.cpp +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp @@ -49,18 +49,18 @@ short DressUp::mustExecute() const } -void DressUp::positionByBase(void) +void DressUp::positionByBaseFeature(void) { - Part::Feature *base = static_cast(Base.getValue()); + Part::Feature *base = static_cast(BaseFeature.getValue()); if (base && base->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) this->Placement.setValue(base->Placement.getValue()); } void DressUp::onChanged(const App::Property* prop) { - if (prop == &Base) { + if (prop == &BaseFeature) { // if attached to a sketch then mark it as read-only - this->Placement.setStatus(App::Property::ReadOnly, Base.getValue() != 0); + this->Placement.setStatus(App::Property::ReadOnly, BaseFeature.getValue() != 0); } Feature::onChanged(prop); diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp.orig b/src/Mod/PartDesign/App/FeatureDressUp.cpp.orig new file mode 100644 index 000000000000..1c0bbfbda30d --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp.orig @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 "FeatureDressUp.h" + + +using namespace PartDesign; + +namespace PartDesign { + + +PROPERTY_SOURCE(PartDesign::DressUp, PartDesign::Feature) + +DressUp::DressUp() +{ + ADD_PROPERTY(Base,(0)); +} + +short DressUp::mustExecute() const +{ + if (Base.getValue() && Base.getValue()->isTouched()) + return 1; + return PartDesign::Feature::mustExecute(); +} + + +void DressUp::positionByBaseFeature(void) +{ + Part::Feature *base = static_cast(BaseFeature.getValue()); + if (base && base->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + this->Placement.setValue(base->Placement.getValue()); +} + +void DressUp::onChanged(const App::Property* prop) +{ + if (prop == &BaseFeature) { + // if attached to a sketch then mark it as read-only +<<<<<<< 9a36c6ffa0c7768669f16ea256e11820bfea6b82 + this->Placement.setStatus(App::Property::ReadOnly, Base.getValue() != 0); +======= + this->Placement.StatusBits.set(2, BaseFeature.getValue() != 0); +>>>>>>> Made the rest of the PartDesign features aware of the Body + } + + Feature::onChanged(prop); +} + +} diff --git a/src/Mod/PartDesign/App/FeatureDressUp.h b/src/Mod/PartDesign/App/FeatureDressUp.h index 52aa6b335f1f..81e8a556d30c 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.h +++ b/src/Mod/PartDesign/App/FeatureDressUp.h @@ -40,8 +40,8 @@ class PartDesignExport DressUp : public PartDesign::Feature App::PropertyLinkSub Base; short mustExecute() const; - /// updates the Placement property from the Placement of Base - void positionByBase(void); + /// updates the Placement property from the Placement of the BaseFeature + void positionByBaseFeature(void); protected: void onChanged(const App::Property* prop); diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp index f6513cf4562b..d0ba0622255c 100644 --- a/src/Mod/PartDesign/App/FeatureFillet.cpp +++ b/src/Mod/PartDesign/App/FeatureFillet.cpp @@ -61,12 +61,14 @@ short Fillet::mustExecute() const App::DocumentObjectExecReturn *Fillet::execute(void) { - App::DocumentObject* link = Base.getValue(); + App::DocumentObject* link = BaseFeature.getValue(); + if (!link) + link = Base.getValue(); // For legacy features if (!link) return new App::DocumentObjectExecReturn("No object linked"); if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Linked object is not a Part object"); - Part::Feature *base = static_cast(Base.getValue()); + Part::Feature *base = static_cast(link); const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()) return new App::DocumentObjectExecReturn("Cannot fillet invalid shape"); @@ -77,7 +79,8 @@ App::DocumentObjectExecReturn *Fillet::execute(void) double radius = Radius.getValue(); - this->positionByBase(); + this->positionByBaseFeature(); + // create an untransformed copy of the base shape Part::TopoShape baseShape(TopShape); baseShape.setTransform(Base::Matrix4D()); diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index 1d3534b048e8..679ebaa11494 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -72,10 +72,14 @@ void Transformed::positionBySupport(void) App::DocumentObject* Transformed::getSupportObject() const { - if (!Originals.getValues().empty()) - return Originals.getValues().front(); - else - return NULL; + if (BaseFeature.getValue() != NULL) + return BaseFeature.getValue(); + else { + if (!Originals.getValues().empty()) + return Originals.getValues().front(); // For legacy features + else + return NULL; + } } App::DocumentObject* Transformed::getSketchObject() const @@ -186,10 +190,9 @@ App::DocumentObjectExecReturn *Transformed::execute(void) return App::DocumentObject::StdReturn; // No transformations defined, exit silently // Get the support - // NOTE: Because of the way we define the support, FeatureTransformed can only work on - // one Body feature at a time - // TODO: Currently, the support is simply the first Original. Change this to the Body feature later Part::Feature* supportFeature = static_cast(getSupportObject()); + if (supportFeature == NULL) + return new App::DocumentObjectExecReturn("No support for transformation feature"); const Part::TopoShape& supportTopShape = supportFeature->Shape.getShape(); if (supportTopShape._Shape.IsNull()) return new App::DocumentObjectExecReturn("Cannot transform invalid support shape"); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 8430d0fed27f..15c8657eb8d8 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -23,6 +23,12 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include +# include +# include +# include # include # include # include @@ -55,10 +61,13 @@ #include #include + #include #include #include #include +#include +#include #include #include @@ -626,6 +635,36 @@ bool CmdPartDesignNewSketch::isActive(void) return false; } +//=========================================================================== +// Common utility functions for all features creating solids +//=========================================================================== + +void finishFeature(const Gui::Command* cmd, const std::string& FeatName) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + + if (cmd->isActiveObjectValid() && (pcActiveBody != NULL)) { + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); + if (prevSolidFeature != NULL) + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + } + cmd->updateActive(); + // #0001721: use '0' as edit value to avoid switching off selection in + // ViewProviderGeometryObject::setEditViewer + cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); + //cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); + + if (pcActiveBody) { + cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); + } +} + //=========================================================================== // Common utility functions for SketchBased features //=========================================================================== @@ -735,41 +774,14 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2 which.c_str(), FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", FeatName.c_str(), sketch->getNameInDocument()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", - pcActiveBody->getNameInDocument(), FeatName.c_str()); } void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); - if (cmd->isActiveObjectValid()) { + if (cmd->isActiveObjectValid()) cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - if (pcActiveBody != NULL) { - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); - if (prevSolidFeature != NULL) - cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); - } - } - cmd->updateActive(); - // #0001721: use '0' as edit value to avoid switching off selection in - // ViewProviderGeometryObject::setEditViewer - cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); - cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); - cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); - if (pcActiveBody) { - cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - } + finishFeature(cmd, FeatName); } //=========================================================================== @@ -924,25 +936,16 @@ bool CmdPartDesignGroove::isActive(void) } //=========================================================================== -// PartDesign_Fillet +// Common utility functions for Dressup features //=========================================================================== -DEF_STD_CMD_A(CmdPartDesignFillet); -CmdPartDesignFillet::CmdPartDesignFillet() - :Command("PartDesign_Fillet") +void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) { - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Fillet"); - sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); - sWhatsThis = "PartDesign_Fillet"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Fillet"; -} + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) + return; -void CmdPartDesignFillet::activated(int iMsg) -{ - std::vector selection = getSelection().getSelectionEx(); + std::vector selection = cmd->getSelection().getSelectionEx(); if (selection.size() != 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -952,7 +955,7 @@ void CmdPartDesignFillet::activated(int iMsg) if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Fillet works only on parts.")); + QString::fromStdString(which) + QObject::tr(" works only on parts.")); return; } @@ -1032,13 +1035,13 @@ void CmdPartDesignFillet::activated(int iMsg) if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No fillet possible on selected faces/edges.")); + QString::fromStdString(which) + QObject::tr(" not possible on selected faces/edges.")); return; } std::string SelString; SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "ActiveDocument"; SelString += "."; SelString += selection[0].getFeatName(); SelString += ",["; @@ -1051,23 +1054,35 @@ void CmdPartDesignFillet::activated(int iMsg) } SelString += "])"; - std::string FeatName = getUniqueObjectName("Fillet"); + std::string FeatName = cmd->getUniqueObjectName(which.c_str()); - openCommand("Make Fillet"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + cmd->openCommand((std::string("Make ") + which).c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } + finishFeature(cmd, FeatName); +} + +//=========================================================================== +// PartDesign_Fillet +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignFillet); + +CmdPartDesignFillet::CmdPartDesignFillet() + :Command("PartDesign_Fillet") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Fillet"); + sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); + sWhatsThis = "PartDesign_Fillet"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Fillet"; +} - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +void CmdPartDesignFillet::activated(int iMsg) +{ + makeChamferOrFillet(this, "Fillet"); } bool CmdPartDesignFillet::isActive(void) @@ -1094,133 +1109,8 @@ CmdPartDesignChamfer::CmdPartDesignChamfer() void CmdPartDesignChamfer::activated(int iMsg) { - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select an edge, face or body. Only one body is allowed.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Chamfer works only on parts.")); - return; - } - - Part::Feature *base = static_cast(selection[0].getObject()); - - const Part::TopoShape& TopShape = base->Shape.getShape(); - - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - - std::vector SubNames = std::vector(selection[0].getSubNames()); - - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { - TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); - const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); - - if(los.Extent() != 2) - { - SubNames.erase(SubNames.begin()+i); - continue; - } - - const TopoDS_Shape& face1 = los.First(); - const TopoDS_Shape& face2 = los.Last(); - GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), - TopoDS::Face(face1), - TopoDS::Face(face2)); - if (cont != GeomAbs_C0) { - SubNames.erase(SubNames.begin()+i); - continue; - } - - i++; - } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - - TopTools_IndexedMapOfShape mapOfFaces; - TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); - - for(int j = 1; j <= mapOfFaces.Extent(); ++j) { - TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); - - int id = mapOfEdges.FindIndex(edge); - - std::stringstream buf; - buf << "Edge"; - buf << id; - - if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) - { - SubNames.push_back(buf.str()); - } - - } - - SubNames.erase(SubNames.begin()+i); - } - // empty name or any other sub-element - else { - SubNames.erase(SubNames.begin()+i); - } - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No chamfer possible on selected faces/edges.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - - std::string FeatName = getUniqueObjectName("Chamfer"); - - openCommand("Make Chamfer"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); + makeChamferOrFillet(this, "Chamfer"); doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); } bool CmdPartDesignChamfer::isActive(void) @@ -1247,6 +1137,9 @@ CmdPartDesignDraft::CmdPartDesignDraft() void CmdPartDesignDraft::activated(int iMsg) { + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) return; + std::vector selection = getSelection().getSelectionEx(); if (selection.size() < 1) { @@ -1263,6 +1156,12 @@ void CmdPartDesignDraft::activated(int iMsg) Part::Feature *base = static_cast(selection[0].getObject()); + if (base != pcActiveBody->Tip.getValue()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), + QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); + return; + } + const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -1323,20 +1222,8 @@ void CmdPartDesignDraft::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); + finishFeature(this, FeatName); } bool CmdPartDesignDraft::isActive(void) @@ -1379,7 +1266,7 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, } } - FeatName = cmd->getUniqueObjectName("Mirrored"); + FeatName = cmd->getUniqueObjectName(which.c_str()); std::stringstream str; str << "App.activeDocument()." << FeatName << ".Originals = ["; @@ -1389,6 +1276,21 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, } str << "]"; selNames = str.str(); + + cmd->openCommand((std::string("Make ") + which + " feature").c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like + // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' + cmd->updateActive(); // Helps to ensure that the object already exists when the next command comes up + cmd->doCommand(cmd->Doc,selNames.c_str()); +} + +void finishTransformed(Gui::Command* cmd, std::string& FeatName, std::vector& selList) +{ + //for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) + // cmd->doCommand(cmd->Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + finishFeature(cmd, FeatName); } //=========================================================================== @@ -1417,23 +1319,12 @@ void CmdPartDesignMirrored::activated(int iMsg) if (features.empty()) return; - openCommand("Mirrored"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); - // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like - // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' - updateActive(); // Helps to ensure that the object already exists when the next command comes up - doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignMirrored::isActive(void) @@ -1467,30 +1358,14 @@ void CmdPartDesignLinearPattern::activated(int iMsg) if (features.empty()) return; - openCommand("LinearPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignLinearPattern::isActive(void) @@ -1524,30 +1399,14 @@ void CmdPartDesignPolarPattern::activated(int iMsg) if (features.empty()) return; - openCommand("PolarPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignPolarPattern::isActive(void) @@ -1581,19 +1440,10 @@ void CmdPartDesignScaled::activated(int iMsg) if (features.empty()) return; - openCommand("Scaled"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,selNames.c_str()); doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignScaled::isActive(void) @@ -1627,15 +1477,21 @@ void CmdPartDesignMultiTransform::activated(int iMsg) if (features.empty()) return; - openCommand("MultiTransform"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) + return; updateActive(); doCommand(Doc,selNames.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + // Make sure the user isn't presented with an empty screen because no transformations are defined yet... + App::DocumentObject* prevSolid = pcActiveBody->getPrevSolidFeature(NULL, true); + if (prevSolid != NULL) { + Part::Feature* feat = static_cast(prevSolid); + doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", + FeatName.c_str(), feat->getNameInDocument()); + } - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishFeature(this, FeatName); } bool CmdPartDesignMultiTransform::isActive(void) diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig index e127dffa8ff3..e8d3ba8e22cf 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp.orig +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -23,6 +23,12 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include +# include +# include +# include # include # include # include @@ -41,6 +47,7 @@ #include #include +#include #include #include #include @@ -48,39 +55,413 @@ #include #include #include +#include +#include +#include +#include #include + #include +#include #include #include +#include +#include #include #include #include "FeaturePickDialog.h" +#include "Workbench.h" using namespace std; -extern PartDesign::Body *ActivePartObject; +const char* BasePlaneNames[3] = {"Body_PlaneXY", "Body_PlaneYZ", "Body_PlaneXZ"}; + +//=========================================================================== +// PartDesign_Body +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignBody); + +CmdPartDesignBody::CmdPartDesignBody() + : Command("PartDesign_Body") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create body"); + sToolTipText = QT_TR_NOOP("Create a new body feature"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Body"; +} + +void CmdPartDesignBody::activated(int iMsg) +{ + openCommand("Add a body feature"); + std::string FeatName = getUniqueObjectName("Body"); + + // add the standard planes at the root of the feature tree + // first check if they already exist + // FIXME: If the user renames them, they won't be found... + bool found = false; + std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { + for (unsigned i = 0; i < 3; i++) { + if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + found = true; + break; + } + } + if (found) break; + } + + if (!found) { + // Add the planes ... + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[0]); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[1]); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'"); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[2]); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'"); + // ... and put them in the 'Origin' group + doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','Origin')"); + for (unsigned i = 0; i < 3; i++) + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", BasePlaneNames[i]); + // TODO: Fold the group (is that possible through the Python interface?) + } + + // add the Body feature itself, and make it active + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); + doCommand(Doc,"import PartDesignGui"); + doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); + // Make the "Create sketch" prompt appear in the task panel + doCommand(Gui,"Gui.Selection.clearSelection()"); + doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); + + updateActive(); +} + +bool CmdPartDesignBody::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_MoveTip +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignMoveTip); + +CmdPartDesignMoveTip::CmdPartDesignMoveTip() + : Command("PartDesign_MoveTip") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Insert here"); + sToolTipText = QT_TR_NOOP("Move insert point to selected feature"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_MoveTip"; +} + +void CmdPartDesignMoveTip::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + App::DocumentObject* selFeature = features.front(); + + if (!pcActiveBody->hasFeature(selFeature)) { + // Switch to other body + pcActiveBody = PartDesign::Body::findBodyOf(selFeature); + if (pcActiveBody != NULL) + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", + pcActiveBody->getNameInDocument()); + } + + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if (prevSolidFeature != NULL) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + + openCommand("Move insert point to selected feature"); + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); + + // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); + prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); +} + +bool CmdPartDesignMoveTip::isActive(void) +{ + return hasActiveDocument(); +} //=========================================================================== -// Helper for Body +// PartDesign_Datum //=========================================================================== -PartDesign::Body *getBody(void) +const QString getReferenceString(Gui::Command* cmd) { - if(!ActivePartObject){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Body"), - QObject::tr("In order to use PartDesign you need an active Body object in the document. " - "Please make one active or create one. If you have a legacy document " - "with PartDesign objects without Body, use the transfer function in " - "PartDesign to put them into a Body." - )); + QString referenceString; + + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return QString::fromAscii(""); + + Gui::SelectionFilter GeometryFilter("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter EdgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1"); + Gui::SelectionFilter VertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 1"); + Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); + + if (EdgeFilter.match()) + GeometryFilter = EdgeFilter; + else if (VertexFilter.match()) + GeometryFilter = VertexFilter; + if (PlaneFilter2.match()) + PlaneFilter = PlaneFilter2; + + if (GeometryFilter.match() || PlaneFilter.match()) { + // get the selected object + if (GeometryFilter.match()) { + Part::Feature *part = static_cast(GeometryFilter.Result[0][0].getObject()); + // FIXME: Reject or warn about feature that is outside of active body, and feature + // that comes after the current insert point (Tip) + const std::vector &sub = GeometryFilter.Result[0][0].getSubNames(); + referenceString = QString::fromAscii("["); + + for (int r = 0; r != sub.size(); r++) { + // get the selected sub shape + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[r].c_str()); + if (!sh.IsNull()) { + referenceString += QString::fromAscii(r == 0 ? "" : ",") + + QString::fromAscii("(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + + QString::fromAscii(",'") + QString::fromStdString(sub[r]) + QString::fromAscii("')"); + } + } + + referenceString += QString::fromAscii("]"); + if (referenceString.length() == 2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No sub shape selected"), + QObject::tr("You have to select a face, edge, vertex or plane to define a datum feature!")); + return QString::fromAscii(""); + } + + return referenceString; + } else { + Part::Feature *part = static_cast(PlaneFilter.Result[0][0].getObject()); + return QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + + QString::fromAscii(",'')]"); + } } - return ActivePartObject; + else { + // Get a valid datum feature from the user + std::vector status; + std::vector refs = cmd->getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + std::vector refstmp = cmd->getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId()); + refs.insert(refs.end(), refstmp.begin(), refstmp.end()); + refstmp = cmd->getDocument()->getObjectsOfType(PartDesign::Line::getClassTypeId()); + refs.insert(refs.end(), refstmp.begin(), refstmp.end()); + refstmp = cmd->getDocument()->getObjectsOfType(PartDesign::Point::getClassTypeId()); + refs.insert(refs.end(), refstmp.begin(), refstmp.end()); + + unsigned validRefs = 0; + std::vector chosenRefs; + + for (std::vector::iterator r = refs.begin(); r != refs.end(); r++) { + // Check whether this reference is a base plane + bool base = false; + for (unsigned i = 0; i < 3; i++) { + if (strcmp(BasePlaneNames[i], (*r)->getNameInDocument()) == 0) { + status.push_back(PartDesignGui::FeaturePickDialog::basePlane); + if (chosenRefs.empty()) + chosenRefs.push_back(*r); + validRefs++; + base = true; + break; + } + } + if (base) continue; + + // Check whether this reference belongs to the active body + PartDesign::Body* body = PartDesignGui::getBody(); + if (!body->hasFeature(*r)) { + status.push_back(PartDesignGui::FeaturePickDialog::otherBody); + continue; + } else { + if (body->isAfterTip(*r)) + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + continue; + } + + // All checks passed - found a valid reference + if (chosenRefs.empty()) + chosenRefs.push_back(*r); + validRefs++; + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); + } + + if (validRefs == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid references in this document"), + QObject::tr("Please select a face, edge or vertex")); + return QString::fromAscii(""); + } + + // If there is more than one possibility, show dialog and let user pick references + if (validRefs > 1) { + PartDesignGui::FeaturePickDialog Dlg(refs, status); + if ((Dlg.exec() != QDialog::Accepted) || (chosenRefs = Dlg.getFeatures()).empty()) + return QString::fromAscii(""); // Cancelled or nothing selected + if (chosenRefs.size() > 3) + Base::Console().Warning("You have chosen more than three references for a datum feature. The extra references are being ignored"); + } + + referenceString = QString::fromAscii("["); + for (int i = 0; i < chosenRefs.size(); i++) { + referenceString += QString::fromAscii(i == 0 ? "" : ",") + + QString::fromAscii("(App.activeDocument().") + QString::fromUtf8(chosenRefs[i]->getNameInDocument()) + + QString::fromAscii(",'')"); + } + + referenceString += QString::fromAscii("]"); + return referenceString; + } +} + +/* Datum feature commands =======================================================*/ + +DEF_STD_CMD_A(CmdPartDesignPlane); + +CmdPartDesignPlane::CmdPartDesignPlane() + :Command("PartDesign_Plane") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a datum plane"); + sToolTipText = QT_TR_NOOP("Create a new datum plane"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Plane"; +} + +void CmdPartDesignPlane::activated(int iMsg) +{ + // create Datum plane + std::string FeatName = getUniqueObjectName("DatumPlane"); + QString refStr = getReferenceString(this); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + openCommand("Create a datum plane"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",FeatName.c_str()); + if (refStr.length() > 0) + doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + +} + +bool CmdPartDesignPlane::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +DEF_STD_CMD_A(CmdPartDesignLine); + +CmdPartDesignLine::CmdPartDesignLine() + :Command("PartDesign_Line") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a datum line"); + sToolTipText = QT_TR_NOOP("Create a new datum line"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Line"; +} + +void CmdPartDesignLine::activated(int iMsg) +{ + // create Datum line + std::string FeatName = getUniqueObjectName("DatumLine"); + QString refStr = getReferenceString(this); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + openCommand("Create a datum line"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Line','%s')",FeatName.c_str()); + if (refStr.length() > 0) + doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } +bool CmdPartDesignLine::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +DEF_STD_CMD_A(CmdPartDesignPoint); + +CmdPartDesignPoint::CmdPartDesignPoint() + :Command("PartDesign_Point") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Create a datum point"); + sToolTipText = QT_TR_NOOP("Create a new datum point"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Point"; +} + +void CmdPartDesignPoint::activated(int iMsg) +{ + // create Datum point + std::string FeatName = getUniqueObjectName("DatumPoint"); + QString refStr = getReferenceString(this); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + openCommand("Create a datum point"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Point','%s')",FeatName.c_str()); + if (refStr.length() > 0) + doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); + doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + +} + +bool CmdPartDesignPoint::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // PartDesign_Sketch //=========================================================================== @@ -103,104 +484,147 @@ CmdPartDesignNewSketch::CmdPartDesignNewSketch() void CmdPartDesignNewSketch::activated(int iMsg) { - PartDesign::Body *pcActiveBody = getBody(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); // No PartDesign feature without Body past FreeCAD 0.13 if(!pcActiveBody) return; Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter PlaneFilter1 ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); openCommand("Edit Sketch"); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); } - else if (FaceFilter.match()) { + else if (FaceFilter.match() || PlaneFilter1.match() || PlaneFilter2.match()) { // get the selected object - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); - Base::Placement ObjectPos = part->Placement.getValue(); - const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); - if (sub.size() > 1){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), - QObject::tr("You have to select a single face as support for a sketch!")); - return; - } - // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getValue(); - TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); - const TopoDS_Face& face = TopoDS::Face(sh); - if (face.IsNull()){ - // No assert for wrong user input! - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), - QObject::tr("You have to select a face as support for a sketch!")); - return; - } + std::string supportString; + + if (FaceFilter.match()) { + Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + // FIXME: Reject or warn about feature that is outside of active body, and feature + // that comes after the current insert point (Tip) + const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); + if (sub.size() > 1){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Several sub-elements selected"), + QObject::tr("You have to select a single face as support for a sketch!")); + return; + } + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getValue(); + TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); + const TopoDS_Face& face = TopoDS::Face(sh); + if (face.IsNull()){ + // No assert for wrong user input! + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No support face selected"), + QObject::tr("You have to select a face as support for a sketch!")); + return; + } - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() != GeomAbs_Plane){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), - QObject::tr("You need a planar face as support for a sketch!")); - return; - } + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No planar support"), + QObject::tr("You need a planar face as support for a sketch!")); + return; + } - std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + } else { + if (PlaneFilter1.match()) + supportString = PlaneFilter1.Result[0][0].getAsPropertyLinkSubString(); + else + supportString = PlaneFilter2.Result[0][0].getAsPropertyLinkSubString(); + } // create Sketch on Face std::string FeatName = getUniqueObjectName("Sketch"); openCommand("Create a Sketch on Face"); - doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the sketch placement based on its support //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } else { - // ask user for orientation - SketcherGui::SketchOrientationDialog Dlg; - - if (Dlg.exec() != QDialog::Accepted) - return; // canceled - Base::Vector3d p = Dlg.Pos.getPosition(); - Base::Rotation r = Dlg.Pos.getRotation(); - - // do the right view direction - std::string camstring; - switch(Dlg.DirType){ - case 0: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 87 \\n orientation 0 0 1 0 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 1: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA \\n position 0 0 -87 \\n orientation -1 0 0 3.1415927 \\n nearDistance -112.88701 \\n farDistance 287.28702 \\n aspectRatio 1 \\n focalDistance 87 \\n height 143.52005 }"; - break; - case 2: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 -87 0 \\n orientation -1 0 0 4.712389\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 3: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 0 87 0 \\n orientation 0 0.70710683 0.70710683 3.1415927\\n nearDistance -112.88701\\n farDistance 287.28702\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 4: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position 87 0 0 \\n orientation 0.57735026 0.57735026 0.57735026 2.0943952 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; - case 5: - camstring = "#Inventor V2.1 ascii \\n OrthographicCamera {\\n viewportMapping ADJUST_CAMERA\\n position -87 0 0 \\n orientation -0.57735026 0.57735026 0.57735026 4.1887903 \\n nearDistance -112.887\\n farDistance 287.28699\\n aspectRatio 1\\n focalDistance 87\\n height 143.52005\\n\\n}"; - break; + // Get a valid plane from the user + std::vector status; + std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); + std::vector planestmp = getDocument()->getObjectsOfType(PartDesign::Plane::getClassTypeId()); + planes.insert(planes.end(), planestmp.begin(), planestmp.end()); + + unsigned validPlanes = 0; + std::vector::const_iterator firstValidPlane = planes.end(); + + for (std::vector::iterator p = planes.begin(); p != planes.end(); p++) { + // Check whether this plane is a base plane + bool base = false; + for (unsigned i = 0; i < 3; i++) { + if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + status.push_back(PartDesignGui::FeaturePickDialog::basePlane); + if (firstValidPlane == planes.end()) + firstValidPlane = p; + validPlanes++; + base = true; + break; + } + } + if (base) continue; + + // Check whether this plane belongs to the active body + PartDesign::Body* body = PartDesignGui::getBody(); + if (!body->hasFeature(*p)) { + status.push_back(PartDesignGui::FeaturePickDialog::otherBody); + continue; + } else { + if (body->isAfterTip(*p)) + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + continue; + } + + // All checks passed - found a valid plane + if (firstValidPlane == planes.end()) + firstValidPlane = p; + validPlanes++; + status.push_back(PartDesignGui::FeaturePickDialog::validFeature); } + + if (validPlanes == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid planes in this document"), + QObject::tr("Please create a plane first or select a face to sketch on")); + return; + } + + // If there is more than one possibility, show dialog and let user pick plane + if (validPlanes > 1) { + PartDesignGui::FeaturePickDialog Dlg(planes, status); + if ((Dlg.exec() != QDialog::Accepted) || (planes = Dlg.getFeatures()).empty()) + return; // Cancelled or nothing selected + firstValidPlane = planes.begin(); + } + + App::Plane* plane = static_cast(*firstValidPlane); + Base::Vector3d p = plane->Placement.getValue().getPosition(); + Base::Rotation r = plane->Placement.getValue().getRotation(); + std::string FeatName = getUniqueObjectName("Sketch"); + std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); - doCommand(Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",camstring.c_str()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); } - } bool CmdPartDesignNewSketch::isActive(void) @@ -211,6 +635,36 @@ bool CmdPartDesignNewSketch::isActive(void) return false; } +//=========================================================================== +// Common utility functions for all features creating solids +//=========================================================================== + +void finishFeature(const Gui::Command* cmd, const std::string& FeatName) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), FeatName.c_str()); + + if (cmd->isActiveObjectValid() && (pcActiveBody != NULL)) { + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); + if (prevSolidFeature != NULL) + cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + } + cmd->updateActive(); + // #0001721: use '0' as edit value to avoid switching off selection in + // ViewProviderGeometryObject::setEditViewer + cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); + cmd->doCommand(cmd->Gui,"Gui.Selection.clearSelection()"); + //cmd->doCommand(cmd->Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); + + if (pcActiveBody) { + cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); + cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); + } +} + //=========================================================================== // Common utility functions for SketchBased features //=========================================================================== @@ -227,12 +681,13 @@ bool CmdPartDesignNewSketch::isActive(void) firstValidSketch = sketches.end(); for (std::vector::iterator s = sketches.begin(); s != sketches.end(); s++) { + //Base::Console().Error("Checking sketch %s\n", (*s)->getNameInDocument()); // Check whether this sketch is already being used by another feature // Body features don't count... std::vector inList = (*s)->getInList(); std::vector::iterator o = inList.begin(); while (o != inList.end()) { - Base::Console().Error("InList: %s\n", (*o)->getNameInDocument()); + //Base::Console().Error("Inlist: %s\n", (*o)->getNameInDocument()); if ((*o)->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) o = inList.erase(o); else @@ -244,7 +699,7 @@ bool CmdPartDesignNewSketch::isActive(void) } // Check whether this sketch belongs to the active body - PartDesign::Body* body = getBody(); + PartDesign::Body* body = PartDesignGui::getBody(); if (!body->hasFeature(*s)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; @@ -279,10 +734,9 @@ bool CmdPartDesignNewSketch::isActive(void) return validSketches; } -void prepareSketchBased(Gui::Command* cmd, const std::string& which, - Part::Part2DObject*& sketch, std::string& FeatName) +void prepareSketchBased(Gui::Command* cmd, const std::string& which, Part::Part2DObject*& sketch, std::string& FeatName) { - PartDesign::Body *pcActiveBody = getBody(); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if (!pcActiveBody) return; // Get a valid sketch from the user @@ -312,39 +766,22 @@ void prepareSketchBased(Gui::Command* cmd, const std::string& which, } sketch = static_cast(*firstValidSketch); + FeatName = cmd->getUniqueObjectName(which.c_str()); cmd->openCommand((std::string("Make ") + which).c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Model = App.activeDocument().%s.Model + [App.activeDocument().%s]",pcActiveBody->getNameInDocument(),pcActiveBody->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s",FeatName.c_str(),sketch->getNameInDocument()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")", + which.c_str(), FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Sketch = App.activeDocument().%s", + FeatName.c_str(), sketch->getNameInDocument()); } void finishSketchBased(const Gui::Command* cmd, const Part::Part2DObject* sketch, const std::string& FeatName) { - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - cmd->doCommand(cmd->Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - cmd->updateActive(); - if (cmd->isActiveObjectValid()) { + if (cmd->isActiveObjectValid()) cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", sketch->getNameInDocument()); - } - // #0001721: use '0' as edit value to avoid switching off selection in - // ViewProviderGeometryObject::setEditViewer - cmd->doCommand(cmd->Gui,"Gui.activeDocument().setEdit('%s', 0)", FeatName.c_str()); - PartDesign::Body *pcActiveBody = getBody(); - if (pcActiveBody) { - cmd->copyVisual(FeatName.c_str(), "ShapeColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "LineColor", pcActiveBody->getNameInDocument()); - cmd->copyVisual(FeatName.c_str(), "PointColor", pcActiveBody->getNameInDocument()); - } + finishFeature(cmd, FeatName); } //=========================================================================== @@ -499,25 +936,16 @@ bool CmdPartDesignGroove::isActive(void) } //=========================================================================== -// PartDesign_Fillet +// Common utility functions for Dressup features //=========================================================================== -DEF_STD_CMD_A(CmdPartDesignFillet); -CmdPartDesignFillet::CmdPartDesignFillet() - :Command("PartDesign_Fillet") +void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) { - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Fillet"); - sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); - sWhatsThis = "PartDesign_Fillet"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Fillet"; -} + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) + return; -void CmdPartDesignFillet::activated(int iMsg) -{ - std::vector selection = getSelection().getSelectionEx(); + std::vector selection = cmd->getSelection().getSelectionEx(); if (selection.size() != 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -527,7 +955,11 @@ void CmdPartDesignFillet::activated(int iMsg) if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), +<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 QObject::tr("Fillet works only on parts.")); +======= + QString::fromStdString(which) + QObject::tr(" works only on parts")); +>>>>>>> Made the rest of the PartDesign features aware of the Body return; } @@ -607,13 +1039,17 @@ void CmdPartDesignFillet::activated(int iMsg) if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), +<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 QObject::tr("No fillet possible on selected faces/edges.")); +======= + QString::fromStdString(which) + QObject::tr(" not possible on selected faces/edges")); +>>>>>>> Made the rest of the PartDesign features aware of the Body return; } std::string SelString; SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); + SelString += "ActiveDocument"; SelString += "."; SelString += selection[0].getFeatName(); SelString += ",["; @@ -626,8 +1062,9 @@ void CmdPartDesignFillet::activated(int iMsg) } SelString += "])"; - std::string FeatName = getUniqueObjectName("Fillet"); + std::string FeatName = cmd->getUniqueObjectName(which.c_str()); +<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 openCommand("Make Fillet"); doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); @@ -639,10 +1076,35 @@ void CmdPartDesignFillet::activated(int iMsg) doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" ,grp->getNameInDocument(),FeatName.c_str()); } +======= + cmd->openCommand((std::string("Make ") + which).c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); + finishFeature(cmd, FeatName); +} + +//=========================================================================== +// PartDesign_Fillet +//=========================================================================== +DEF_STD_CMD_A(CmdPartDesignFillet); + +CmdPartDesignFillet::CmdPartDesignFillet() + :Command("PartDesign_Fillet") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Fillet"); + sToolTipText = QT_TR_NOOP("Make a fillet on an edge, face or body"); + sWhatsThis = "PartDesign_Fillet"; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Fillet"; +} +>>>>>>> Made the rest of the PartDesign features aware of the Body + +void CmdPartDesignFillet::activated(int iMsg) +{ + makeChamferOrFillet(this, "Fillet"); } bool CmdPartDesignFillet::isActive(void) @@ -669,6 +1131,7 @@ CmdPartDesignChamfer::CmdPartDesignChamfer() void CmdPartDesignChamfer::activated(int iMsg) { +<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 std::vector selection = getSelection().getSelectionEx(); if (selection.size() != 1) { @@ -796,6 +1259,9 @@ void CmdPartDesignChamfer::activated(int iMsg) copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); +======= + makeChamferOrFillet(this, "Chamfer"); +>>>>>>> Made the rest of the PartDesign features aware of the Body } bool CmdPartDesignChamfer::isActive(void) @@ -822,6 +1288,9 @@ CmdPartDesignDraft::CmdPartDesignDraft() void CmdPartDesignDraft::activated(int iMsg) { + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) return; + std::vector selection = getSelection().getSelectionEx(); if (selection.size() < 1) { @@ -838,6 +1307,12 @@ void CmdPartDesignDraft::activated(int iMsg) Part::Feature *base = static_cast(selection[0].getObject()); + if (base != pcActiveBody->Tip.getValue()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), + QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); + return; + } + const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -898,20 +1373,8 @@ void CmdPartDesignDraft::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Draft\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); doCommand(Doc,"App.activeDocument().%s.Angle = %f",FeatName.c_str(), 1.5); - updateActive(); - if (isActiveObjectValid()) { - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - } - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); + finishFeature(this, FeatName); } bool CmdPartDesignDraft::isActive(void) @@ -922,28 +1385,10 @@ bool CmdPartDesignDraft::isActive(void) //=========================================================================== // Common functions for all Transformed features //=========================================================================== -<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 -DEF_STD_CMD_A(CmdPartDesignMirrored); -CmdPartDesignMirrored::CmdPartDesignMirrored() - : Command("PartDesign_Mirrored") -{ - sAppModule = "PartDesign"; - sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("Mirrored"); - sToolTipText = QT_TR_NOOP("Create a mirrored feature"); - sWhatsThis = "PartDesign_Mirrored"; - sStatusTip = sToolTipText; - sPixmap = "PartDesign_Mirrored"; -} - -void CmdPartDesignMirrored::activated(int iMsg) -======= -;;; void prepareTransformed(Gui::Command* cmd, const std::string& which, std::vector& features, std::string& FeatName, std::vector& selList, std::string& selNames) ->>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile { // Get a valid original from the user // First check selections @@ -972,7 +1417,7 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, } } - FeatName = cmd->getUniqueObjectName("Mirrored"); + FeatName = cmd->getUniqueObjectName(which.c_str()); std::stringstream str; str << "App.activeDocument()." << FeatName << ".Originals = ["; @@ -982,6 +1427,21 @@ void prepareTransformed(Gui::Command* cmd, const std::string& which, } str << "]"; selNames = str.str(); + + cmd->openCommand((std::string("Make ") + which + " feature").c_str()); + cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); + // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like + // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' + cmd->updateActive(); // Helps to ensure that the object already exists when the next command comes up + cmd->doCommand(cmd->Doc,selNames.c_str()); +} + +void finishTransformed(Gui::Command* cmd, std::string& FeatName, std::vector& selList) +{ + //for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) + // cmd->doCommand(cmd->Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); + + finishFeature(cmd, FeatName); } //=========================================================================== @@ -1010,23 +1470,12 @@ void CmdPartDesignMirrored::activated(int iMsg) if (features.empty()) return; - openCommand("Mirrored"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",FeatName.c_str()); - // FIXME: There seems to be kind of a race condition here, leading to sporadic errors like - // Exception (Thu Sep 6 11:52:01 2012): 'App.Document' object has no attribute 'Mirrored' - updateActive(); // Helps to ensure that the object already exists when the next command comes up - doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignMirrored::isActive(void) @@ -1053,72 +1502,21 @@ CmdPartDesignLinearPattern::CmdPartDesignLinearPattern() void CmdPartDesignLinearPattern::activated(int iMsg) { -<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("LinearPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; -======= std::string FeatName, selNames; std::vector features; std::vector selList; prepareTransformed(this, "LinearPattern", features, FeatName, selList, selNames); if (features.empty()) return; ->>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile - openCommand("LinearPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Length = 100", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignLinearPattern::isActive(void) @@ -1145,72 +1543,21 @@ CmdPartDesignPolarPattern::CmdPartDesignPolarPattern() void CmdPartDesignPolarPattern::activated(int iMsg) { -<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("PolarPattern"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; -======= std::string FeatName, selNames; std::vector features; std::vector selList; prepareTransformed(this, "PolarPattern", features, FeatName, selList, selNames); if (features.empty()) return; ->>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile - openCommand("PolarPattern"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,selNames.c_str()); Part::Part2DObject *sketch = (static_cast(features.front()))->getVerifiedSketch(); if (sketch) doCommand(Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", FeatName.c_str(), sketch->getNameInDocument()); doCommand(Doc,"App.activeDocument().%s.Angle = 360", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = sketch->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),sketch->getNameInDocument()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignPolarPattern::isActive(void) @@ -1237,61 +1584,17 @@ CmdPartDesignScaled::CmdPartDesignScaled() void CmdPartDesignScaled::activated(int iMsg) { -<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("Scaled"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; -======= std::string FeatName, selNames; std::vector features; std::vector selList; prepareTransformed(this, "Scaled", features, FeatName, selList, selNames); if (features.empty()) return; ->>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile - openCommand("Scaled"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",FeatName.c_str()); - updateActive(); - doCommand(Doc,selNames.c_str()); doCommand(Doc,"App.activeDocument().%s.Factor = 2", FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Occurrences = 2", FeatName.c_str()); - for (std::vector::iterator it = selList.begin(); it != selList.end(); ++it) - doCommand(Gui,"Gui.activeDocument().%s.Visibility=False",it->c_str()); - - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishTransformed(this, FeatName, selList); } bool CmdPartDesignScaled::isActive(void) @@ -1318,57 +1621,28 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { -<<<<<<< 8a516f9e630a4cf221f2f34109748e14bb5d0381 - // Get a valid original from the user - // First check selections - std::vector features = getSelection().getObjectsOfType(PartDesign::Additive::getClassTypeId()); - std::vector subtractive = getSelection().getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // Next create a list of all eligible objects - if (features.size() == 0) { - features = getDocument()->getObjectsOfType(PartDesign::Additive::getClassTypeId()); - subtractive = getDocument()->getObjectsOfType(PartDesign::Subtractive::getClassTypeId()); - features.insert(features.end(), subtractive.begin(), subtractive.end()); - // If there is more than one selected or eligible object, show dialog and let user pick one - if (features.size() > 1) { - PartDesignGui::FeaturePickDialog Dlg(features); - if ((Dlg.exec() != QDialog::Accepted) || (features = Dlg.getFeatures()).empty()) - return; // Cancelled or nothing selected - } else { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid features in this document"), - QObject::tr("Please create a subtractive or additive feature first, please.")); - return; - } - } - - std::string FeatName = getUniqueObjectName("MultiTransform"); - - std::stringstream str; - std::vector tempSelNames; - str << "App.activeDocument()." << FeatName << ".Originals = ["; - for (std::vector::iterator it = features.begin(); it != features.end(); ++it){ - str << "App.activeDocument()." << (*it)->getNameInDocument() << ","; - tempSelNames.push_back((*it)->getNameInDocument()); - } - str << "]"; -======= std::string FeatName, selNames; std::vector features; std::vector selList; prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); if (features.empty()) return; ->>>>>>> Preliminary work on Transformed feature's pick dialog to make Command.cpp compile - openCommand("MultiTransform"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")",FeatName.c_str()); + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) + return; updateActive(); doCommand(Doc,selNames.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + // Make sure the user isn't presented with an empty screen because no transformations are defined yet... + App::DocumentObject* prevSolid = pcActiveBody->getPrevSolidFeature(NULL, true); + if (prevSolid != NULL) { + Part::Feature* feat = static_cast(prevSolid); + doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", + FeatName.c_str(), feat->getNameInDocument()); + } - copyVisual(FeatName.c_str(), "ShapeColor", selList.front().c_str()); - copyVisual(FeatName.c_str(), "DisplayMode", selList.front().c_str()); + finishFeature(this, FeatName); } bool CmdPartDesignMultiTransform::isActive(void) @@ -1385,13 +1659,18 @@ void CreatePartDesignCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.addCommand(new CmdPartDesignBody()); + rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); + rcCmdMgr.addCommand(new CmdPartDesignPlane()); + rcCmdMgr.addCommand(new CmdPartDesignLine()); + rcCmdMgr.addCommand(new CmdPartDesignPoint()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); rcCmdMgr.addCommand(new CmdPartDesignGroove()); rcCmdMgr.addCommand(new CmdPartDesignFillet()); - rcCmdMgr.addCommand(new CmdPartDesignDraft()); - rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignDraft()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); rcCmdMgr.addCommand(new CmdPartDesignMirrored()); rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp index 8e1c522072c5..58bda2c58e6a 100644 --- a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp @@ -28,6 +28,7 @@ #include "ui_TaskChamferParameters.h" #include "TaskChamferParameters.h" +#include "Workbench.h" #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include @@ -154,19 +156,20 @@ bool TaskDlgChamferParameters::accept() bool TaskDlgChamferParameters::reject() { - // get the support and Sketch - PartDesign::Chamfer* pcChamfer = static_cast(ChamferView->getObject()); - App::DocumentObject *pcSupport; - pcSupport = pcChamfer->Base.getValue(); - // role back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcChamfer)) { - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } } return true; diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index 0151811cfe3b..de55ef33221a 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -29,6 +29,7 @@ #include "ui_TaskDraftParameters.h" #include "TaskDraftParameters.h" +#include "Workbench.h" #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include @@ -426,19 +428,20 @@ bool TaskDlgDraftParameters::accept() bool TaskDlgDraftParameters::reject() { - // get the support - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); - App::DocumentObject *pcSupport; - pcSupport = pcDraft->Base.getValue(); - // roll back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcDraft)) { - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } } return true; diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp index a86637ac3a42..0e1045a7d172 100644 --- a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp @@ -28,6 +28,7 @@ #include "ui_TaskFilletParameters.h" #include "TaskFilletParameters.h" +#include "Workbench.h" #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include @@ -154,19 +156,20 @@ bool TaskDlgFilletParameters::accept() bool TaskDlgFilletParameters::reject() { - // get the support and Sketch - PartDesign::Fillet* pcFillet = static_cast(FilletView->getObject()); - App::DocumentObject *pcSupport; - pcSupport = pcFillet->Base.getValue(); - // role back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcFillet)) { - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } } return true; diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp index 97424bda6f6f..1642fcd13d64 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp @@ -456,7 +456,6 @@ bool TaskDlgMultiTransformParameters::reject() // Get objects before view is invalidated // For the same reason we can't delegate showing the originals to TaskDlgTransformedParameters::reject() PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); - std::vector pcOriginals = pcMultiTransform->Originals.getValues(); std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); // Delete the transformation features - must happen before abortCommand()! @@ -471,17 +470,7 @@ bool TaskDlgMultiTransformParameters::reject() Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - // if abort command deleted the object the originals are visible again - if (!Gui::Application::Instance->getViewProvider(pcMultiTransform)) { - for (std::vector::const_iterator it = pcOriginals.begin(); it != pcOriginals.end(); ++it) - { - if (((*it) != NULL) && (Gui::Application::Instance->getViewProvider(*it) != NULL)) { - Gui::Application::Instance->getViewProvider(*it)->show(); - } - } - } - - return true; + return TaskDlgTransformedParameters::reject(); } #include "moc_TaskMultiTransformParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index b19314705532..179b5ea00532 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -559,7 +559,7 @@ bool TaskDlgPadParameters::reject() Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - // if abort command deleted the object the support is visible again + // if abort command deleted the object the sketch is visible again if (!Gui::Application::Instance->getViewProvider(pcPad)) { if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) Gui::Application::Instance->getViewProvider(pcSketch)->show(); diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 9031165f0738..6615ee05738e 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -32,6 +32,7 @@ #include "TaskTransformedParameters.h" #include "TaskMultiTransformParameters.h" +#include "Workbench.h" #include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include "ReferenceSelection.h" using namespace PartDesignGui; @@ -274,21 +276,19 @@ bool TaskDlgTransformedParameters::reject() // ensure that we are not in selection mode parameter->exitSelectionMode(); - // get object and originals before view is invalidated (if it is invalidated) - PartDesign::Transformed* pcTransformed = static_cast(TransformedView->getObject()); - std::vector pcOriginals = pcTransformed->Originals.getValues(); - // roll back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - // if abort command deleted the object the originals are visible again - if (!Gui::Application::Instance->getViewProvider(pcTransformed)) { - for (std::vector::const_iterator it = pcOriginals.begin(); it != pcOriginals.end(); ++it) - { - if (((*it) != NULL) && (Gui::Application::Instance->getViewProvider(*it) != NULL)) { - Gui::Application::Instance->getViewProvider(*it)->show(); - } + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); } } diff --git a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp index 9e0cf542711d..a86ccd9fc9d6 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp @@ -115,20 +115,11 @@ void ViewProviderChamfer::unsetEdit(int ModNum) } } -bool ViewProviderChamfer::onDelete(const std::vector &) +bool ViewProviderChamfer::onDelete(const std::vector &s) { - // get the support and Sketch - PartDesign::Chamfer* pcChamfer = static_cast(getObject()); - App::DocumentObject *pcSupport = 0; - if (pcChamfer->Base.getValue()){ - pcSupport = static_cast(pcChamfer->Base.getValue()); - } + return ViewProvider::onDelete(s); +} - // if abort command deleted the object the support is visible again - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - return true; -} diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp index a5cba298affd..e7f4545f8241 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp @@ -115,20 +115,9 @@ void ViewProviderDraft::unsetEdit(int ModNum) } } -bool ViewProviderDraft::onDelete(const std::vector &) +bool ViewProviderDraft::onDelete(const std::vector &s) { - // get the support and Sketch - PartDesign::Draft* pcDraft = static_cast(getObject()); - App::DocumentObject *pcSupport = 0; - if (pcDraft->Base.getValue()){ - pcSupport = static_cast(pcDraft->Base.getValue()); - } - - // if abort command deleted the object the support is visible again - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - - return true; + return ViewProvider::onDelete(s); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp index 26c253b7c150..28fda0583fe1 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp @@ -115,20 +115,9 @@ void ViewProviderFillet::unsetEdit(int ModNum) } } -bool ViewProviderFillet::onDelete(const std::vector &) +bool ViewProviderFillet::onDelete(const std::vector &s) { - // get the support and Sketch - PartDesign::Fillet* pcFillet = static_cast(getObject()); - App::DocumentObject *pcSupport = 0; - if (pcFillet->Base.getValue()){ - pcSupport = static_cast(pcFillet->Base.getValue()); - } - - // if abort command deleted the object the support is visible again - if (pcSupport && Gui::Application::Instance->getViewProvider(pcSupport)) - Gui::Application::Instance->getViewProvider(pcSupport)->show(); - - return true; + return ViewProvider::onDelete(s); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index f1b6f4b06767..55bf53d04925 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -149,19 +149,9 @@ void ViewProviderTransformed::unsetEdit(int ModNum) rejectedFaceSet->unref(); } -bool ViewProviderTransformed::onDelete(const std::vector &) +bool ViewProviderTransformed::onDelete(const std::vector &s) { - PartDesign::Transformed* pcTransformed = static_cast(getObject()); - std::vector originals = pcTransformed->Originals.getValues(); - - // if abort command deleted the object the originals are visible again - for (std::vector::const_iterator it = originals.begin(); it != originals.end(); ++it) - { - if (((*it) != NULL) && Gui::Application::Instance->getViewProvider(*it)) - Gui::Application::Instance->getViewProvider(*it)->show(); - } - - return true; + return ViewProvider::onDelete(s); } const bool ViewProviderTransformed::checkDlgOpen(TaskDlgTransformedParameters* transformedDlg) { From 45af3e2a78c7ffee952e22ab1d8677b058120359 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 24 Apr 2013 20:50:09 +0430 Subject: [PATCH 085/664] Miscellaneous fixes --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 9 +++- src/Mod/PartDesign/App/Body.cpp | 32 +++--------- src/Mod/PartDesign/Gui/Command.cpp | 55 +++++++++++---------- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 4 +- src/Mod/PartDesign/Gui/Workbench.cpp | 25 ++++++++-- src/Mod/PartDesign/Gui/Workbench.h | 7 +++ 6 files changed, 73 insertions(+), 59 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 812d2cdec359..22473a31904e 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -45,6 +45,9 @@ Gui::Document *ActiveGuiDoc =0; App::Document *ActiveAppDoc =0; Gui::ViewProviderDocumentObject *ActiveVp =0; +// The names of the base planes. Note: The user-visible label is different from this +const char* BaseplaneNames[3] = {"BaseplaneXY", "BaseplaneYZ", "BaseplaneXZ"}; + } static PyObject * setActivePart(PyObject *self, PyObject *args) @@ -55,7 +58,9 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) // Should be set! assert(Item); - if (PartDesignGui::ActivePartObject != NULL) + // Set old body inactive if we are activating another body in the same document + if ((PartDesignGui::ActivePartObject != NULL) && + (PartDesignGui::ActivePartObject->getDocument() == Item->getDocument())) PartDesignGui::ActivePartObject->IsActive.setValue(false); PartDesignGui::ActivePartObject = Item; PartDesignGui::ActiveAppDoc = Item->getDocument(); @@ -64,7 +69,7 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) Item->IsActive.setValue(true); } else { // This handles the case of deactivating the workbench - PartDesignGui::ActivePartObject = 0; + PartDesignGui::ActivePartObject=0; PartDesignGui::ActiveGuiDoc =0; PartDesignGui::ActiveAppDoc =0; PartDesignGui::ActiveVp =0; diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 9421be8c8c7a..afa7f05da288 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -113,34 +113,14 @@ const Part::TopoShape Body::getTipShape() App::DocumentObject* link = Tip.getValue(); if (!link) return Part::TopoShape(); - //Base::Console().Error("Body tip: %s\n", link->getNameInDocument()); + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) //return new App::DocumentObjectExecReturn("Linked object is not a PartDesign object"); return Part::TopoShape(); // get the shape of the tip return static_cast(link)->Shape.getShape(); } -/* -const Part::TopoShape Body::getPreviousSolid(const PartDesign::Feature* f) -{ - std::vector features = Model.getValues(); - std::vector::const_iterator it = std::find(features.begin(), features.end(), f); - if ((it == features.end()) || (it == features.begin())) - // Wrong body or there is no previous feature - return Part::TopoShape(); - // move to previous feature - it--; - // Skip sketches and datum features - while ((*it)->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) || - (*it)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - if (it == features.begin()) - return Part::TopoShape(); - it--; - } - return static_cast(*it)->Shape.getShape(); -} -*/ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start, const bool inclusive) { std::vector features = Model.getValues(); @@ -200,8 +180,8 @@ const bool Body::isAfterTip(const App::DocumentObject *f) { const bool Body::isSolidFeature(const App::DocumentObject* f) { - return (!f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) && - !f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); + return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) && + !f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())); } Body* Body::findBodyOf(const App::DocumentObject* f) @@ -318,7 +298,7 @@ void Body::removeFeature(App::DocumentObject* feature) App::DocumentObjectExecReturn *Body::execute(void) { - Base::Console().Error("Checking Body '%s' for sanity\n", getNameInDocument()); + Base::Console().Error("Body '%s':\n", getNameInDocument()); App::DocumentObject* tip = Tip.getValue(); Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); std::vector model = Model.getValues(); @@ -326,8 +306,8 @@ App::DocumentObjectExecReturn *Body::execute(void) for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { if (*m == NULL) continue; Base::Console().Error(" %s", (*m)->getNameInDocument()); - if ((*m)->getTypeId().isDerivedFrom(PartDesign::SketchBased::getClassTypeId())) { - App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); + if (Body::isSolidFeature(*m)) { + App::DocumentObject* baseFeature = static_cast(*m)->BaseFeature.getValue(); Base::Console().Error(", Base: %s\n", baseFeature == NULL ? "None" : baseFeature->getNameInDocument()); } else { Base::Console().Error("\n"); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 15c8657eb8d8..766860f168d6 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -77,8 +77,6 @@ using namespace std; -const char* BasePlaneNames[3] = {"Body_PlaneXY", "Body_PlaneYZ", "Body_PlaneXZ"}; - //=========================================================================== // PartDesign_Body //=========================================================================== @@ -108,7 +106,7 @@ void CmdPartDesignBody::activated(int iMsg) std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { for (unsigned i = 0; i < 3; i++) { - if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*p)->getNameInDocument()) == 0) { found = true; break; } @@ -118,29 +116,30 @@ void CmdPartDesignBody::activated(int iMsg) if (!found) { // Add the planes ... - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[0]); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'"); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[1]); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[0]); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XY-Plane").toStdString().c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[1]); doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'"); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[2]); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); // ... and put them in the 'Origin' group - doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','Origin')"); + doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", QObject::tr("Origin").toStdString().c_str()); for (unsigned i = 0; i < 3; i++) - doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", BasePlaneNames[i]); + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", PartDesignGui::BaseplaneNames[i]); // TODO: Fold the group (is that possible through the Python interface?) } // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = []",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); doCommand(Doc,"import PartDesignGui"); - doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); + doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.%s)", FeatName.c_str()); // Make the "Create sketch" prompt appear in the task panel doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); + doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s)", FeatName.c_str()); updateActive(); } @@ -281,7 +280,7 @@ const QString getReferenceString(Gui::Command* cmd) // Check whether this reference is a base plane bool base = false; for (unsigned i = 0; i < 3; i++) { - if (strcmp(BasePlaneNames[i], (*r)->getNameInDocument()) == 0) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*r)->getNameInDocument()) == 0) { status.push_back(PartDesignGui::FeaturePickDialog::basePlane); if (chosenRefs.empty()) chosenRefs.push_back(*r); @@ -325,11 +324,13 @@ const QString getReferenceString(Gui::Command* cmd) Base::Console().Warning("You have chosen more than three references for a datum feature. The extra references are being ignored"); } + // TODO: Allow user to choose front or back of the plane + referenceString = QString::fromAscii("["); for (int i = 0; i < chosenRefs.size(); i++) { referenceString += QString::fromAscii(i == 0 ? "" : ",") + QString::fromAscii("(App.activeDocument().") + QString::fromUtf8(chosenRefs[i]->getNameInDocument()) + - QString::fromAscii(",'')"); + QString::fromAscii(",'front')"); } referenceString += QString::fromAscii("]"); @@ -491,15 +492,17 @@ void CmdPartDesignNewSketch::activated(int iMsg) Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); - Gui::SelectionFilter PlaneFilter1 ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); + if (PlaneFilter2.match()) + PlaneFilter = PlaneFilter2; if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); openCommand("Edit Sketch"); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); } - else if (FaceFilter.match() || PlaneFilter1.match() || PlaneFilter2.match()) { + else if (FaceFilter.match() || PlaneFilter.match()) { // get the selected object std::string supportString; @@ -534,13 +537,12 @@ void CmdPartDesignNewSketch::activated(int iMsg) supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); } else { - if (PlaneFilter1.match()) - supportString = PlaneFilter1.Result[0][0].getAsPropertyLinkSubString(); - else - supportString = PlaneFilter2.Result[0][0].getAsPropertyLinkSubString(); + Part::Feature *plane = static_cast(PlaneFilter.Result[0][0].getObject()); + // TODO: Find out whether the user picked front or back of this plane + supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", ['front'])"; } - // create Sketch on Face + // create Sketch on Face or Plane std::string FeatName = getUniqueObjectName("Sketch"); openCommand("Create a Sketch on Face"); @@ -566,7 +568,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) // Check whether this plane is a base plane bool base = false; for (unsigned i = 0; i < 3; i++) { - if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*p)->getNameInDocument()) == 0) { status.push_back(PartDesignGui::FeaturePickDialog::basePlane); if (firstValidPlane == planes.end()) firstValidPlane = p; @@ -609,17 +611,20 @@ void CmdPartDesignNewSketch::activated(int iMsg) firstValidPlane = planes.begin(); } + //TODO: Allow user to choose front or back of the plane + App::Plane* plane = static_cast(*firstValidPlane); Base::Vector3d p = plane->Placement.getValue().getPosition(); Base::Rotation r = plane->Placement.getValue().getRotation(); std::string FeatName = getUniqueObjectName("Sketch"); - std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; + std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", ['front'])"; openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + //doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))", + // FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index d92e135a377b..de5729fd3b64 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -144,11 +144,13 @@ std::vector ViewProviderBody::claimChildren3D(void)const void ViewProviderBody::updateTree() { + if (ActiveGuiDoc == NULL) return; + // Highlight active body and all its features //Base::Console().Error("ViewProviderBody::updateTree()\n"); PartDesign::Body* body = static_cast(getObject()); bool active = body->IsActive.getValue(); - //Base::Console().Error("Body is %s\n", active ? "active" : "inactive"); + //Base::Console().Error("Body is %s\n", active ? "active" : "inactive"); ActiveGuiDoc->signalHighlightObject(*this, Gui::Blue, active); std::vector features = body->Model.getValues(); bool highlight = true; diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index eb4bead40d7f..2b73799336a4 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -78,10 +78,6 @@ TYPESYSTEM_SOURCE(PartDesignGui::Workbench, Gui::StdWorkbench) Workbench::Workbench() { - // Let us be notified when a document is activated, so that we can update the ActivePartObject - Gui::Application::Instance->signalActiveDocument.connect(boost::bind(&Workbench::slotActiveDocument, this, _1)); - App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, _1)); - App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); } Workbench::~Workbench() @@ -129,6 +125,14 @@ void Workbench::slotFinishRestoreDocument(const App::Document& Doc) switchToDocument(&Doc); } +void Workbench::slotDeleteDocument(const App::Document&) +{ + ActivePartObject = 0; + ActiveGuiDoc = 0; + ActiveAppDoc = 0; + ActiveVp = 0; +} + void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const { if (strcmp(recipient,"Tree") == 0) @@ -297,16 +301,27 @@ void Workbench::activated() )); // make the previously used active Body active again + PartDesignGui::ActivePartObject = NULL; switchToDocument(App::GetApplication().getActiveDocument()); addTaskWatcher(Watcher); Gui::Control().showTaskView(); - + // Let us be notified when a document is activated, so that we can update the ActivePartObject + Gui::Application::Instance->signalActiveDocument.connect(boost::bind(&Workbench::slotActiveDocument, this, _1)); + App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, _1)); + App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); + App::GetApplication().signalDeleteDocument.connect(boost::bind(&Workbench::slotDeleteDocument, this, _1)); } void Workbench::deactivated() { + // Let us be notified when a document is activated, so that we can update the ActivePartObject + Gui::Application::Instance->signalActiveDocument.disconnect(boost::bind(&Workbench::slotActiveDocument, this, _1)); + App::GetApplication().signalNewDocument.disconnect(boost::bind(&Workbench::slotNewDocument, this, _1)); + App::GetApplication().signalFinishRestoreDocument.disconnect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); + App::GetApplication().signalDeleteDocument.disconnect(boost::bind(&Workbench::slotDeleteDocument, this, _1)); + removeTaskWatcher(); // reset the active Body Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 51d1c5b3d0fc..3c1af1f862f7 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -47,6 +47,8 @@ extern PartDesign::Body *ActivePartObject; extern Gui::Document *ActiveGuiDoc; extern App::Document *ActiveAppDoc; extern Gui::ViewProviderDocumentObject *ActiveVp; +// The names of the base planes +extern const char* BaseplaneNames[3]; /// Return active body or show a warning message PartDesign::Body *getBody(void); @@ -76,9 +78,14 @@ class PartDesignGuiExport Workbench : public Gui::StdWorkbench Gui::ToolBarItem* setupCommandBars() const; private: + /// Refresh the Body's highlighting when a document becomes active void slotActiveDocument(const Gui::Document&); + /// Refresh the highlighting. Migrate legacy documents on loading void slotFinishRestoreDocument(const App::Document&); + /// Ensure that there are base planes and a body in a new document void slotNewDocument(const App::Document&); + /// Update the ActivePartObject etc. when a document is closed + void slotDeleteDocument(const App::Document&); }; } // namespace PartDesignGui From 428033475199889e275c1e10170e0acaf33f994f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 24 Apr 2013 20:51:05 +0430 Subject: [PATCH 086/664] Make sure that App::Plane sketch placement is identical to deprecated SketchOrientationDialog placement --- src/Mod/Part/App/Part2DObject.cpp | 34 +++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index 2a68c0018392..16f754a3a7be 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -84,13 +84,43 @@ void Part2DObject::positionBySupport(void) throw Base::Exception("Sketch support has been deleted"); if (support->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + // Find the name of the Baseplane without having to access PartDesignGui::BaseplaneNames[] + Place = static_cast(support)->Placement.getValue(); + Base::Vector3d dir; + Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); + const std::vector &sub = Support.getSubValues(); + if (!sub.empty() && (sub[0] == "back")) { + Reverse = true; + dir *= -1.0; + } + + // Set placement identical to the way it used to be done in the Sketcher::SketchOrientationDialog + if (dir == Base::Vector3d(0,0,1)) { + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Reverse ? -1.0 : 0.0,0.0,0.0,0.0)); + } else if (dir == Base::Vector3d(0,1,0)) { + if (Reverse) + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Base::Vector3d(0,sqrt(2.0)/2.0,sqrt(2.0)/2.0),M_PI)); + else + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Base::Vector3d(-1,0,0),1.5*M_PI)); + } else if (dir == Base::Vector3d(1,0,0)) { + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Reverse ? -0.5 : 0.5,0.5,0.5, Reverse ? -0.5 : 0.5)); + } + + Reverse = false; // We already reversed... + + Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); + Base::Vector3d pos = Place.getPosition(); + plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); + }/* else if (support->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { Place = static_cast(support)->Placement.getValue(); - // TODO: How to handle the Reverse property??? Base::Vector3d pos = Place.getPosition(); Base::Vector3d dir; Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); + const std::vector &sub = Support.getSubValues(); + if (!sub.empty()) + Reverse = (sub[0] == "back"); plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); - } else { + }*/ else { Part::Feature *part = static_cast(support); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return; From ce224298a722f89e606fa9f3c71080f2c7d3178b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 24 Apr 2013 20:51:37 +0430 Subject: [PATCH 087/664] Automatically add Body feature to Parts if the PartDesign workbench is active --- src/Mod/PartDesign/Gui/Workbench.cpp | 137 +++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 7 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 2b73799336a4..81157b44e7e8 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -26,9 +26,13 @@ #ifndef _PreComp_ # include # include +# include +# include #endif #include "Workbench.h" +#include +#include #include #include #include @@ -42,6 +46,8 @@ #include #include #include +#include +#include using namespace PartDesignGui; @@ -91,11 +97,124 @@ void switchToDocument(const App::Document* doc) PartDesign::Body* activeBody = NULL; std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { - PartDesign::Body* body = static_cast(*b); - if (body->IsActive.getValue()) { - activeBody = body; - break; + // Is there a body feature in this document? + if (bodies.empty()) { + // Get the objects now, before adding the Body and the base planes + std::vector features = doc->getObjects(); + + // This adds both the base planes and the body + // Note: In the following code we rely on the first body always having the name "Body"! + Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); + + // Assign all document features to the new body + std::string modelString = ""; + + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + if ((*f)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || + (*f)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { + modelString += std::string(modelString.empty() ? "" : ",") + "App.ActiveDocument." + (*f)->getNameInDocument(); + } + } + + if (!modelString.empty()) { + modelString = std::string("[") + modelString + "]"; + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Body.Model = %s", modelString.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Body.Tip = App.activeDocument().%s", features.back()->getNameInDocument()); + } + + // Initialize the BaseFeature property of all PartDesign solid features + App::DocumentObject* baseFeature = NULL; + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + if (PartDesign::Body::isSolidFeature(*f)) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = %s", + (*f)->getNameInDocument(), + baseFeature == NULL ? + "None" : + (std::string("App.activeDocument().") + baseFeature->getNameInDocument()).c_str()); + + baseFeature = *f; + } + } + + // Re-route all sketches without support to the base planes + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { + Sketcher::SketchObject* sketch = static_cast(*f); + App::DocumentObject* support = sketch->Support.getValue(); + if (support != NULL) + continue; // Sketch is on a face of a solid + Base::Placement plm = sketch->Placement.getValue(); + Base::Vector3d pnt = plm.getPosition(); + // Currently we only handle positions that correspond to the base planes + if (pnt.Length() > Precision::Confusion()) { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), + QObject::tr("Please edit ") + QString::fromAscii(sketch->getNameInDocument()) + + QObject::tr("and redefine it to use a Base or Datum plane as the sketch plane.")); + break; // avoid repeating this message for every sketch + } + Base::Rotation rot = plm.getRotation(); + Base::Vector3d SketchVector(0,0,1); + rot.multVec(SketchVector, SketchVector); + std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front"; + if (side == "back") SketchVector *= -1.0; + + if (SketchVector == Base::Vector3d(0,0,1)) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", + sketch->getNameInDocument(), BaseplaneNames[0], side.c_str()); + } else if (SketchVector == Base::Vector3d(1,0,0)) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", + sketch->getNameInDocument(), BaseplaneNames[1], side.c_str()); + } else if (SketchVector == Base::Vector3d(0,1,0)) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", + sketch->getNameInDocument(), BaseplaneNames[2], side.c_str()); + } else { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), + QObject::tr("Please edit") + QString::fromAscii(sketch->getNameInDocument()) + + QObject::tr("and redefine it to use a Base or Datum plane as the sketch plane.")); + break; // avoid repeating this message for every sketch + } + } + } + + activeBody = static_cast(doc->getObject("Body")); + } else { + // Find active body + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + PartDesign::Body* body = static_cast(*b); + if (body->IsActive.getValue()) { + activeBody = body; + break; + } + } + + // Do the base planes exist in this document? + bool found = false; + std::vector planes = doc->getObjectsOfType(App::Plane::getClassTypeId()); + for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { + for (unsigned i = 0; i < 3; i++) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*p)->getNameInDocument()) == 0) { + found = true; + break; + } + } + if (found) break; + } + + if (!found) { + // Add the planes ... + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[0]); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XY-Plane").toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[1]); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); + // ... and put them in the 'Origin' group + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", QObject::tr("Origin").toStdString().c_str()); + for (unsigned i = 0; i < 3; i++) + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", PartDesignGui::BaseplaneNames[i]); + // TODO: Fold the group (is that possible through the Python interface?) } } @@ -106,6 +225,11 @@ void switchToDocument(const App::Document* doc) if (activeBody != NULL) { Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); + } else { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Could not create body"), + QObject::tr("No body was found in this document, and none could be created. Please report this bug." + "We recommend you do not use this document with the PartDesign workbench until the bug has been fixed." + )); } } @@ -116,12 +240,11 @@ void Workbench::slotActiveDocument(const Gui::Document& Doc) void Workbench::slotNewDocument(const App::Document& Doc) { - Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); switchToDocument(&Doc); } void Workbench::slotFinishRestoreDocument(const App::Document& Doc) -{ +{ switchToDocument(&Doc); } From 8682b5f4904c13c3d81ccc45141fef97740447ca Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 25 Apr 2013 13:49:56 +0430 Subject: [PATCH 088/664] Switch to PartDesign workbench as soon as a PartDesign feature is edited --- src/Mod/PartDesign/Gui/ViewProvider.h | 3 +++ src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp | 11 ++++++----- src/Mod/PartDesign/Gui/ViewProviderDraft.cpp | 11 ++++++----- src/Mod/PartDesign/Gui/ViewProviderFillet.cpp | 11 ++++++----- src/Mod/PartDesign/Gui/ViewProviderGroove.cpp | 11 ++++++----- src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp | 3 +++ src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp | 3 +++ src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp | 3 +++ src/Mod/PartDesign/Gui/ViewProviderPad.cpp | 9 ++++++--- src/Mod/PartDesign/Gui/ViewProviderPocket.cpp | 11 ++++++----- src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp | 3 +++ src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp | 11 ++++++----- src/Mod/PartDesign/Gui/ViewProviderScaled.cpp | 3 +++ src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp | 4 ++++ src/Mod/Start/Gui/Workbench.cpp | 7 +++++++ 15 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 955910b2a6c2..fd023e0c2a07 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -43,6 +43,9 @@ class PartDesignGuiExport ViewProvider : public PartGui::ViewProviderPart { void updateData(const App::Property*); virtual bool onDelete(const std::vector &); + +protected: + std::string oldWb; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp index a86ccd9fc9d6..490c01b6931b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp @@ -85,8 +85,9 @@ bool ViewProviderChamfer::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); - //if(ModNum == 1) - // Gui::Command::openCommand("Change chamfer parameters"); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); // start the edit dialog if (padDlg) @@ -103,10 +104,10 @@ bool ViewProviderChamfer::setEdit(int ModNum) void ViewProviderChamfer::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default ) { - // and update the pad - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default ) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp index e7f4545f8241..7d8b60f0770b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp @@ -85,8 +85,9 @@ bool ViewProviderDraft::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); - //if(ModNum == 1) - // Gui::Command::openCommand("Change draft parameters"); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); // start the edit dialog if (draftDlg) @@ -103,10 +104,10 @@ bool ViewProviderDraft::setEdit(int ModNum) void ViewProviderDraft::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default ) { - // and update the draft - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default ) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp index 28fda0583fe1..0882ce5760a3 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp @@ -85,8 +85,9 @@ bool ViewProviderFillet::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); - //if(ModNum == 1) - // Gui::Command::openCommand("Change fillet parameters"); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); // start the edit dialog if (padDlg) @@ -103,10 +104,10 @@ bool ViewProviderFillet::setEdit(int ModNum) void ViewProviderFillet::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default ) { - // and update the pad - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default ) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp index fbe733e5c5c8..cbfa9b3d3c5a 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp @@ -102,8 +102,9 @@ bool ViewProviderGroove::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); - //if (ModNum == 1) - // Gui::Command::openCommand("Change Groove parameters"); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); // start the edit dialog if (padDlg) @@ -120,10 +121,10 @@ bool ViewProviderGroove::setEdit(int ModNum) void ViewProviderGroove::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default) { - // and update the pad - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp b/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp index cb0e256a9601..f23c64b89d91 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp @@ -46,6 +46,9 @@ bool ViewProviderLinearPattern::setEdit(int ModNum) TaskDlgLinearPatternParameters *linearpatternDlg = NULL; if (checkDlgOpen(linearpatternDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (linearpatternDlg) Gui::Control().showDialog(linearpatternDlg); diff --git a/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp b/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp index dece48ea2191..cd7c14c56483 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp @@ -46,6 +46,9 @@ bool ViewProviderMirrored::setEdit(int ModNum) TaskDlgMirroredParameters *mirroredDlg = NULL; if (checkDlgOpen(mirroredDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (mirroredDlg) Gui::Control().showDialog(mirroredDlg); diff --git a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp index 839e28ff00db..86105a19b8d9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp @@ -46,6 +46,9 @@ bool ViewProviderMultiTransform::setEdit(int ModNum) TaskDlgMultiTransformParameters *multitransformDlg = NULL; if (checkDlgOpen(multitransformDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (multitransformDlg) Gui::Control().showDialog(multitransformDlg); diff --git a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp index 0ff00ad0554d..131e8b1451d9 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp @@ -100,6 +100,9 @@ bool ViewProviderPad::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (padDlg) Gui::Control().showDialog(padDlg); @@ -115,10 +118,10 @@ bool ViewProviderPad::setEdit(int ModNum) void ViewProviderPad::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default) { - // and update the pad - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp index e21cf00bde9f..4df05c235365 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp @@ -92,8 +92,9 @@ bool ViewProviderPocket::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); - //if(ModNum == ViewProvider::Default) - // Gui::Command::openCommand("Change pocket parameters"); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); // start the edit dialog if (padDlg) @@ -110,10 +111,10 @@ bool ViewProviderPocket::setEdit(int ModNum) void ViewProviderPocket::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default ) { - // and update the pad - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default ) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp index cafefd54d99d..7ec126da5497 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp @@ -46,6 +46,9 @@ bool ViewProviderPolarPattern::setEdit(int ModNum) TaskDlgPolarPatternParameters *polarpatternDlg = NULL; if (checkDlgOpen(polarpatternDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (polarpatternDlg) Gui::Control().showDialog(polarpatternDlg); diff --git a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp index 398f8aeae7e9..caa00dd8f0c4 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp @@ -102,8 +102,9 @@ bool ViewProviderRevolution::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); - //if (ModNum == 1) - // Gui::Command::openCommand("Change revolution parameters"); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); // start the edit dialog if (padDlg) @@ -120,10 +121,10 @@ bool ViewProviderRevolution::setEdit(int ModNum) void ViewProviderRevolution::unsetEdit(int ModNum) { - if (ModNum == ViewProvider::Default) { - // and update the pad - //getSketchObject()->getDocument()->recompute(); + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp b/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp index 61df00ca4960..9a4e8f45588f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp @@ -46,6 +46,9 @@ bool ViewProviderScaled::setEdit(int ModNum) TaskDlgScaledParameters *scaledDlg = NULL; if (checkDlgOpen(scaledDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (scaledDlg) Gui::Control().showDialog(scaledDlg); diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index 55bf53d04925..7be6c4c47e6b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -51,6 +51,7 @@ #include "TaskTransformedParameters.h" #include #include +#include #include #include #include @@ -129,6 +130,9 @@ bool ViewProviderTransformed::setEdit(int ModNum) void ViewProviderTransformed::unsetEdit(int ModNum) { + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); diff --git a/src/Mod/Start/Gui/Workbench.cpp b/src/Mod/Start/Gui/Workbench.cpp index 52b3aa857f9d..619214464bbe 100644 --- a/src/Mod/Start/Gui/Workbench.cpp +++ b/src/Mod/Start/Gui/Workbench.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,12 @@ StartGui::Workbench::~Workbench() void StartGui::Workbench::activated() { + // Ensure that we don't open the Start page multiple times + QList ch = Gui::getMainWindow()->windows(); + for (QList::const_iterator c = ch.begin(); c != ch.end(); c++) + if ((*c)->windowTitle() == QObject::tr("Start page")) + return; + try { Gui::Command::doCommand(Gui::Command::Gui,"import WebGui"); Gui::Command::doCommand(Gui::Command::Gui,"from StartPage import StartPage"); From 1c1531278cb659557c3c55fa77eb55fccdb30849 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 27 Apr 2013 20:40:52 +0430 Subject: [PATCH 089/664] Specialized viewproviders for datum features, create points from intersection of edges and faces --- src/Mod/PartDesign/App/Body.cpp | 16 +- src/Mod/PartDesign/App/Body.h | 8 +- src/Mod/PartDesign/App/BodyPyImp.cpp | 13 +- src/Mod/PartDesign/App/DatumFeature.cpp | 274 +++++++++++------- src/Mod/PartDesign/App/DatumFeature.h | 68 ++--- src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 3 + src/Mod/PartDesign/Gui/Command.cpp | 10 +- .../PartDesign/Gui/TaskDatumParameters.cpp | 14 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 172 ++++++++++- src/Mod/PartDesign/Gui/ViewProviderDatum.h | 51 +++- 10 files changed, 456 insertions(+), 173 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index afa7f05da288..fb6632772769 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -180,8 +180,20 @@ const bool Body::isAfterTip(const App::DocumentObject *f) { const bool Body::isSolidFeature(const App::DocumentObject* f) { - return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) && - !f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())); + if (f == NULL) + return false; + + return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())); +} + +const bool Body::isAllowed(const App::DocumentObject* f) +{ + if (f == NULL) + return false; + + return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || + f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) || + f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); } Body* Body::findBodyOf(const App::DocumentObject* f) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 3ce3d159bf71..18b58d84edda 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -90,11 +90,17 @@ class Body : public Part::BodyBase /** * Return true if the given feature is a solid feature allowed in a Body. Currently this is only valid - * for features derived from PartDesign::Feature with the exception of PartDesign::Datum features + * for features derived from PartDesign::Feature * Return false if the given feature is a Sketch or a PartDesign::Datum feature */ static const bool isSolidFeature(const App::DocumentObject* f); + /** + * Return true if the given feature is allowed in a Body. Currently allowed are + * all features derived from PartDesign::Feature and PartDesign::Datum and sketches + */ + static const bool isAllowed(const App::DocumentObject* f); + /// Return the body which this feature belongs too, or NULL static Body* findBodyOf(const App::DocumentObject* f); diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp index 8bc88ca600a7..f66754810648 100644 --- a/src/Mod/PartDesign/App/BodyPyImp.cpp +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -32,14 +32,13 @@ int BodyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) PyObject* BodyPy::addFeature(PyObject *args) { PyObject* featurePy; - if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) + if (!PyArg_ParseTuple(args, "O!", &(App::DocumentObjectPy::Type), &featurePy)) return 0; - Part::Feature* feature = static_cast(featurePy)->getFeaturePtr(); + App::DocumentObject* feature = static_cast(featurePy)->getDocumentObjectPtr(); - if (!feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) && - !feature->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - PyErr_SetString(PyExc_SystemError, "Only PartDesign features and sketches can be inserted into a Body"); + if (!Body::isAllowed(feature)) { + PyErr_SetString(PyExc_SystemError, "Only PartDesign features, datum features and sketches can be inserted into a Body"); return 0; } Body* body = this->getBodyPtr(); @@ -57,10 +56,10 @@ PyObject* BodyPy::addFeature(PyObject *args) PyObject* BodyPy::removeFeature(PyObject *args) { PyObject* featurePy; - if (!PyArg_ParseTuple(args, "O!", &(Part::PartFeaturePy::Type), &featurePy)) + if (!PyArg_ParseTuple(args, "O!", &(App::DocumentObjectPy::Type), &featurePy)) return 0; - Part::Feature* feature = static_cast(featurePy)->getFeaturePtr(); + App::DocumentObject* feature = static_cast(featurePy)->getDocumentObjectPtr(); Body* body = this->getBodyPtr(); try { diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp index 75a95ca53d51..416c4f913f62 100644 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -30,23 +30,34 @@ # include # include # include +# include # include # include # include +# include +# include # include # include +# include +# include +# include # include # include # include # include +# include +# include +# include +# include # include #endif - +#include #include #include "DatumFeature.h" #include #include +#include #include "Mod/Part/App/PrimitiveFeature.h" #ifndef M_PI @@ -55,7 +66,7 @@ using namespace PartDesign; -PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, PartDesign::Feature) +PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::DocumentObject) Datum::Datum(void) { @@ -68,12 +79,11 @@ Datum::~Datum() { } -short Datum::mustExecute(void) const + +App::DocumentObjectExecReturn *Datum::execute(void) { - if (References.isTouched() || - Values.isTouched()) - return 1; - return Feature::mustExecute(); + References.touch(); + return StdReturn; } void Datum::onChanged(const App::Property* prop) @@ -88,16 +98,22 @@ void Datum::onChanged(const App::Property* prop) refTypes.insert(getRefType(refs[r], refnames[r])); } - PartDesign::Feature::onChanged(prop); + App::DocumentObject::onChanged(prop); +} + +void Datum::onDocumentRestored() +{ + // This seems to be the only way to make the ViewProvider display the datum feature + References.touch(); + App::DocumentObject::onDocumentRestored(); } // Note: We don't distinguish between e.g. datum lines and edges here -// These values are just markers so it doesn't matter that they are Part features -#define PLANE Part::Plane::getClassTypeId() -#define LINE Part::Line::getClassTypeId() -#define POINT Part::Vertex::getClassTypeId() +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") -const Base::Type Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) +const QString Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) { Base::Type type = obj->getTypeId(); @@ -122,15 +138,15 @@ const Base::Type Datum::getRefType(const App::DocumentObject* obj, const std::st // ================================ Initialize the hints ===================== -std::map, std::set > Point::hints = std::map, std::set >(); +std::map, std::set > Point::hints = std::map, std::set >(); void Point::initHints() { - std::set DONE; - DONE.insert(PartDesign::Point::getClassTypeId()); + std::set DONE; + DONE.insert(QObject::tr("Point")); - std::multiset key; - std::set value; + std::multiset key; + std::set value; key.insert(POINT); hints[key] = DONE; // POINT -> DONE. Point from another point or vertex @@ -166,15 +182,15 @@ void Point::initHints() hints[key] = value; } -std::map, std::set > Line::hints = std::map, std::set >(); +std::map, std::set > Line::hints = std::map, std::set >(); void Line::initHints() { - std::set DONE; - DONE.insert(PartDesign::Line::getClassTypeId()); + std::set DONE; + DONE.insert(QObject::tr("Line")); - std::multiset key; - std::set value; + std::multiset key; + std::set value; key.insert(LINE); hints[key] = DONE; // LINE -> DONE. Line from another line or edge @@ -201,15 +217,15 @@ void Line::initHints() hints[key] = value; } -std::map, std::set > Plane::hints = std::map, std::set >(); +std::map, std::set > Plane::hints = std::map, std::set >(); void Plane::initHints() { - std::set DONE; - DONE.insert(PartDesign::Plane::getClassTypeId()); + std::set DONE; + DONE.insert(QObject::tr("Plane")); - std::multiset key; - std::set value; + std::multiset key; + std::set value; key.insert(PLANE); hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face @@ -247,71 +263,138 @@ PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) Point::Point() { + ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,1)),"DatumPoint", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the datum point"); } Point::~Point() { } -short Point::mustExecute() const +void Point::onChanged(const App::Property* prop) { - return PartDesign::Datum::mustExecute(); -} + Datum::onChanged(prop); -App::DocumentObjectExecReturn *Point::execute(void) -{ - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(PartDesign::Point::getClassTypeId()) != hint.end()))) - return App::DocumentObject::StdReturn; // incomplete references - - // Extract the shapes of the references - std::vector shapes; - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - for (int i = 0; i < refs.size(); i++) { - if (!refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("PartDesign::Point: Invalid reference type"); - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return new App::DocumentObjectExecReturn("PartDesign::Point: Reference has NULL shape"); - if (refnames[i].empty()) { - // Datum feature or App::Plane - shapes.push_back(sh); - } else { - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return new App::DocumentObjectExecReturn("PartDesign::Point: Reference has NULL subshape"); - shapes.push_back(subshape); + if (prop == &References) { + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Point")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + Base::Vector3f* point = NULL; + Handle_Geom_Curve c1 = NULL; + Handle_Geom_Curve c2 = NULL; + Handle_Geom_Surface s1 = NULL; + Handle_Geom_Surface s2 = NULL; + Handle_Geom_Surface s3 = NULL; + + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Point: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Point: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + Standard_Real first, last; + if (c1.IsNull()) + c1 = BRep_Tool::Curve(e, first, last); + else + c2 = BRep_Tool::Curve(e, first, last); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + if (s1.IsNull()) + s1 = BRep_Tool::Surface(f); + else if (s2.IsNull()) + s2 = BRep_Tool::Surface(f); + else + s3 = BRep_Tool::Surface(f); + } + } else { + return; //"PartDesign::Point: Invalid reference type" + } } - } - // Find the point - gp_Pnt point(0,0,0); + if (point != NULL) { + // Point from vertex or other point. Nothing to be done + } else if (!c1.IsNull()) { + if (!c2.IsNull()) { + // Point from intersection of two curves + GeomAPI_ExtremaCurveCurve intersector(c1, c2); + if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) + return; // No intersection + // Note: We don't check for multiple intersection points + gp_Pnt p, p2; + intersector.Points(1, p, p2); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else if (!s1.IsNull()) { + GeomAPI_IntCS intersector(c1, s1); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from curve and surface"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else + return; + } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { + GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); + if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) + return; + if (intersectorSS.NbLines() > 1) + Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Handle_Geom_Curve line = intersectorSS.Line(1); + + GeomAPI_IntCS intersector(line, s3); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from surfaces"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else { + return; + } - if (shapes.size() == 1) { - // Point from vertex or other point - if (shapes[0].ShapeType() != TopAbs_VERTEX) - return new App::DocumentObjectExecReturn("PartDesign::Point::execute(): Internal error, unexpected ShapeType"); - TopoDS_Vertex v = TopoDS::Vertex(shapes[0]); - //point.X = v. + _Point.setValue(*point); + _Point.touch(); // This triggers ViewProvider::updateData() + delete point; } - - BRepBuilderAPI_MakeVertex MakeVertex(point); - const TopoDS_Vertex& vertex = MakeVertex.Vertex(); - this->Shape.setValue(vertex); - - return App::DocumentObject::StdReturn; } -const std::set Point::getHint() +const std::set Point::getHint() { if (hints.find(refTypes) != hints.end()) return hints[refTypes]; else - return std::set(); + return std::set(); } @@ -325,33 +408,22 @@ Line::~Line() { } -short Line::mustExecute() const -{ - return PartDesign::Datum::mustExecute(); -} - -App::DocumentObjectExecReturn *Line::execute(void) +void Line::onChanged(const App::Property *prop) { gp_Pnt point1(0,0,0); gp_Pnt point2(10,10,10); - BRepBuilderAPI_MakeEdge mkEdge(point1, point2); - if (!mkEdge.IsDone()) - return new App::DocumentObjectExecReturn("Failed to create edge"); - const TopoDS_Edge& edge = mkEdge.Edge(); - this->Shape.setValue(edge); - - return App::DocumentObject::StdReturn; + return; } -const std::set Line::getHint() +const std::set Line::getHint() { if (hints.find(refTypes) != hints.end()) return hints[refTypes]; else - return std::set(); + return std::set(); } @@ -361,39 +433,25 @@ Plane::Plane() { } -short Plane::mustExecute() const -{ - return PartDesign::Datum::mustExecute(); -} - -App::DocumentObjectExecReturn *Plane::execute(void) +void Plane::onChanged(const App::Property *prop) { double O = 10.0; //this->Offset.getValue(); double A = 45.0; //this->Angle.getValue(); if (fabs(A) > 360.0) - return new App::DocumentObjectExecReturn("Angle too large (please use -360.0 .. +360.0)"); + return; // "Angle too large (please use -360.0 .. +360.0)" gp_Pnt pnt(0.0,0.0,0.0); gp_Dir dir(0.0,0.0,1.0); - Handle_Geom_Plane aPlane = new Geom_Plane(pnt, dir); - BRepBuilderAPI_MakeFace mkFace(aPlane, 0.0, 100.0, 0.0, 100.0 -#if OCC_VERSION_HEX >= 0x060502 - , Precision::Confusion() -#endif - ); - - TopoDS_Shape ResultShape = mkFace.Shape(); - this->Shape.setValue(ResultShape); - return App::DocumentObject::StdReturn; + return; } -const std::set Plane::getHint() +const std::set Plane::getHint() { if (hints.find(refTypes) != hints.end()) return hints[refTypes]; else - return std::set(); + return std::set(); } diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index 7e4f6d7a8511..99a4bbf75d59 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -24,14 +24,14 @@ #ifndef PARTDESIGN_DATUMFEATURE_H #define PARTDESIGN_DATUMFEATURE_H -//#include +#include #include #include "Feature.h" namespace PartDesign { -class PartDesignExport Datum : public PartDesign::Feature +class PartDesignExport Datum : public App::DocumentObject { PROPERTY_HEADER(PartDesign::Datum); @@ -44,26 +44,24 @@ class PartDesignExport Datum : public PartDesign::Feature /// The values defining the datum object, e.g. the offset from a Reference plane App::PropertyFloatList Values; - /** @name methods override feature */ - //@{ /// recalculate the feature - App::DocumentObjectExecReturn *execute(void) = 0; - short mustExecute() const; + App::DocumentObjectExecReturn *execute(void); + /// returns the type name of the view provider const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderDatum"; } - //@} - virtual const std::set getHint() = 0; + virtual const std::set getHint() = 0; protected: void onChanged (const App::Property* prop); + void onDocumentRestored(); protected: - std::multiset refTypes; + std::multiset refTypes; - static const Base::Type getRefType(const App::DocumentObject* obj, const std::string& subname); + static const QString getRefType(const App::DocumentObject* obj, const std::string& subname); }; @@ -72,22 +70,24 @@ class PartDesignExport Point : public PartDesign::Datum PROPERTY_HEADER(PartDesign::Point); public: + App::PropertyVector _Point; + Point(); virtual ~Point(); - /** @name methods override feature */ - //@{ - /// recalculate the Feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - //@} + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatumPoint"; + } static void initHints(); - const std::set getHint(); + const std::set getHint(); + +protected: + virtual void onChanged(const App::Property* prop); private: // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; + static std::map, std::set > hints; }; class PartDesignExport Line : public PartDesign::Datum @@ -98,19 +98,19 @@ class PartDesignExport Line : public PartDesign::Datum Line(); virtual ~Line(); - /** @name methods override feature */ - //@{ - /// recalculate the Feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - //@} + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatumLine"; + } static void initHints(); - const std::set getHint(); + const std::set getHint(); + +protected: + virtual void onChanged(const App::Property* prop); private: // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; + static std::map, std::set > hints; }; class PartDesignExport Plane : public PartDesign::Datum @@ -120,19 +120,19 @@ class PartDesignExport Plane : public PartDesign::Datum public: Plane(); - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - //@} + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatumPlane"; + } static void initHints(); - const std::set getHint(); + const std::set getHint(); + +protected: + virtual void onChanged(const App::Property* prop); private: // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; + static std::map, std::set > hints; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index bec1ad5d8da4..2b26c6afe922 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -121,6 +121,9 @@ PyMODINIT_FUNC initPartDesignGui() PartDesignGui::ViewProviderScaled ::init(); PartDesignGui::ViewProviderMultiTransform::init(); PartDesignGui::ViewProviderDatum ::init(); + PartDesignGui::ViewProviderDatumPoint ::init(); + PartDesignGui::ViewProviderDatumLine ::init(); + PartDesignGui::ViewProviderDatumPlane ::init(); // add resources and reloads the translators loadPartDesignResource(); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 766860f168d6..5277285edf15 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -611,20 +611,16 @@ void CmdPartDesignNewSketch::activated(int iMsg) firstValidPlane = planes.begin(); } - //TODO: Allow user to choose front or back of the plane - - App::Plane* plane = static_cast(*firstValidPlane); - Base::Vector3d p = plane->Placement.getValue().getPosition(); - Base::Rotation r = plane->Placement.getValue().getRotation(); + // TODO: Allow user to choose front or back of the plane + App::Plane* plane = static_cast(*firstValidPlane); std::string FeatName = getUniqueObjectName("Sketch"); std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", ['front'])"; openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - //doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))", - // FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + updateActive(); // Make sure the Support's Placement property is updated doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 46e114f56e95..0adfb5f1a9f4 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -168,16 +168,16 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p updateUI(); } -const QString makeRefText(std::set hint) +const QString makeRefText(std::set hint) { QString result; - for (std::set::const_iterator t = hint.begin(); t != hint.end(); t++) { + for (std::set::const_iterator t = hint.begin(); t != hint.end(); t++) { QString tText; - if (((*t) == Part::Plane::getClassTypeId()) || ((*t) == PartDesign::Plane::getClassTypeId())) + if (((*t) == QObject::tr("DPLANE")) || ((*t) == QObject::tr("Plane"))) tText = QObject::tr("Plane"); - else if (((*t) == Part::Line::getClassTypeId()) || ((*t) == PartDesign::Line::getClassTypeId())) + else if (((*t) == QObject::tr("DLINE")) || ((*t) == QObject::tr("Line"))) tText = QObject::tr("Line"); - else if (((*t) == Part::Vertex::getClassTypeId()) || ((*t) == PartDesign::Point::getClassTypeId())) + else if (((*t) == QObject::tr("DPOINT")) || ((*t) == QObject::tr("Point"))) tText = QObject::tr("Point"); result += QString::fromAscii(result.size() == 0 ? "" : "/") + tText; } @@ -200,8 +200,8 @@ void TaskDatumParameters::updateUI() } // Get hints for further required references - std::set hint = pcDatum->getHint(); - if (hint == std::set()) { + std::set hint = pcDatum->getHint(); + if (hint == std::set()) { QMessageBox::warning(this, tr("Illegal selection"), tr("This feature cannot be created with this combination of references")); if (refs.size() == 1) { onButtonRef1(true); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 3275075691ea..2bbfd9c63489 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -27,6 +27,15 @@ # include # include # include +# include +# include +# include +# include +# include +# include +# include +# include +# include #endif #include "ViewProviderDatum.h" @@ -34,22 +43,26 @@ #include "Workbench.h" #include #include +#include using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderDatum,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatum,Gui::ViewProviderGeometryObject) ViewProviderDatum::ViewProviderDatum() { + pShapeSep = new SoSeparator(); + pShapeSep->ref(); } ViewProviderDatum::~ViewProviderDatum() { + pShapeSep->unref(); } void ViewProviderDatum::attach(App::DocumentObject *obj) { - ViewProvider::attach(obj); + ViewProviderDocumentObject::attach(obj); PartDesign::Datum* pcDatum = static_cast(getObject()); if (pcDatum->getTypeId() == PartDesign::Plane::getClassTypeId()) @@ -58,6 +71,42 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) datumType = QObject::tr("Line"); else if (pcDatum->getTypeId() == PartDesign::Point::getClassTypeId()) datumType = QObject::tr("Point"); + + SoSeparator* sep = new SoSeparator(); + SoShapeHints* hints = new SoShapeHints(); + hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE); + hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); + SoBaseColor* color = new SoBaseColor(); + color->rgb.setValue(0.9, 0.9, 0.2); + sep->addChild(hints); + sep->addChild(color); + sep->addChild(pShapeSep); + addDisplayMaskMode(sep, "Base"); +} + +std::vector ViewProviderDatum::getDisplayModes(void) const +{ + // add modes + std::vector StrList; + StrList.push_back("Base"); + return StrList; +} + +void ViewProviderDatum::setDisplayMode(const char* ModeName) +{ + if (strcmp(ModeName, "Base") == 0) + setDisplayMaskMode("Base"); + ViewProviderDocumentObject::setDisplayMode(ModeName); +} + +void ViewProviderDatum::onChanged(const App::Property* prop) +{ + /*if (prop == &Shape) { + updateData(prop); + } + else {*/ + ViewProviderDocumentObject::onChanged(prop); + //} } void ViewProviderDatum::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) @@ -65,11 +114,14 @@ void ViewProviderDatum::setupContextMenu(QMenu* menu, QObject* receiver, const c QAction* act; act = menu->addAction(QObject::tr("Edit datum ") + datumType, receiver, member); act->setData(QVariant((int)ViewProvider::Default)); - PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); + Gui::ViewProviderGeometryObject::setupContextMenu(menu, receiver, member); } bool ViewProviderDatum::setEdit(int ModNum) { + if (!ViewProvider::setEdit(ModNum)) + return false; + if (ModNum == ViewProvider::Default ) { // When double-clicking on the item for this datum feature the // object unsets and sets its edit mode without closing @@ -94,6 +146,9 @@ bool ViewProviderDatum::setEdit(int ModNum) // clear the selection (convenience) Gui::Selection().clearSelection(); + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + // start the edit dialog if (datumDlg) Gui::Control().showDialog(datumDlg); @@ -103,19 +158,126 @@ bool ViewProviderDatum::setEdit(int ModNum) return true; } else { - return ViewProviderPart::setEdit(ModNum); + return ViewProvider::setEdit(ModNum); } } void ViewProviderDatum::unsetEdit(int ModNum) { + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); } else { - PartGui::ViewProviderPart::unsetEdit(ModNum); + Gui::ViewProviderGeometryObject::unsetEdit(ModNum); + } +} + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPoint,PartDesignGui::ViewProviderDatum) + +ViewProviderDatumPoint::ViewProviderDatumPoint() +{ + SoMarkerSet* points = new SoMarkerSet(); + points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; + points->numPoints = 1; + pShapeSep->addChild(points); +} + +ViewProviderDatumPoint::~ViewProviderDatumPoint() +{ + +} + +void ViewProviderDatumPoint::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + PartDesign::Point* pcDatum = static_cast(this->getObject()); + + if (strcmp(prop->getName(),"_Point") == 0) { + Base::Vector3f p = pcDatum->_Point.getValue(); + SoMFVec3f v; + v.set1Value(0, p.x, p.y, p.z); + SoVertexProperty* vprop = new SoVertexProperty(); + vprop->vertex = v; + SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); + points->vertexProperty = vprop; } + + ViewProviderDatum::updateData(prop); +} + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProviderDatum) + +ViewProviderDatumLine::ViewProviderDatumLine() +{ + /* + SoMarkerSet* points = new SoMarkerSet(); + points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; + points->numPoints = 1; + pShapeSep->addChild(points); + */ +} + +ViewProviderDatumLine::~ViewProviderDatumLine() +{ + +} + +void ViewProviderDatumLine::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + PartDesign::Line* pcDatum = static_cast(this->getObject()); + + /* + if (strcmp(prop->getName(),"_Point") == 0) { + Base::Vector3f p = pcDatum->_Point.getValue(); + SoMFVec3f v; + v.set1Value(0, p.x, p.y, p.z); + SoVertexProperty* vprop = new SoVertexProperty(); + vprop->vertex = v; + SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); + points->vertexProperty = vprop; + }*/ + + ViewProviderDatum::updateData(prop); +} + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProviderDatum) + +ViewProviderDatumPlane::ViewProviderDatumPlane() +{ + /* + SoMarkerSet* points = new SoMarkerSet(); + points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; + points->numPoints = 1; + pShapeSep->addChild(points); + */ +} + +ViewProviderDatumPlane::~ViewProviderDatumPlane() +{ + +} + +void ViewProviderDatumPlane::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + PartDesign::Plane* pcDatum = static_cast(this->getObject()); +/* + if (strcmp(prop->getName(),"_Point") == 0) { + Base::Vector3f p = pcDatum->_Point.getValue(); + SoMFVec3f v; + v.set1Value(0, p.x, p.y, p.z); + SoVertexProperty* vprop = new SoVertexProperty(); + vprop->vertex = v; + SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); + points->vertexProperty = vprop; + }*/ + + ViewProviderDatum::updateData(prop); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.h b/src/Mod/PartDesign/Gui/ViewProviderDatum.h index acb4a89b3d41..bde60f4e727d 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.h @@ -24,11 +24,11 @@ #ifndef PARTGUI_ViewProviderDatum_H #define PARTGUI_ViewProviderDatum_H -#include "ViewProvider.h" +#include "Gui/ViewProviderGeometryObject.h" namespace PartDesignGui { -class PartDesignGuiExport ViewProviderDatum : public ViewProvider +class PartDesignGuiExport ViewProviderDatum : public Gui::ViewProviderGeometryObject { PROPERTY_HEADER(PartDesignGui::ViewProviderDatum); @@ -42,14 +42,61 @@ class PartDesignGuiExport ViewProviderDatum : public ViewProvider void setupContextMenu(QMenu*, QObject*, const char*); virtual void attach(App::DocumentObject *); + virtual void updateData(const App::Property* prop) { Gui::ViewProviderGeometryObject::updateData(prop); } + std::vector getDisplayModes(void) const; + void setDisplayMode(const char* ModeName); /// The datum type (Plane, Line or Point) QString datumType; protected: + void onChanged(const App::Property* prop); virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); +protected: + SoSeparator* pShapeSep; + std::string oldWb; + +}; + +class PartDesignGuiExport ViewProviderDatumPoint : public PartDesignGui::ViewProviderDatum +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatumPoint); + +public: + /// Constructor + ViewProviderDatumPoint(); + virtual ~ViewProviderDatumPoint(); + + virtual void updateData(const App::Property*); + +}; + +class PartDesignGuiExport ViewProviderDatumLine : public PartDesignGui::ViewProviderDatum +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatumLine); + +public: + /// Constructor + ViewProviderDatumLine(); + virtual ~ViewProviderDatumLine(); + + virtual void updateData(const App::Property*); + +}; + +class PartDesignGuiExport ViewProviderDatumPlane : public PartDesignGui::ViewProviderDatum +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatumPlane); + +public: + /// Constructor + ViewProviderDatumPlane(); + virtual ~ViewProviderDatumPlane(); + + virtual void updateData(const App::Property*); + }; From b7fe543ca9fef3c7a00b25e5a1eeb0a9176811e7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 29 Apr 2013 20:30:48 +0430 Subject: [PATCH 090/664] Fix compile error after rebase --- src/Base/Reader.cpp | 18 +- src/Mod/PartDesign/App/DatumFeature.cpp | 457 ------------------------ 2 files changed, 9 insertions(+), 466 deletions(-) delete mode 100644 src/Mod/PartDesign/App/DatumFeature.cpp diff --git a/src/Base/Reader.cpp b/src/Base/Reader.cpp index 61ff60649518..b5c8fc1120df 100644 --- a/src/Base/Reader.cpp +++ b/src/Base/Reader.cpp @@ -393,15 +393,15 @@ bool Base::XMLReader::doNameMapping() const // --------------------------------------------------------------------------- // Base::XMLReader: Implementation of the SAX DocumentHandler interface // --------------------------------------------------------------------------- -void Base::XMLReader::startDocument() -{ - ReadType = StartDocument; -} - -void Base::XMLReader::endDocument() -{ - ReadType = EndDocument; -} +void Base::XMLReader::startDocument() +{ + ReadType = StartDocument; +} + +void Base::XMLReader::endDocument() +{ + ReadType = EndDocument; +} void Base::XMLReader::startElement(const XMLCh* const /*uri*/, const XMLCh* const localname, const XMLCh* const /*qname*/, const XERCES_CPP_NAMESPACE_QUALIFIER Attributes& attrs) { diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp deleted file mode 100644 index 416c4f913f62..000000000000 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Jan Rheinländer * - * * - * 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 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - -#include -#include -#include "DatumFeature.h" -#include -#include -#include -#include "Mod/Part/App/PrimitiveFeature.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -using namespace PartDesign; - -PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::DocumentObject) - -Datum::Datum(void) -{ - ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); - ADD_PROPERTY(Values,(0.0)); - touch(); -} - -Datum::~Datum() -{ -} - - -App::DocumentObjectExecReturn *Datum::execute(void) -{ - References.touch(); - return StdReturn; -} - -void Datum::onChanged(const App::Property* prop) -{ - - if (prop == &References) { - refTypes.clear(); - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - - for (int r = 0; r < refs.size(); r++) - refTypes.insert(getRefType(refs[r], refnames[r])); - } - - App::DocumentObject::onChanged(prop); -} - -void Datum::onDocumentRestored() -{ - // This seems to be the only way to make the ViewProvider display the datum feature - References.touch(); - App::DocumentObject::onDocumentRestored(); -} - -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define LINE QObject::tr("DLINE") -#define POINT QObject::tr("DPOINT") - -const QString Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) -{ - Base::Type type = obj->getTypeId(); - - if ((type == App::Plane::getClassTypeId()) || (type == PartDesign::Plane::getClassTypeId())) - return PLANE; - else if (type == PartDesign::Line::getClassTypeId()) - return LINE; - else if (type == PartDesign::Point::getClassTypeId()) - return POINT; - else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { - // Note: For now, only planar references are possible - if (subname.size() > 4 && subname.substr(0,4) == "Face") - return PLANE; - else if (subname.size() > 4 && subname.substr(0,4) == "Edge") - return LINE; - else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") - return POINT; - } - - throw Base::Exception("PartDesign::Datum::getRefType(): Illegal object type"); -} - -// ================================ Initialize the hints ===================== - -std::map, std::set > Point::hints = std::map, std::set >(); - -void Point::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Point")); - - std::multiset key; - std::set value; - key.insert(POINT); - hints[key] = DONE; // POINT -> DONE. Point from another point or vertex - - key.clear(); value.clear(); - key.insert(LINE); - value.insert(LINE); value.insert(PLANE); - hints[key] = value; // LINE -> LINE or PLANE - - key.clear(); value.clear(); - key.insert(LINE); key.insert(LINE); - hints[key] = DONE; // {LINE, LINE} -> DONE. Point from two lines or edges - - key.clear(); value.clear(); - key.insert(LINE); key.insert(PLANE); - hints[key] = DONE; // {LINE, PLANE} -> DONE. Point from line and plane - - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(PLANE); value.insert(LINE); - hints[key] = value; // PLANE -> PLANE or LINE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); - value.insert(PLANE); - hints[key] = value; // {PLANE, PLANE} -> PLANE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); key.insert(PLANE); - hints[key] = DONE; // {PLANE, PLANE, PLANE} -> DONE. Point from three planes - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} - -std::map, std::set > Line::hints = std::map, std::set >(); - -void Line::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Line")); - - std::multiset key; - std::set value; - key.insert(LINE); - hints[key] = DONE; // LINE -> DONE. Line from another line or edge - - key.clear(); value.clear(); - key.insert(POINT); - value.insert(POINT); - hints[key] = value; // POINT -> POINT - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); - hints[key] = DONE; // {POINT, POINT} -> DONE. Line from two points or vertices - - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(PLANE); - hints[key] = value; // PLANE -> PLANE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); - hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} - -std::map, std::set > Plane::hints = std::map, std::set >(); - -void Plane::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Plane")); - - std::multiset key; - std::set value; - key.insert(PLANE); - hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face - - key.clear(); value.clear(); - key.insert(POINT); - value.insert(POINT); value.insert(LINE); - hints[key] = value; // POINT -> POINT or LINE - - key.clear(); value.clear(); - key.insert(POINT); key.insert(LINE); - hints[key] = DONE; // {POINT, LINE} -> DONE. Plane from point/vertex and line/edge - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); - value.insert(POINT); - hints[key] = value; // {POINT, POINT} -> POINT - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); key.insert(POINT); - hints[key] = DONE; // {POINT, POINT, POINT} -> DONE. Plane from 3 points or vertices - - key.clear(); value.clear(); - key.insert(LINE); - value.insert(POINT); - hints[key] = value; // LINE -> POINT - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} - -// ============================================================================ - -PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) - -Point::Point() -{ - ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,1)),"DatumPoint", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the datum point"); -} - -Point::~Point() -{ -} - -void Point::onChanged(const App::Property* prop) -{ - Datum::onChanged(prop); - - if (prop == &References) { - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Point")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - Base::Vector3f* point = NULL; - Handle_Geom_Curve c1 = NULL; - Handle_Geom_Curve c2 = NULL; - Handle_Geom_Surface s1 = NULL; - Handle_Geom_Surface s2 = NULL; - Handle_Geom_Surface s3 = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - point = new Base::Vector3f (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - //point = new Base::Vector3f (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - //point = new Base::Vector3f (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - //point = new Base::Vector3f (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Point: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Point: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - Standard_Real first, last; - if (c1.IsNull()) - c1 = BRep_Tool::Curve(e, first, last); - else - c2 = BRep_Tool::Curve(e, first, last); - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - if (s1.IsNull()) - s1 = BRep_Tool::Surface(f); - else if (s2.IsNull()) - s2 = BRep_Tool::Surface(f); - else - s3 = BRep_Tool::Surface(f); - } - } else { - return; //"PartDesign::Point: Invalid reference type" - } - } - - if (point != NULL) { - // Point from vertex or other point. Nothing to be done - } else if (!c1.IsNull()) { - if (!c2.IsNull()) { - // Point from intersection of two curves - GeomAPI_ExtremaCurveCurve intersector(c1, c2); - if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) - return; // No intersection - // Note: We don't check for multiple intersection points - gp_Pnt p, p2; - intersector.Points(1, p, p2); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); - } else if (!s1.IsNull()) { - GeomAPI_IntCS intersector(c1, s1); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - return; - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from curve and surface"); - - gp_Pnt p = intersector.Point(1); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); - } else - return; - } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { - GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); - if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) - return; - if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection line for datum point from surfaces"); - Handle_Geom_Curve line = intersectorSS.Line(1); - - GeomAPI_IntCS intersector(line, s3); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - return; - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from surfaces"); - - gp_Pnt p = intersector.Point(1); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); - } else { - return; - } - - _Point.setValue(*point); - _Point.touch(); // This triggers ViewProvider::updateData() - delete point; - } -} - - -const std::set Point::getHint() -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - - -PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) - -Line::Line() -{ -} - -Line::~Line() -{ -} - -void Line::onChanged(const App::Property *prop) -{ - gp_Pnt point1(0,0,0); - - gp_Pnt point2(10,10,10); - - return; -} - - -const std::set Line::getHint() -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - - -PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) - -Plane::Plane() -{ -} - -void Plane::onChanged(const App::Property *prop) -{ - double O = 10.0; //this->Offset.getValue(); - double A = 45.0; //this->Angle.getValue(); - - if (fabs(A) > 360.0) - return; // "Angle too large (please use -360.0 .. +360.0)" - - gp_Pnt pnt(0.0,0.0,0.0); - gp_Dir dir(0.0,0.0,1.0); - - return; -} - - -const std::set Plane::getHint() -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} From 6effd7d864ae741095ddb7d7c18cd409744f4728 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 29 Apr 2013 20:31:18 +0430 Subject: [PATCH 091/664] Visualization of datum lines and planes --- src/Mod/PartDesign/App/DatumFeature.cpp | 457 ++++++++++++++++++ src/Mod/PartDesign/App/DatumFeature.h | 6 + src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 241 +++++++-- .../Gui/ViewProviderTransformed.cpp | 1 + 4 files changed, 669 insertions(+), 36 deletions(-) create mode 100644 src/Mod/PartDesign/App/DatumFeature.cpp diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp new file mode 100644 index 000000000000..bb6861f11aa6 --- /dev/null +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -0,0 +1,457 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include "DatumFeature.h" +#include +#include +#include +#include "Mod/Part/App/PrimitiveFeature.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace PartDesign; + +PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::DocumentObject) + +Datum::Datum(void) +{ + ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); + ADD_PROPERTY(Values,(0.0)); + touch(); +} + +Datum::~Datum() +{ +} + + +App::DocumentObjectExecReturn *Datum::execute(void) +{ + References.touch(); + return StdReturn; +} + +void Datum::onChanged(const App::Property* prop) +{ + + if (prop == &References) { + refTypes.clear(); + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + + for (int r = 0; r < refs.size(); r++) + refTypes.insert(getRefType(refs[r], refnames[r])); + } + + App::DocumentObject::onChanged(prop); +} + +void Datum::onDocumentRestored() +{ + // This seems to be the only way to make the ViewProvider display the datum feature + References.touch(); + App::DocumentObject::onDocumentRestored(); +} + +// Note: We don't distinguish between e.g. datum lines and edges here +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") + +const QString Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) +{ + Base::Type type = obj->getTypeId(); + + if ((type == App::Plane::getClassTypeId()) || (type == PartDesign::Plane::getClassTypeId())) + return PLANE; + else if (type == PartDesign::Line::getClassTypeId()) + return LINE; + else if (type == PartDesign::Point::getClassTypeId()) + return POINT; + else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { + // Note: For now, only planar references are possible + if (subname.size() > 4 && subname.substr(0,4) == "Face") + return PLANE; + else if (subname.size() > 4 && subname.substr(0,4) == "Edge") + return LINE; + else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") + return POINT; + } + + throw Base::Exception("PartDesign::Datum::getRefType(): Illegal object type"); +} + +// ================================ Initialize the hints ===================== + +std::map, std::set > Point::hints = std::map, std::set >(); + +void Point::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Point")); + + std::multiset key; + std::set value; + key.insert(POINT); + hints[key] = DONE; // POINT -> DONE. Point from another point or vertex + + key.clear(); value.clear(); + key.insert(LINE); + value.insert(LINE); value.insert(PLANE); + hints[key] = value; // LINE -> LINE or PLANE + + key.clear(); value.clear(); + key.insert(LINE); key.insert(LINE); + hints[key] = DONE; // {LINE, LINE} -> DONE. Point from two lines or edges + + key.clear(); value.clear(); + key.insert(LINE); key.insert(PLANE); + hints[key] = DONE; // {LINE, PLANE} -> DONE. Point from line and plane + + key.clear(); value.clear(); + key.insert(PLANE); + value.insert(PLANE); value.insert(LINE); + hints[key] = value; // PLANE -> PLANE or LINE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); + value.insert(PLANE); + hints[key] = value; // {PLANE, PLANE} -> PLANE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); key.insert(PLANE); + hints[key] = DONE; // {PLANE, PLANE, PLANE} -> DONE. Point from three planes + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +std::map, std::set > Line::hints = std::map, std::set >(); + +void Line::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Line")); + + std::multiset key; + std::set value; + key.insert(LINE); + hints[key] = DONE; // LINE -> DONE. Line from another line or edge + + key.clear(); value.clear(); + key.insert(POINT); + value.insert(POINT); + hints[key] = value; // POINT -> POINT + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); + hints[key] = DONE; // {POINT, POINT} -> DONE. Line from two points or vertices + + key.clear(); value.clear(); + key.insert(PLANE); + value.insert(PLANE); + hints[key] = value; // PLANE -> PLANE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); + hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +std::map, std::set > Plane::hints = std::map, std::set >(); + +void Plane::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Plane")); + + std::multiset key; + std::set value; + key.insert(PLANE); + hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face + + key.clear(); value.clear(); + key.insert(POINT); + value.insert(POINT); value.insert(LINE); + hints[key] = value; // POINT -> POINT or LINE + + key.clear(); value.clear(); + key.insert(POINT); key.insert(LINE); + hints[key] = DONE; // {POINT, LINE} -> DONE. Plane from point/vertex and line/edge + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); + value.insert(POINT); + hints[key] = value; // {POINT, POINT} -> POINT + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); key.insert(POINT); + hints[key] = DONE; // {POINT, POINT, POINT} -> DONE. Plane from 3 points or vertices + + key.clear(); value.clear(); + key.insert(LINE); + value.insert(POINT); + hints[key] = value; // LINE -> POINT + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +// ============================================================================ + +PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) + +Point::Point() +{ + ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,1)),"DatumPoint", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the datum point"); +} + +Point::~Point() +{ +} + +void Point::onChanged(const App::Property* prop) +{ + Datum::onChanged(prop); + + if (prop == &References) { + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Point")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + Base::Vector3f* point = NULL; + Handle_Geom_Curve c1 = NULL; + Handle_Geom_Curve c2 = NULL; + Handle_Geom_Surface s1 = NULL; + Handle_Geom_Surface s2 = NULL; + Handle_Geom_Surface s3 = NULL; + + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + point = new Base::Vector3d (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + //point = new Base::Vector3f (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Point: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Point: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + Standard_Real first, last; + if (c1.IsNull()) + c1 = BRep_Tool::Curve(e, first, last); + else + c2 = BRep_Tool::Curve(e, first, last); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + if (s1.IsNull()) + s1 = BRep_Tool::Surface(f); + else if (s2.IsNull()) + s2 = BRep_Tool::Surface(f); + else + s3 = BRep_Tool::Surface(f); + } + } else { + return; //"PartDesign::Point: Invalid reference type" + } + } + + if (point != NULL) { + // Point from vertex or other point. Nothing to be done + } else if (!c1.IsNull()) { + if (!c2.IsNull()) { + // Point from intersection of two curves + GeomAPI_ExtremaCurveCurve intersector(c1, c2); + if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) + return; // No intersection + // Note: We don't check for multiple intersection points + gp_Pnt p, p2; + intersector.Points(1, p, p2); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else if (!s1.IsNull()) { + GeomAPI_IntCS intersector(c1, s1); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from curve and surface"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else + return; + } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { + GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); + if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) + return; + if (intersectorSS.NbLines() > 1) + Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Handle_Geom_Curve line = intersectorSS.Line(1); + + GeomAPI_IntCS intersector(line, s3); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from surfaces"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + } else { + return; + } + + _Point.setValue(*point); + _Point.touch(); // This triggers ViewProvider::updateData() + delete point; + } +} + + +const std::set Point::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + + +PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) + +Line::Line() +{ +} + +Line::~Line() +{ +} + +void Line::onChanged(const App::Property *prop) +{ + gp_Pnt point1(0,0,0); + + gp_Pnt point2(10,10,10); + + return; +} + + +const std::set Line::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + + +PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) + +Plane::Plane() +{ +} + +void Plane::onChanged(const App::Property *prop) +{ + double O = 10.0; //this->Offset.getValue(); + double A = 45.0; //this->Angle.getValue(); + + if (fabs(A) > 360.0) + return; // "Angle too large (please use -360.0 .. +360.0)" + + gp_Pnt pnt(0.0,0.0,0.0); + gp_Dir dir(0.0,0.0,1.0); + + return; +} + + +const std::set Plane::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index 99a4bbf75d59..6bee01310821 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -95,6 +95,9 @@ class PartDesignExport Line : public PartDesign::Datum PROPERTY_HEADER(PartDesign::Line); public: + App::PropertyVector _Base; + App::PropertyVector _Direction; + Line(); virtual ~Line(); @@ -118,6 +121,9 @@ class PartDesignExport Plane : public PartDesign::Datum PROPERTY_HEADER(PartDesign::Plane); public: + App::PropertyVector _Base; + App::PropertyVector _Normal; + Plane(); const char* getViewProviderName(void) const { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 2bbfd9c63489..5a66b17f72ae 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -28,14 +28,22 @@ # include # include # include +# include # include +# include # include # include # include +# include +# include # include # include # include # include +# include +# include +# include +# include #endif #include "ViewProviderDatum.h" @@ -44,6 +52,7 @@ #include #include #include +#include using namespace PartDesignGui; @@ -73,13 +82,19 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) datumType = QObject::tr("Point"); SoSeparator* sep = new SoSeparator(); + SoPickStyle* ps = new SoPickStyle(); + ps->style = SoPickStyle::SHAPE; SoShapeHints* hints = new SoShapeHints(); hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE); hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); SoBaseColor* color = new SoBaseColor(); - color->rgb.setValue(0.9, 0.9, 0.2); + color->rgb.setValue(0.9, 0.9, 0.1); + SoMaterial* material = new SoMaterial(); + material->diffuseColor.setValue(0.9f, 0.9f, 0.1f); + material->transparency.setValue(0.2); sep->addChild(hints); sep->addChild(color); + sep->addChild(material); sep->addChild(pShapeSep); addDisplayMaskMode(sep, "Base"); } @@ -182,7 +197,7 @@ ViewProviderDatumPoint::ViewProviderDatumPoint() { SoMarkerSet* points = new SoMarkerSet(); points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 1; + points->numPoints = 0; pShapeSep->addChild(points); } @@ -197,13 +212,23 @@ void ViewProviderDatumPoint::updateData(const App::Property* prop) PartDesign::Point* pcDatum = static_cast(this->getObject()); if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3f p = pcDatum->_Point.getValue(); + Base::Vector3d p = pcDatum->_Point.getValue(); SoMFVec3f v; + v.setNum(1); v.set1Value(0, p.x, p.y, p.z); - SoVertexProperty* vprop = new SoVertexProperty(); - vprop->vertex = v; SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - points->vertexProperty = vprop; + + SoVertexProperty* vprop; + if (points->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + points->vertexProperty = vprop; + } else { + vprop = static_cast(points->vertexProperty.getValue()); + vprop->vertex = v; + } + + points->numPoints = 1; } ViewProviderDatum::updateData(prop); @@ -213,12 +238,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProvider ViewProviderDatumLine::ViewProviderDatumLine() { - /* - SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 1; - pShapeSep->addChild(points); - */ + SoLineSet* lineSet = new SoLineSet(); + pShapeSep->addChild(lineSet); } ViewProviderDatumLine::~ViewProviderDatumLine() @@ -231,16 +252,51 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) // Gets called whenever a property of the attached object changes PartDesign::Line* pcDatum = static_cast(this->getObject()); - /* - if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3f p = pcDatum->_Point.getValue(); + if (strcmp(prop->getName(),"_Base") == 0) { + Base::Vector3d base = pcDatum->_Base.getValue(); + Base::Vector3d dir = pcDatum->_Direction.getValue(); + + // Get limits of the line from bounding box of the body + PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + if (body == NULL) + return; + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + return; + Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + Base::Vector3d p1, p2; + if (bbox.IsInBox(base)) { + bbox.IntersectionPoint(base, dir, p1, Precision::Confusion()); + bbox.IntersectionPoint(base, -dir, p2, Precision::Confusion()); + } else { + bbox.IntersectWithLine(base, dir, p1, p2); + if ((p1 == Base::Vector3d(0,0,0)) && (p2 == Base::Vector3d(0,0,0))) + bbox.IntersectWithLine(base, -dir, p1, p2); + } + + // Display the line SoMFVec3f v; - v.set1Value(0, p.x, p.y, p.z); - SoVertexProperty* vprop = new SoVertexProperty(); - vprop->vertex = v; - SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - points->vertexProperty = vprop; - }*/ + v.setNum(2); + v.set1Value(0, p1.x, p1.y, p1.z); + v.set1Value(1, p2.x, p2.y, p2.z); + SoLineSet* lineSet = static_cast(pShapeSep->getChild(0)); + + SoVertexProperty* vprop; + if (lineSet->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + lineSet->vertexProperty = vprop; + } else { + vprop = static_cast(lineSet->vertexProperty.getValue()); + vprop->vertex = v; + } + + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, 2); + lineSet->numVertices = idx; + } ViewProviderDatum::updateData(prop); } @@ -249,12 +305,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProvide ViewProviderDatumPlane::ViewProviderDatumPlane() { - /* - SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 1; - pShapeSep->addChild(points); - */ + SoFaceSet* faceSet = new SoFaceSet(); + pShapeSep->addChild(faceSet); } ViewProviderDatumPlane::~ViewProviderDatumPlane() @@ -266,16 +318,133 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) { // Gets called whenever a property of the attached object changes PartDesign::Plane* pcDatum = static_cast(this->getObject()); -/* - if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3f p = pcDatum->_Point.getValue(); + + if (strcmp(prop->getName(),"_Base") == 0) { + Base::Vector3d base = pcDatum->_Base.getValue(); + Base::Vector3d normal = pcDatum->_Normal.getValue(); + + // Get limits of the plane from bounding box of the body + PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + if (body == NULL) + return; + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + return; + Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + + // Calculate intersection of plane with bounding box edges + // TODO: This can be a lot more efficient if we do the maths ourselves, e.g. + // http://cococubed.asu.edu/code_pages/raybox.shtml + // http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf + Handle_Geom_Plane plane = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + std::vector points; + + for (int i = 0; i < 12; i++) { + // Get the edge of the bounding box + Base::Vector3d p1, p2; + bbox.CalcDistance(i, p1, p2); + Base::Vector3d ldir = p2 - p1; + Handle_Geom_Line line = new Geom_Line(gp_Pnt(p1.x, p1.y, p1.z), gp_Dir(ldir.x, ldir.y, ldir.z)); + GeomAPI_IntCS intersector(line, plane); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + continue; + gp_Pnt pnt = intersector.Point(1); + Base::Vector3d point(pnt.X(), pnt.Y(), pnt.Z()); + + // Check whether intersection is on the bbox edge (bbox.IsInside() always tests false) + double edgeLength = (p1 - p2).Length(); + double l1 = (p1 - point).Length(); + double l2 = (p2 - point).Length(); + if (fabs(edgeLength - l1 - l2) > 0.001) + continue; + + // Check for duplicates + bool duplicate = false; + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + if ((point - *p).Sqr() < Precision::Confusion()) { + duplicate = true; + break; + } + } + if (!duplicate) + points.push_back(point); + } + + if (points.size() < 3) + return; + + // Sort the points to get a proper polygon, see http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf p.5 + if (points.size() > 3) { + // Longest component of normal vector + int longest; + if (normal.x > normal.y) + if (normal.x > normal.z) + longest = 0; // x is longest + else + longest = 2; // z is longest + else + if (normal.y > normal.z) + longest = 1; // y is longest + else + longest = 2; // z is longest + + // mean value for intersection points + Base::Vector3d m; + for (std::vector::iterator p = points.begin(); p != points.end(); p++) + m += *p; + m /= points.size(); + + // Sort by angles + double a[points.size()]; + for (int i = 0; i < points.size() - 1; i++) { + if (longest == 0) + a[i] = atan2(points[i].z - m.z, points[i].y - m.y); + else if (longest == 1) + a[i] = atan2(points[i].z - m.z, points[i].x - m.x); + else + a[i] = atan2(points[i].y - m.y, points[i].x - m.x); + + for (int k = i+1; k < points.size(); k++) { + if (longest == 0) + a[k] = atan2(points[k].z - m.z, points[k].y - m.y); + else if (longest == 1) + a[k] = atan2(points[k].z - m.z, points[k].x - m.x); + else + a[k] = atan2(points[k].y - m.y, points[k].x - m.x); + + if (a[k] < a[i]) { + Base::Vector3d temp = points[i]; + points[i] = points[k]; + points[k] = temp; + a[i] = a[k]; + } + } + } + } + + // Display the plane SoMFVec3f v; - v.set1Value(0, p.x, p.y, p.z); - SoVertexProperty* vprop = new SoVertexProperty(); - vprop->vertex = v; - SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - points->vertexProperty = vprop; - }*/ + v.setNum(points.size()); + for (int p = 0; p < points.size(); p++) + v.set1Value(p, points[p].x, points[p].y, points[p].z); + SoFaceSet* faceSet = static_cast(pShapeSep->getChild(0)); + + SoVertexProperty* vprop; + if (faceSet->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + faceSet->vertexProperty = vprop; + } else { + vprop = static_cast(faceSet->vertexProperty.getValue()); + vprop->vertex = v; + } + + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, points.size()); + faceSet->numVertices = idx; + } ViewProviderDatum::updateData(prop); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index 7be6c4c47e6b..60f2cfd6a289 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include From 7a6c399a14c5dcca39d032d00fb7242a3e4ef646 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 30 Apr 2013 17:20:40 +0430 Subject: [PATCH 092/664] Make Datum features pickable --- src/Mod/PartDesign/App/DatumFeature.h | 4 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 137 +++++++++++++++---- src/Mod/PartDesign/Gui/ViewProviderDatum.h | 9 ++ 3 files changed, 122 insertions(+), 28 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index 6bee01310821..768bdb20469c 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -26,12 +26,12 @@ #include #include -#include "Feature.h" +#include namespace PartDesign { -class PartDesignExport Datum : public App::DocumentObject +class PartDesignExport Datum : public App::GeoFeature { PROPERTY_HEADER(PartDesign::Datum); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 5a66b17f72ae..2f57d457459f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -36,6 +36,9 @@ # include # include # include +# include +# include +# include # include # include # include @@ -71,7 +74,7 @@ ViewProviderDatum::~ViewProviderDatum() void ViewProviderDatum::attach(App::DocumentObject *obj) { - ViewProviderDocumentObject::attach(obj); + ViewProviderGeometryObject::attach(obj); PartDesign::Datum* pcDatum = static_cast(getObject()); if (pcDatum->getTypeId() == PartDesign::Plane::getClassTypeId()) @@ -88,17 +91,38 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE); hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); SoBaseColor* color = new SoBaseColor(); - color->rgb.setValue(0.9, 0.9, 0.1); - SoMaterial* material = new SoMaterial(); - material->diffuseColor.setValue(0.9f, 0.9f, 0.1f); - material->transparency.setValue(0.2); + color->rgb.setValue(0.9, 0.9, 0.3); sep->addChild(hints); sep->addChild(color); - sep->addChild(material); + sep->addChild(ps); sep->addChild(pShapeSep); addDisplayMaskMode(sep, "Base"); } +bool ViewProviderDatum::onDelete(const std::vector &) +{ + // Body feature housekeeping + PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); + if (body != NULL) { + body->removeFeature(getObject()); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = body->Tip.getValue(); + App::DocumentObject* prev = body->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + // TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support + // 1. Delete + // 2. Suppress + // 3. Re-route + + return true; +} + std::vector ViewProviderDatum::getDisplayModes(void) const { // add modes @@ -111,7 +135,7 @@ void ViewProviderDatum::setDisplayMode(const char* ModeName) { if (strcmp(ModeName, "Base") == 0) setDisplayMaskMode("Base"); - ViewProviderDocumentObject::setDisplayMode(ModeName); + ViewProviderGeometryObject::setDisplayMode(ModeName); } void ViewProviderDatum::onChanged(const App::Property* prop) @@ -120,10 +144,59 @@ void ViewProviderDatum::onChanged(const App::Property* prop) updateData(prop); } else {*/ - ViewProviderDocumentObject::onChanged(prop); + ViewProviderGeometryObject::onChanged(prop); //} } +std::string ViewProviderDatum::getElement(const SoDetail* detail) const +{ + if (detail) { + int element; + + if (detail->getTypeId() == SoLineDetail::getClassTypeId()) { + const SoLineDetail* line_detail = static_cast(detail); + element = line_detail->getLineIndex(); + } else if (detail->getTypeId() == SoFaceDetail::getClassTypeId()) { + const SoFaceDetail* face_detail = static_cast(detail); + element = face_detail->getFaceIndex(); + } else if (detail->getTypeId() == SoPointDetail::getClassTypeId()) { + const SoPointDetail* point_detail = static_cast(detail); + element = point_detail->getCoordinateIndex(); + } + + if (element == 0) + return datumType.toStdString(); + } + + return std::string(""); +} + +SoDetail* ViewProviderDatum::getDetail(const char* subelement) const +{ + QString subelem = QString::fromAscii(subelement); + + if (subelem == QObject::tr("Line")) { + SoLineDetail* detail = new SoLineDetail(); + detail->setPartIndex(0); + return detail; + } else if (subelem == QObject::tr("Plane")) { + SoFaceDetail* detail = new SoFaceDetail(); + detail->setPartIndex(0); + return detail; + } else if (subelem == QObject::tr("Point")) { + SoPointDetail* detail = new SoPointDetail(); + detail->setCoordinateIndex(0); + return detail; + } + + return NULL; +} + +bool ViewProviderDatum::isSelectable(void) const +{ + return true; +} + void ViewProviderDatum::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) { QAction* act; @@ -238,8 +311,10 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProvider ViewProviderDatumLine::ViewProviderDatumLine() { - SoLineSet* lineSet = new SoLineSet(); - pShapeSep->addChild(lineSet); + SoMaterial* material = new SoMaterial(); + material->diffuseColor.setValue(0.9f, 0.9f, 0.13); + material->transparency.setValue(0.2); + pShapeSep->addChild(material); } ViewProviderDatumLine::~ViewProviderDatumLine() @@ -280,22 +355,26 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) v.setNum(2); v.set1Value(0, p1.x, p1.y, p1.z); v.set1Value(1, p2.x, p2.y, p2.z); - SoLineSet* lineSet = static_cast(pShapeSep->getChild(0)); + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, 2); + SoLineSet* lineSet; SoVertexProperty* vprop; - if (lineSet->vertexProperty.getValue() == NULL) { + + if (pShapeSep->getNumChildren() == 1) { + lineSet = new SoLineSet(); vprop = new SoVertexProperty(); vprop->vertex = v; lineSet->vertexProperty = vprop; + lineSet->numVertices = idx; + pShapeSep->addChild(lineSet); } else { + lineSet = static_cast(pShapeSep->getChild(1)); vprop = static_cast(lineSet->vertexProperty.getValue()); vprop->vertex = v; + lineSet->numVertices = idx; } - - SoMFInt32 idx; - idx.setNum(1); - idx.set1Value(0, 2); - lineSet->numVertices = idx; } ViewProviderDatum::updateData(prop); @@ -305,8 +384,10 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProvide ViewProviderDatumPlane::ViewProviderDatumPlane() { - SoFaceSet* faceSet = new SoFaceSet(); - pShapeSep->addChild(faceSet); + SoMaterial* material = new SoMaterial(); + material->diffuseColor.setValue(0.9f, 0.9f, 0.13); + material->transparency.setValue(0.2); + pShapeSep->addChild(material); } ViewProviderDatumPlane::~ViewProviderDatumPlane() @@ -428,22 +509,26 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) v.setNum(points.size()); for (int p = 0; p < points.size(); p++) v.set1Value(p, points[p].x, points[p].y, points[p].z); - SoFaceSet* faceSet = static_cast(pShapeSep->getChild(0)); + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, points.size()); + SoFaceSet* faceSet; SoVertexProperty* vprop; - if (faceSet->vertexProperty.getValue() == NULL) { + + if (pShapeSep->getNumChildren() == 1) { + faceSet = new SoFaceSet(); vprop = new SoVertexProperty(); vprop->vertex = v; faceSet->vertexProperty = vprop; + faceSet->numVertices = idx; + pShapeSep->addChild(faceSet); } else { + faceSet = static_cast(pShapeSep->getChild(1)); vprop = static_cast(faceSet->vertexProperty.getValue()); vprop->vertex = v; + faceSet->numVertices = idx; } - - SoMFInt32 idx; - idx.setNum(1); - idx.set1Value(0, points.size()); - faceSet->numVertices = idx; } ViewProviderDatum::updateData(prop); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.h b/src/Mod/PartDesign/Gui/ViewProviderDatum.h index bde60f4e727d..b2ef4f5b262a 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.h @@ -42,10 +42,19 @@ class PartDesignGuiExport ViewProviderDatum : public Gui::ViewProviderGeometryOb void setupContextMenu(QMenu*, QObject*, const char*); virtual void attach(App::DocumentObject *); + virtual bool onDelete(const std::vector &); virtual void updateData(const App::Property* prop) { Gui::ViewProviderGeometryObject::updateData(prop); } std::vector getDisplayModes(void) const; void setDisplayMode(const char* ModeName); + /// indicates if the ViewProvider use the new Selection model + virtual bool useNewSelectionModel(void) const { return true; } + /// indicates if the ViewProvider can be selected + virtual bool isSelectable(void) const ; + /// return a hit element to the selection path or 0 + virtual std::string getElement(const SoDetail *) const; + virtual SoDetail* getDetail(const char*) const; + /// The datum type (Plane, Line or Point) QString datumType; From bb1a3a532f79e39107c43169fef74f5dbb05ee08 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 30 Apr 2013 17:55:45 +0430 Subject: [PATCH 093/664] Miscellaneous fixes --- src/Mod/Part/App/Part2DObject.cpp | 11 +- src/Mod/PartDesign/App/DatumFeature.cpp | 311 +++++++++++++++++-- src/Mod/PartDesign/Gui/Command.cpp | 25 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 1 + src/Mod/PartDesign/Gui/Workbench.cpp | 2 + src/Mod/Sketcher/App/PreCompiled.h | 2 + src/Mod/Sketcher/App/SketchObject.cpp | 15 +- 7 files changed, 323 insertions(+), 44 deletions(-) diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index 16f754a3a7be..b70c337bb0ac 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -111,16 +111,7 @@ void Part2DObject::positionBySupport(void) Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); Base::Vector3d pos = Place.getPosition(); plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); - }/* else if (support->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - Place = static_cast(support)->Placement.getValue(); - Base::Vector3d pos = Place.getPosition(); - Base::Vector3d dir; - Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); - const std::vector &sub = Support.getSubValues(); - if (!sub.empty()) - Reverse = (sub[0] == "back"); - plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); - }*/ else { + } else { Part::Feature *part = static_cast(support); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) return; diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp index bb6861f11aa6..ce951ffa2543 100644 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -32,6 +32,9 @@ # include # include # include +# include +# include +# include # include # include # include @@ -56,8 +59,8 @@ #include #include "DatumFeature.h" #include -#include #include +#include #include "Mod/Part/App/PrimitiveFeature.h" #ifndef M_PI @@ -66,7 +69,7 @@ using namespace PartDesign; -PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::DocumentObject) +PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::GeoFeature) Datum::Datum(void) { @@ -98,14 +101,14 @@ void Datum::onChanged(const App::Property* prop) refTypes.insert(getRefType(refs[r], refnames[r])); } - App::DocumentObject::onChanged(prop); + App::GeoFeature::onChanged(prop); } void Datum::onDocumentRestored() { // This seems to be the only way to make the ViewProvider display the datum feature References.touch(); - App::DocumentObject::onDocumentRestored(); + App::GeoFeature::onDocumentRestored(); } // Note: We don't distinguish between e.g. datum lines and edges here @@ -263,7 +266,7 @@ PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) Point::Point() { - ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,1)),"DatumPoint", + ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,0)),"DatumPoint", App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), "Coordinates of the datum point"); } @@ -284,7 +287,7 @@ void Point::onChanged(const App::Property* prop) // Extract the geometry of the references std::vector refs = References.getValues(); std::vector refnames = References.getSubValues(); - Base::Vector3f* point = NULL; + Base::Vector3d* point = NULL; Handle_Geom_Curve c1 = NULL; Handle_Geom_Curve c2 = NULL; Handle_Geom_Surface s1 = NULL; @@ -297,13 +300,40 @@ void Point::onChanged(const App::Property* prop) point = new Base::Vector3d (p->_Point.getValue()); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* l = static_cast(refs[i]); - //point = new Base::Vector3f (p->_Point.getValue()); + Base::Vector3d base = l->_Base.getValue(); + Base::Vector3d dir = l->_Direction.getValue(); + if (c1.IsNull()) + c1 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); + else + c2 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* p = static_cast(refs[i]); - //point = new Base::Vector3f (p->_Point.getValue()); + Base::Vector3d base = p->_Base.getValue(); + Base::Vector3d normal = p->_Normal.getValue(); + if (s1.IsNull()) + s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + else if (s2.IsNull()) + s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + else + s3 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { App::Plane* p = static_cast(refs[i]); - //point = new Base::Vector3f (p->_Point.getValue()); + // Note: We only handle the three base planes here + gp_Pnt base(0,0,0); + gp_Dir normal; + if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) + normal = gp_Dir(0,0,1); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + normal = gp_Dir(1,0,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) + normal = gp_Dir(0,1,0); + + if (s1.IsNull()) + s1 = new Geom_Plane(base, normal); + else if (s2.IsNull()) + s2 = new Geom_Plane(base, normal); + else + s3 = new Geom_Plane(base, normal); } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Part::Feature* feature = static_cast(refs[i]); const TopoDS_Shape& sh = feature->Shape.getValue(); @@ -317,7 +347,7 @@ void Point::onChanged(const App::Property* prop) if (subshape.ShapeType() == TopAbs_VERTEX) { TopoDS_Vertex v = TopoDS::Vertex(subshape); gp_Pnt p = BRep_Tool::Pnt(v); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); } else if (subshape.ShapeType() == TopAbs_EDGE) { TopoDS_Edge e = TopoDS::Edge(subshape); Standard_Real first, last; @@ -337,7 +367,7 @@ void Point::onChanged(const App::Property* prop) } else { return; //"PartDesign::Point: Invalid reference type" } - } + } if (point != NULL) { // Point from vertex or other point. Nothing to be done @@ -350,7 +380,7 @@ void Point::onChanged(const App::Property* prop) // Note: We don't check for multiple intersection points gp_Pnt p, p2; intersector.Points(1, p, p2); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); } else if (!s1.IsNull()) { GeomAPI_IntCS intersector(c1, s1); if (!intersector.IsDone() || (intersector.NbPoints() == 0)) @@ -359,7 +389,7 @@ void Point::onChanged(const App::Property* prop) Base::Console().Warning("More than one intersection point for datum point from curve and surface"); gp_Pnt p = intersector.Point(1); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); } else return; } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { @@ -377,7 +407,7 @@ void Point::onChanged(const App::Property* prop) Base::Console().Warning("More than one intersection point for datum point from surfaces"); gp_Pnt p = intersector.Point(1); - point = new Base::Vector3f(p.X(), p.Y(), p.Z()); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); } else { return; } @@ -402,6 +432,12 @@ PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) Line::Line() { + ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumLine", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the line base point"); + ADD_PROPERTY_TYPE(_Direction,(Base::Vector3d(1,1,1)),"DatumLine", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the line direction"); } Line::~Line() @@ -410,11 +446,129 @@ Line::~Line() void Line::onChanged(const App::Property *prop) { - gp_Pnt point1(0,0,0); + Datum::onChanged(prop); + + if (prop == &References) { + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Line")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + Base::Vector3d* base = NULL; + Base::Vector3d* direction = NULL; + Base::Vector3d* p1 = NULL; + Base::Vector3d* p2 = NULL; + gp_Lin* line = NULL; + Handle_Geom_Surface s1 = NULL; + Handle_Geom_Surface s2 = NULL; + + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + if (p1 == NULL) + p1 = new Base::Vector3d (p->_Point.getValue()); + else + p2 = new Base::Vector3d (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + base = new Base::Vector3d (l->_Base.getValue()); + direction = new Base::Vector3d (l->_Direction.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + Base::Vector3d base = p->_Base.getValue(); + Base::Vector3d normal = p->_Normal.getValue(); + if (s1.IsNull()) + s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + else + s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + // Note: We only handle the three base planes here + gp_Pnt base(0,0,0); + gp_Dir normal; + if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) + normal = gp_Dir(0,0,1); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + normal = gp_Dir(1,0,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) + normal = gp_Dir(0,1,0); + + if (s1.IsNull()) + s1 = new Geom_Plane(base, normal); + else + s2 = new Geom_Plane(base, normal); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Line: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Line: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + if (p1 == NULL) + p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + else + p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + BRepAdaptor_Curve adapt(e); + if (adapt.GetType() != GeomAbs_Line) + return; // Non-linear edge + line = new gp_Lin(adapt.Line()); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + if (s1.IsNull()) + s1 = BRep_Tool::Surface(f); + else + s2 = BRep_Tool::Surface(f); + } + } else { + return; //"PartDesign::Point: Invalid reference type" + } + } - gp_Pnt point2(10,10,10); + if ((base != NULL) && (direction != NULL)) { + // Line from other datum line. Nothing to be done + } else if ((p1 != NULL) && (p2 != NULL)) { + // Line from two points + base = new Base::Vector3d(*p1); + direction = new Base::Vector3d(*p2 - *p1); + } else if (line != NULL) { + // Line from gp_lin + base = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); + direction = new Base::Vector3d(line->Direction().X(), line->Direction().Y(), line->Direction().Z()); + } else if (!s1.IsNull() && !s2.IsNull()) { + GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); + if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) + return; + if (intersectorSS.NbLines() > 1) + Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Handle_Geom_Line l = Handle_Geom_Line::DownCast(intersectorSS.Line(1)); + if (l.IsNull()) + return; // non-linear intersection curve + gp_Lin lin = l->Lin(); + base = new Base::Vector3d(lin.Location().X(), lin.Location().Y(), lin.Location().Z()); + direction = new Base::Vector3d(lin.Direction().X(), lin.Direction().Y(), lin.Direction().Z()); + } else { + return; + } - return; + _Base.setValue(*base); + _Direction.setValue(*direction); + _Base.touch(); // This triggers ViewProvider::updateData() + delete base; + delete direction; + if (p1 != NULL) delete p1; + if (p2 != NULL) delete p2; + if (line != NULL) delete line; + } } @@ -431,20 +585,129 @@ PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) Plane::Plane() { +ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumPlane", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the plane base point"); +ADD_PROPERTY_TYPE(_Normal,(Base::Vector3d(1,1,1)),"DatumPlane", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the plane normal"); } void Plane::onChanged(const App::Property *prop) { - double O = 10.0; //this->Offset.getValue(); - double A = 45.0; //this->Angle.getValue(); + Datum::onChanged(prop); - if (fabs(A) > 360.0) - return; // "Angle too large (please use -360.0 .. +360.0)" + if (prop == &References) { + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Plane")) != hint.end()))) + return; // incomplete references - gp_Pnt pnt(0.0,0.0,0.0); - gp_Dir dir(0.0,0.0,1.0); + // Extract the geometry of the references + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + Base::Vector3d* p1 = NULL; + Base::Vector3d* p2 = NULL; + Base::Vector3d* p3 = NULL; + Base::Vector3d* normal = NULL; + gp_Lin* line = NULL; - return; + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + if (p1 == NULL) + p1 = new Base::Vector3d (p->_Point.getValue()); + else if (p2 == NULL) + p2 = new Base::Vector3d (p->_Point.getValue()); + else + p3 = new Base::Vector3d (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + Base::Vector3d base = l->_Base.getValue(); + Base::Vector3d dir = l->_Direction.getValue(); + line = new gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + p1 = new Base::Vector3d(p->_Base.getValue()); + normal = new Base::Vector3d(p->_Normal.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + // Note: We only handle the three base planes here + p1 = new Base::Vector3d(0,0,0); + normal = new Base::Vector3d; + if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) + *normal = Base::Vector3d(0,0,1); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + *normal = Base::Vector3d(1,0,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) + *normal = Base::Vector3d(0,1,0); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Plane: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Plane: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + if (p1 == NULL) + p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + else if (p2 == NULL) + p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + else + p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + BRepAdaptor_Curve adapt(e); + if (adapt.GetType() != GeomAbs_Line) + return; // Non-linear edge + line = new gp_Lin(adapt.Line()); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + BRepAdaptor_Surface adapt(f); + if (adapt.GetType() != GeomAbs_Plane) + return; // Non-planar face + gp_Pnt b = adapt.Plane().Location(); + gp_Dir d = adapt.Plane().Axis().Direction(); + p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); + normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); + } + } else { + return; //"PartDesign::Plane: Invalid reference type" + } + } + + if ((p1 != NULL) && (normal != NULL)) { + // plane from other plane. Nothing to be done + } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { + // Plane from three points + Base::Vector3d vec1 = *p2 - *p1; + Base::Vector3d vec2 = *p3 - *p1; + normal = new Base::Vector3d(vec1 % vec2); + } else if ((line != NULL) && (p1 != NULL)) { + // Plane from point and line + p2 = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); + gp_Pnt p(line->Location().X() + line->Direction().X(), line->Location().Y() + line->Direction().Y(), line->Location().Z() + line->Direction().Z()); + p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + Base::Vector3d vec1 = *p2 - *p1; + Base::Vector3d vec2 = *p3 - *p1; + normal = new Base::Vector3d(vec1 % vec2); + } else { + return; + } + + _Base.setValue(*p1); + _Normal.setValue(*normal); + _Base.touch(); // This triggers ViewProvider::updateData() + delete p1; + delete normal; + if (p2 != NULL) delete p2; + if (p3 != NULL) delete p3; + if (line != NULL) delete line; + } } diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 5277285edf15..7081d2f23391 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -216,19 +216,27 @@ const QString getReferenceString(Gui::Command* cmd) if(!pcActiveBody) return QString::fromAscii(""); Gui::SelectionFilter GeometryFilter("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter DatumFilter ("SELECT PartDesign::Plane COUNT 1"); Gui::SelectionFilter EdgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1"); + Gui::SelectionFilter LineFilter ("SELECT PartDesign::Line COUNT 1"); Gui::SelectionFilter VertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 1"); + Gui::SelectionFilter PointFilter ("SELECT PartDesign::Point COUNT 1"); Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); - Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); + if (EdgeFilter.match()) GeometryFilter = EdgeFilter; else if (VertexFilter.match()) GeometryFilter = VertexFilter; - if (PlaneFilter2.match()) - PlaneFilter = PlaneFilter2; - if (GeometryFilter.match() || PlaneFilter.match()) { + if (LineFilter.match()) + DatumFilter = LineFilter; + else if (PointFilter.match()) + DatumFilter = PointFilter; + else if (PlaneFilter.match()) + DatumFilter = PlaneFilter; + + if (GeometryFilter.match() || DatumFilter.match()) { // get the selected object if (GeometryFilter.match()) { Part::Feature *part = static_cast(GeometryFilter.Result[0][0].getObject()); @@ -257,7 +265,7 @@ const QString getReferenceString(Gui::Command* cmd) return referenceString; } else { - Part::Feature *part = static_cast(PlaneFilter.Result[0][0].getObject()); + Part::Feature *part = static_cast(DatumFilter.Result[0][0].getObject()); return QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + QString::fromAscii(",'')]"); } @@ -296,9 +304,8 @@ const QString getReferenceString(Gui::Command* cmd) if (!body->hasFeature(*r)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; - } else { - if (body->isAfterTip(*r)) - status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + } else if (body->isAfterTip(*r)) { + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); continue; } @@ -311,7 +318,7 @@ const QString getReferenceString(Gui::Command* cmd) if (validRefs == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid references in this document"), - QObject::tr("Please select a face, edge or vertex")); + QObject::tr("Please select a datum feature, or a face, edge or vertex")); return QString::fromAscii(""); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 2f57d457459f..46773c7cf0cf 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include using namespace PartDesignGui; diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 81157b44e7e8..bdba81f42fa4 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include using namespace PartDesignGui; @@ -261,6 +262,7 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con if (strcmp(recipient,"Tree") == 0) { if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + + Gui::Selection().countObjectsOfType(PartDesign::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveTip"; } diff --git a/src/Mod/Sketcher/App/PreCompiled.h b/src/Mod/Sketcher/App/PreCompiled.h index 0ea5baa4818b..017e51666a14 100644 --- a/src/Mod/Sketcher/App/PreCompiled.h +++ b/src/Mod/Sketcher/App/PreCompiled.h @@ -30,10 +30,12 @@ #ifdef FC_OS_WIN32 # define SketcherExport __declspec(dllexport) # define PartExport __declspec(dllimport) +# define PartDesignExport __declspec(dllimport) # define MeshExport __declspec(dllimport) #else // for Linux # define SketcherExport # define PartExport +# define PartDesignExport # define MeshExport #endif diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 95af4568d8ef..7e75f2a34b11 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -57,6 +57,7 @@ #include #include +#include #include "SketchObject.h" #include "SketchObjectPy.h" @@ -114,7 +115,19 @@ SketchObject::~SketchObject() App::DocumentObjectExecReturn *SketchObject::execute(void) { try { - this->positionBySupport(); + App::DocumentObject* support = Support.getValue(); + if (support == NULL) + throw Base::Exception("Sketch support has been deleted"); + + if (support->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + // We don't want to handle this case in Part::Part2DObject because then Part would depend on PartDesign + PartDesign::Plane* plane = static_cast(support); + Base::Vector3d pos = plane->_Base.getValue(); + Base::Vector3d normal = plane->_Normal.getValue(); + this->Placement.setValue(Base::Placement(pos, Base::Rotation(Base::Vector3d(0,0,1), normal))); + } else { + this->positionBySupport(); + } } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); From 20ba1983a43cd8cd06a814f7b60e5c8c2eaeef02 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 1 May 2013 21:05:30 +0430 Subject: [PATCH 094/664] Datum planes with offset and angle. Miscellaneous fixes --- src/Mod/PartDesign/App/DatumFeature.cpp | 75 +++++-- src/Mod/PartDesign/App/DatumFeature.h | 5 +- src/Mod/PartDesign/Gui/Command.cpp | 5 +- .../PartDesign/Gui/TaskDatumParameters.cpp | 186 +++++++++++------- src/Mod/PartDesign/Gui/TaskDatumParameters.h | 10 +- src/Mod/PartDesign/Gui/TaskDatumParameters.ui | 41 +++- 6 files changed, 216 insertions(+), 106 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp index ce951ffa2543..e9268c050d2b 100644 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ b/src/Mod/PartDesign/App/DatumFeature.cpp @@ -74,7 +74,8 @@ PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::GeoFeature) Datum::Datum(void) { ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); - ADD_PROPERTY(Values,(0.0)); + ADD_PROPERTY(Offset,(0.0)); + ADD_PROPERTY(Angle,(0.0)); touch(); } @@ -89,6 +90,12 @@ App::DocumentObjectExecReturn *Datum::execute(void) return StdReturn; } +// Note: We don't distinguish between e.g. datum lines and edges here +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") +#define ANGLE QObject::tr("Angle") + void Datum::onChanged(const App::Property* prop) { @@ -99,6 +106,15 @@ void Datum::onChanged(const App::Property* prop) for (int r = 0; r < refs.size(); r++) refTypes.insert(getRefType(refs[r], refnames[r])); + + if (fabs(Angle.getValue()) > Precision::Confusion()) + refTypes.insert(ANGLE); + } else if (prop == &Angle) { + // Zero value counts as angle not defined + if (fabs(Angle.getValue()) > Precision::Confusion()) + refTypes.insert(ANGLE); + else + refTypes.erase(ANGLE); } App::GeoFeature::onChanged(prop); @@ -111,11 +127,6 @@ void Datum::onDocumentRestored() App::GeoFeature::onDocumentRestored(); } -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define LINE QObject::tr("DLINE") -#define POINT QObject::tr("DPOINT") - const QString Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) { Base::Type type = obj->getTypeId(); @@ -146,7 +157,7 @@ std::map, std::set > Point::hints = std::map DONE; - DONE.insert(QObject::tr("Point")); + DONE.insert(QObject::tr("Done")); std::multiset key; std::set value; @@ -190,7 +201,7 @@ std::map, std::set > Line::hints = std::map DONE; - DONE.insert(QObject::tr("Line")); + DONE.insert(QObject::tr("Done")); std::multiset key; std::set value; @@ -225,7 +236,7 @@ std::map, std::set > Plane::hints = std::map DONE; - DONE.insert(QObject::tr("Plane")); + DONE.insert(QObject::tr("Done")); std::multiset key; std::set value; @@ -252,11 +263,31 @@ void Plane::initHints() key.clear(); value.clear(); key.insert(LINE); - value.insert(POINT); - hints[key] = value; // LINE -> POINT + value.insert(POINT); value.insert(PLANE); value.insert(ANGLE); + hints[key] = value; // LINE -> POINT or PLANE or ANGLE key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); + key.insert(PLANE); key.insert(LINE); + value.insert(ANGLE); + hints[key] = value; // {PLANE, LINE} -> ANGLE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(ANGLE); + value.insert(LINE); + hints[key] = value; // {PLANE, ANGLE} -> LINE + + key.clear(); value.clear(); + key.insert(ANGLE); key.insert(LINE); + value.insert(PLANE); + hints[key] = value; // {ANGLE, LINE} -> PLANE + + key.clear(); value.clear(); + key.insert(LINE); key.insert(PLANE); key.insert(ANGLE); + hints[key] = DONE; // {LINE, PLANE, ANGLE} -> DONE. Plane through line with angle to other plane + + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); value.insert(ANGLE); hints[key] = value; } @@ -281,7 +312,7 @@ void Point::onChanged(const App::Property* prop) if (prop == &References) { std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Point")) != hint.end()))) + if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) return; // incomplete references // Extract the geometry of the references @@ -450,7 +481,7 @@ void Line::onChanged(const App::Property *prop) if (prop == &References) { std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Line")) != hint.end()))) + if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) return; // incomplete references // Extract the geometry of the references @@ -599,7 +630,7 @@ void Plane::onChanged(const App::Property *prop) if (prop == &References) { std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Plane")) != hint.end()))) + if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) return; // incomplete references // Extract the geometry of the references @@ -680,7 +711,16 @@ void Plane::onChanged(const App::Property *prop) } } - if ((p1 != NULL) && (normal != NULL)) { + *normal = normal->Normalize(); + + if ((line != NULL) && (normal != NULL) && (p1 != NULL) && (fabs(Angle.getValue()) > Precision::Confusion())) { + // plane from line, plane, and angle to plane + gp_Pnt p = line->Location(); + *p1 = Base::Vector3d(p.X(), p.Y(), p.Z()); + gp_Dir dir = line->Direction(); + Base::Rotation rot(Base::Vector3d(dir.X(), dir.Y(), dir.Z()), Angle.getValue() / 180.0 * M_PI); + rot.multVec(*normal, *normal); + } else if ((p1 != NULL) && (normal != NULL)) { // plane from other plane. Nothing to be done } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { // Plane from three points @@ -699,6 +739,9 @@ void Plane::onChanged(const App::Property *prop) return; } + if (fabs(Offset.getValue()) > Precision::Confusion()) + *p1 += Offset.getValue() * *normal; + _Base.setValue(*p1); _Normal.setValue(*normal); _Base.touch(); // This triggers ViewProvider::updateData() diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h index 768bdb20469c..ab4e357b90f4 100644 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ b/src/Mod/PartDesign/App/DatumFeature.h @@ -41,8 +41,9 @@ class PartDesignExport Datum : public App::GeoFeature /// The references defining the datum object, e.g. three planes for a point, two planes for a line App::PropertyLinkSubList References; - /// The values defining the datum object, e.g. the offset from a Reference plane - App::PropertyFloatList Values; + /// Offset and angle for defining planes + App::PropertyFloat Offset; + App::PropertyFloat Angle; /// recalculate the feature App::DocumentObjectExecReturn *execute(void); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 7081d2f23391..48178f0b4b41 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -372,7 +372,8 @@ void CmdPartDesignPlane::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Offset = 0.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Angle = 0.0",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -413,7 +414,6 @@ void CmdPartDesignLine::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('PartDesign::Line','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -454,7 +454,6 @@ void CmdPartDesignPoint::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('PartDesign::Point','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 0adfb5f1a9f4..d608c854465e 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -106,9 +106,11 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p ui->setupUi(proxy); QMetaObject::connectSlotsByName(this); - connect(ui->spinValue1, SIGNAL(valueChanged(double)), - this, SLOT(onValue1Changed(double))); - connect(ui->checkBox1, SIGNAL(toggled(bool)), + connect(ui->spinOffset, SIGNAL(valueChanged(double)), + this, SLOT(onOffsetChanged(double))); + connect(ui->spinAngle, SIGNAL(valueChanged(double)), + this, SLOT(onAngleChanged(double))); + connect(ui->checkBoxFlip, SIGNAL(toggled(bool)), this, SLOT(onCheckBox1(bool))); connect(ui->buttonRef1, SIGNAL(pressed()), this, SLOT(onButtonRef1())); @@ -126,8 +128,9 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p this->groupLayout()->addWidget(proxy); // Temporarily prevent unnecessary feature recomputes - ui->spinValue1->blockSignals(true); - ui->checkBox1->blockSignals(true); + ui->spinOffset->blockSignals(true); + ui->spinAngle->blockSignals(true); + ui->checkBoxFlip->blockSignals(true); ui->buttonRef1->blockSignals(true); ui->lineRef1->blockSignals(true); ui->buttonRef2->blockSignals(true); @@ -137,16 +140,17 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p // Get the feature data PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector refs = pcDatum->References.getValues(); + //std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); - //bool checked1 = pcDatum->Checked.getValue(); - std::vector vals = pcDatum->Values.getValues(); + double offset = pcDatum->Offset.getValue(); + double angle = pcDatum->Angle.getValue(); // Fill data into dialog elements - ui->spinValue1->setValue(vals[0]); - //ui->checkBox1->setChecked(checked1); + ui->spinOffset->setValue(offset); + ui->spinAngle->setValue(angle); + //ui->checkBoxFlip->setChecked(checked1); std::vector refstrings; makeRefStrings(refstrings, refnames); ui->lineRef1->setText(refstrings[0]); @@ -157,8 +161,9 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p ui->lineRef3->setProperty("RefName", QByteArray(refnames[2].c_str())); // activate and de-activate dialog elements as appropriate - ui->spinValue1->blockSignals(false); - ui->checkBox1->blockSignals(false); + ui->spinOffset->blockSignals(false); + ui->spinAngle->blockSignals(false); + ui->checkBoxFlip->blockSignals(false); ui->buttonRef1->blockSignals(false); ui->lineRef1->blockSignals(false); ui->buttonRef2->blockSignals(false); @@ -179,7 +184,10 @@ const QString makeRefText(std::set hint) tText = QObject::tr("Line"); else if (((*t) == QObject::tr("DPOINT")) || ((*t) == QObject::tr("Point"))) tText = QObject::tr("Point"); + else if ((*t) == QObject::tr("Done")) + tText = QObject::tr("Done"); result += QString::fromAscii(result.size() == 0 ? "" : "/") + tText; + // Note: ANGLE is not passed back here but needs separate treatment } return result; @@ -187,20 +195,21 @@ const QString makeRefText(std::set hint) void TaskDatumParameters::updateUI() { - ui->checkBox1->setEnabled(false); + ui->checkBoxFlip->setVisible(false); + if (DatumView->datumType != QObject::tr("Plane")) { + ui->labelAngle->setVisible(false); + ui->labelOffset->setVisible(false); + ui->spinAngle->setVisible(false); + ui->spinOffset->setVisible(false); + } PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); completed = false; - if (refs.size() == 3) { - onButtonRef1(false); // No more references required - completed = true; - return; - } - // Get hints for further required references - std::set hint = pcDatum->getHint(); + std::set hint = pcDatum->getHint(); + if (hint == std::set()) { QMessageBox::warning(this, tr("Illegal selection"), tr("This feature cannot be created with this combination of references")); if (refs.size() == 1) { @@ -213,28 +222,42 @@ void TaskDatumParameters::updateUI() return; } + double angle = pcDatum->Angle.getValue(); + bool needAngle = (hint.find(QObject::tr("Angle")) != hint.end()); + hint.erase(QObject::tr("Angle")); + // Enable the next reference button - if (refs.size() == 0) { + int numrefs = refs.size(); + if (needAngle && hint.empty()) + numrefs--; + if (numrefs == 0) { ui->buttonRef2->setEnabled(false); ui->lineRef2->setEnabled(false); ui->buttonRef3->setEnabled(false); ui->lineRef3->setEnabled(false); - } else if (refs.size() == 1) { + } else if (numrefs == 1) { ui->buttonRef2->setEnabled(true); ui->lineRef2->setEnabled(true); ui->buttonRef3->setEnabled(false); ui->lineRef3->setEnabled(false); - } else if (refs.size() == 2) { + } else if (numrefs == 2) { ui->buttonRef2->setEnabled(true); ui->lineRef2->setEnabled(true); ui->buttonRef3->setEnabled(true); ui->lineRef3->setEnabled(true); } + if (needAngle) { + ui->labelAngle->setEnabled(true); + ui->spinAngle->setEnabled(true); + } else if (fabs(angle) < Precision::Confusion()) { + ui->labelAngle->setEnabled(false); + ui->spinAngle->setEnabled(false); + } - QString refText = makeRefText(hint); + QString hintText = makeRefText(hint); // Check if we have all required references - if (refText == DatumView->datumType) { + if (hintText == QObject::tr("Done")) { if (refs.size() == 1) { ui->buttonRef2->setEnabled(false); ui->lineRef2->setEnabled(false); @@ -244,19 +267,25 @@ void TaskDatumParameters::updateUI() ui->buttonRef3->setEnabled(false); ui->lineRef3->setEnabled(false); } + if (fabs(angle) < Precision::Confusion()) { + ui->labelAngle->setEnabled(false); + ui->spinAngle->setEnabled(false); + } onButtonRef1(false); // No more references required completed = true; return; } - if (refs.size() == 0) { - onButtonRef1(true); - } else if (refs.size() == 1) { - ui->buttonRef2->setText(refText); - onButtonRef2(true); - } else if (refs.size() == 2) { - ui->buttonRef3->setText(refText); - onButtonRef3(true); + if (hintText.size() != 0) { + if (numrefs == 0) { + onButtonRef1(true); + } else if (numrefs == 1) { + ui->buttonRef2->setText(hintText); + onButtonRef2(true); + } else if (numrefs == 2) { + ui->buttonRef3->setText(hintText); + onButtonRef3(true); + } } } @@ -318,16 +347,23 @@ void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) } } -void TaskDatumParameters::onValue1Changed(double val) +void TaskDatumParameters::onOffsetChanged(double val) { PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); - std::vector vals = pcDatum->Values.getValues(); - vals[0] = val; - pcDatum->Values.setValues(vals); + pcDatum->Offset.setValue(val); pcDatum->getDocument()->recomputeFeature(pcDatum); + updateUI(); } -void TaskDatumParameters::onCheckBox1(bool on) +void TaskDatumParameters::onAngleChanged(double val) +{ + PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + pcDatum->Angle.setValue(val); + pcDatum->getDocument()->recomputeFeature(pcDatum); + updateUI(); +} + +void TaskDatumParameters::onCheckFlip(bool on) { PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); //pcDatum->Reversed.setValue(on); @@ -420,35 +456,30 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) // TODO: check validity of the text that was entered: Does subElement actually reference to an element on the obj? // We must expect that "text" is the translation of "Face", "Edge" or "Vertex" followed by an ID. - QString name; - QTextStream str(&name); - QRegExp rx(name); + QRegExp rx; std::stringstream ss; - str << "^" << tr("Face") << "(\\d+)$"; - if (parts[1].indexOf(rx) < 0) { - line->setProperty("RefName", QByteArray()); - return; - } else { + rx.setPattern(QString::fromAscii("^") + tr("Face") + QString::fromAscii("(\\d+)$")); + if (parts[1].indexOf(rx) >= 0) { int faceId = rx.cap(1).toInt(); ss << "Face" << faceId; - } - str << "^" << tr("Edge") << "(\\d+)$"; - if (parts[1].indexOf(rx) < 0) { - line->setProperty("RefName", QByteArray()); - return; } else { - int lineId = rx.cap(1).toInt(); - ss << "Edge" << lineId; - } - str << "^" << tr("Vertex") << "(\\d+)$"; - if (parts[1].indexOf(rx) < 0) { - line->setProperty("RefName", QByteArray()); - return; - } else { - int vertexId = rx.cap(1).toInt(); - ss << "Vertex" << vertexId; + rx.setPattern(QString::fromAscii("^") + tr("Edge") + QString::fromAscii("(\\d+)$")); + if (parts[1].indexOf(rx) >= 0) { + int lineId = rx.cap(1).toInt(); + ss << "Edge" << lineId; + } else { + rx.setPattern(QString::fromAscii("^") + tr("Vertex") + QString::fromAscii("(\\d+)$")); + if (parts[1].indexOf(rx) < 0) { + line->setProperty("RefName", QByteArray()); + return; + } else { + int vertexId = rx.cap(1).toInt(); + ss << "Vertex" << vertexId; + } + } } + line->setProperty("RefName", QByteArray(ss.str().c_str())); subElement = ss.str(); } @@ -456,16 +487,15 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); - if (refSelectionMode < refs.size()) { - refs[refSelectionMode] = obj; - refnames[refSelectionMode] = subElement.c_str(); + if (idx < refs.size()) { + refs[idx] = obj; + refnames[idx] = subElement.c_str(); } else { refs.push_back(obj); refnames.push_back(subElement.c_str()); } pcDatum->References.setValues(refs, refnames); updateUI(); - //pcDatum->getDocument()->recomputeFeature(pcDatum); } void TaskDatumParameters::onRefName1(const QString& text) @@ -481,14 +511,19 @@ void TaskDatumParameters::onRefName3(const QString& text) onRefName(text, 2); } -double TaskDatumParameters::getValue1() const +double TaskDatumParameters::getOffset() const +{ + return ui->spinOffset->value(); +} + +double TaskDatumParameters::getAngle() const { - return ui->spinValue1->value(); + return ui->spinAngle->value(); } -bool TaskDatumParameters::getCheck1() const +bool TaskDatumParameters::getFlip() const { - return ui->checkBox1->isChecked(); + return ui->checkBoxFlip->isChecked(); } QString TaskDatumParameters::getReference(const int idx) const @@ -523,8 +558,9 @@ void TaskDatumParameters::changeEvent(QEvent *e) { TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { - ui->spinValue1->blockSignals(true); - ui->checkBox1->blockSignals(true); + ui->spinOffset->blockSignals(true); + ui->spinAngle->blockSignals(true); + ui->checkBoxFlip->blockSignals(true); ui->buttonRef1->blockSignals(true); ui->lineRef1->blockSignals(true); ui->buttonRef2->blockSignals(true); @@ -541,8 +577,9 @@ void TaskDatumParameters::changeEvent(QEvent *e) ui->lineRef3->setText(refstrings[2]); // TODO: Translate DatumView->datumType ? - ui->spinValue1->blockSignals(false); - ui->checkBox1->blockSignals(false); + ui->spinOffset->blockSignals(false); + ui->spinAngle->blockSignals(false); + ui->checkBoxFlip->blockSignals(false); ui->buttonRef1->blockSignals(false); ui->lineRef1->blockSignals(false); ui->buttonRef2->blockSignals(false); @@ -594,7 +631,8 @@ bool TaskDlgDatumParameters::accept() std::string name = DatumView->getObject()->getNameInDocument(); try { - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Values = [%f]",name.c_str(),parameter->getValue1()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f",name.c_str(),parameter->getOffset()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle()); //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Checked = %i",name.c_str(),parameter->getCheckBox1()?1:0); App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.h b/src/Mod/PartDesign/Gui/TaskDatumParameters.h index c2ea01ba5e3e..dc9a4fea4ff5 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.h @@ -54,13 +54,15 @@ class TaskDatumParameters : public Gui::TaskView::TaskBox, public Gui::Selection ~TaskDatumParameters(); QString getReference(const int idx) const; - double getValue1(void) const; - bool getCheck1(void) const; + double getOffset(void) const; + double getAngle(void) const; + bool getFlip(void) const; const bool isCompleted() const { return completed; } private Q_SLOTS: - void onValue1Changed(double); - void onCheckBox1(bool); + void onOffsetChanged(double); + void onAngleChanged(double); + void onCheckFlip(bool); void onRefName1(const QString& text); void onRefName2(const QString& text); void onRefName3(const QString& text); diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui b/src/Mod/PartDesign/Gui/TaskDatumParameters.ui index b8987e098fb5..b780526d132d 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.ui @@ -7,7 +7,7 @@ 0 0 272 - 192 + 215 @@ -57,18 +57,18 @@ - + - + Offset - + - 0.000000000000000 + -999999999.000000000000000 999999999.000000000000000 @@ -77,14 +77,41 @@ 5.000000000000000 - 10.000000000000000 + 0.000000000000000 + + + + + + + + + + + Angle + + + + + + + -360.000000000000000 + + + 360.000000000000000 + + + 1.000000000000000 + + + 0.000000000000000 - + Flip sides From 5b3d5e6bd8568161e9211164b68a562b3a59caf4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 3 May 2013 20:27:25 +0430 Subject: [PATCH 095/664] Moved generic Datum class to Part module to avoid Sketcher dependency on PartDesign --- src/Mod/Part/App/AppPart.cpp | 3 +- src/Mod/Part/App/CMakeLists.txt | 2 + src/Mod/Part/App/DatumFeature.cpp | 103 + src/Mod/Part/App/DatumFeature.h | 75 + src/Mod/Part/App/Part2DObject.cpp | 15 +- src/Mod/PartDesign/App/AppPartDesign.cpp | 5 +- src/Mod/PartDesign/App/Body.cpp | 7 +- src/Mod/PartDesign/App/Body.h | 4 +- src/Mod/PartDesign/App/BodyPyImp.cpp | 1 - src/Mod/PartDesign/App/CMakeLists.txt | 8 +- src/Mod/PartDesign/App/DatumFeature.cpp | 763 --- src/Mod/PartDesign/App/DatumFeature.h | 148 - src/Mod/PartDesign/App/DatumLine.cpp | 280 ++ src/Mod/PartDesign/App/DatumLine.h | 64 + src/Mod/PartDesign/App/DatumPlane.cpp | 317 ++ src/Mod/PartDesign/App/DatumPlane.h | 62 + src/Mod/PartDesign/App/DatumPoint.cpp | 331 ++ src/Mod/PartDesign/App/DatumPoint.h | 69 + src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 4 +- src/Mod/PartDesign/Gui/CMakeLists.txt | 6 + src/Mod/PartDesign/Gui/Command.cpp | 4 +- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 8 +- .../PartDesign/Gui/TaskDatumParameters.cpp | 30 +- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 283 +- src/Mod/PartDesign/Gui/ViewProviderDatum.h | 40 - .../PartDesign/Gui/ViewProviderDatumLine.cpp | 132 + .../PartDesign/Gui/ViewProviderDatumLine.h | 48 + .../PartDesign/Gui/ViewProviderDatumPlane.cpp | 223 + .../PartDesign/Gui/ViewProviderDatumPlane.h | 48 + .../PartDesign/Gui/ViewProviderDatumPoint.cpp | 101 + .../PartDesign/Gui/ViewProviderDatumPoint.h | 48 + src/Mod/PartDesign/Gui/Workbench.cpp | 4 +- src/Mod/Sketcher/App/SketchObject.cpp | 161 +- src/Mod/Sketcher/App/SketchObject.cpp.orig | 4180 +++++++++++++++++ src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 18 +- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 16 +- 36 files changed, 6297 insertions(+), 1314 deletions(-) create mode 100644 src/Mod/Part/App/DatumFeature.cpp create mode 100644 src/Mod/Part/App/DatumFeature.h delete mode 100644 src/Mod/PartDesign/App/DatumFeature.cpp delete mode 100644 src/Mod/PartDesign/App/DatumFeature.h create mode 100644 src/Mod/PartDesign/App/DatumLine.cpp create mode 100644 src/Mod/PartDesign/App/DatumLine.h create mode 100644 src/Mod/PartDesign/App/DatumPlane.cpp create mode 100644 src/Mod/PartDesign/App/DatumPlane.h create mode 100644 src/Mod/PartDesign/App/DatumPoint.cpp create mode 100644 src/Mod/PartDesign/App/DatumPoint.h create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatumLine.h create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatumPlane.h create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDatumPoint.h create mode 100644 src/Mod/Sketcher/App/SketchObject.cpp.orig diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 3b581f4aa5d7..5973dd402355 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -91,6 +91,7 @@ #include "BRepOffsetAPI_MakePipeShellPy.h" #include "PartFeaturePy.h" #include "PropertyGeometryList.h" +#include "DatumFeature.h" namespace Part { extern PyObject* initModule(); @@ -301,7 +302,7 @@ PyMODINIT_FUNC initPart() Part::GeomTrimmedSurface ::init(); Part::GeomSurfaceOfRevolution ::init(); Part::GeomSurfaceOfExtrusion ::init(); - + Part::Datum ::init(); IGESControl_Controller::Init(); STEPControl_Controller::Init(); diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 1328cac34e49..8889304405ef 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -137,6 +137,8 @@ SET(Features_SRCS CustomFeature.h BodyBase.h BodyBase.cpp + DatumFeature.cpp + DatumFeature.h ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) diff --git a/src/Mod/Part/App/DatumFeature.cpp b/src/Mod/Part/App/DatumFeature.cpp new file mode 100644 index 000000000000..a4fe088c3607 --- /dev/null +++ b/src/Mod/Part/App/DatumFeature.cpp @@ -0,0 +1,103 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include "DatumFeature.h" +#include +#include +#include +#include "Mod/Part/App/PrimitiveFeature.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace Part; + +PROPERTY_SOURCE_ABSTRACT(Part::Datum, Part::Feature) + +Datum::Datum(void) +{ + ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); + ADD_PROPERTY(Offset,(0.0)); + ADD_PROPERTY(Angle,(0.0)); + touch(); +} + +Datum::~Datum() +{ +} + +void Datum::onChanged (const App::Property* prop) +{ + Part::Feature::onChanged(prop); +} + +App::DocumentObjectExecReturn *Datum::execute(void) +{ + References.touch(); + return StdReturn; +} + +void Datum::onDocumentRestored() +{ + // This seems to be the only way to make the ViewProvider display the datum feature + References.touch(); + Part::Feature::onDocumentRestored(); +} + diff --git a/src/Mod/Part/App/DatumFeature.h b/src/Mod/Part/App/DatumFeature.h new file mode 100644 index 000000000000..c10126138ab0 --- /dev/null +++ b/src/Mod/Part/App/DatumFeature.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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_DATUMFEATURE_H +#define PART_DATUMFEATURE_H + +#include +#include + +#include "PartFeature.h" + +namespace Part +{ + +// This generic class is defined here so that the Sketcher module can access datum features +// without creating a dependency on PartDesign + +class PartExport Datum : public Part::Feature +{ + PROPERTY_HEADER(Part::Datum); + +public: + Datum(); + virtual ~Datum(); + + /// The references defining the datum object, e.g. three planes for a point, two planes for a line + App::PropertyLinkSubList References; + /// Offset and angle for defining planes + App::PropertyFloat Offset; + App::PropertyFloat Angle; + + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + + /// returns the type name of the view provider + virtual const char* getViewProviderName(void) const = 0; + + virtual const std::set getHint() = 0; + + /// Return a shape representing the datum feature + //virtual const TopoDS_Shape getShape() const = 0; + +protected: + void onChanged (const App::Property* prop); + void onDocumentRestored(); + +protected: + std::multiset refTypes; + +}; + +} //namespace Part + + +#endif // PART_DATUMFEATURE_H diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index b70c337bb0ac..e6122d69fd28 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -48,6 +48,7 @@ #include #include "Part2DObject.h" #include "Geometry.h" +#include "DatumFeature.h" #include #include "Part2DObjectPy.h" @@ -96,7 +97,7 @@ void Part2DObject::positionBySupport(void) // Set placement identical to the way it used to be done in the Sketcher::SketchOrientationDialog if (dir == Base::Vector3d(0,0,1)) { - Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Reverse ? -1.0 : 0.0,0.0,0.0,0.0)); + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Reverse ? -1.0 : 0.0, 0.0,0.0,0.0)); } else if (dir == Base::Vector3d(0,1,0)) { if (Reverse) Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Base::Vector3d(0,sqrt(2.0)/2.0,sqrt(2.0)/2.0),M_PI)); @@ -111,6 +112,18 @@ void Part2DObject::positionBySupport(void) Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); Base::Vector3d pos = Place.getPosition(); plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); + } else if (support->getTypeId() == Part::Datum::getClassTypeId()) { + Part::Datum* pcDatum = static_cast(support); + TopoDS_Shape plane = pcDatum->Shape.getValue(); + if (plane.ShapeType() != TopAbs_FACE) + return; + BRepAdaptor_Surface adapt(TopoDS::Face(plane)); + if (adapt.GetType() != GeomAbs_Plane) + return; + gp_Pln pl = adapt.Plane(); + Base::Vector3d pos(pl.Location().X(), pl.Location().Y(), pl.Location().Z()); + Base::Vector3d normal(pl.Axis().Direction().X(), pl.Axis().Direction().Y(), pl.Axis().Direction().Z()); + this->Placement.setValue(Base::Placement(pos, Base::Rotation(Base::Vector3d(0,0,1), normal))); } else { Part::Feature *part = static_cast(support); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 98782e7a2733..55e52e5ec656 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -49,7 +49,9 @@ #include "FeatureScaled.h" #include "FeatureMultiTransform.h" #include "FeatureHole.h" -#include "DatumFeature.h" +#include "DatumPlane.h" +#include "DatumLine.h" +#include "DatumPoint.h" namespace PartDesign { extern PyObject* initModule(); @@ -97,7 +99,6 @@ PyMODINIT_FUNC init_PartDesign() PartDesign::Groove ::init(); PartDesign::Chamfer ::init(); PartDesign::Draft ::init(); - PartDesign::Datum ::init(); PartDesign::Plane ::init(); PartDesign::Line ::init(); PartDesign::Point ::init(); diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index fb6632772769..4ed343a75013 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -28,14 +28,14 @@ #include #include "Feature.h" -#include "DatumFeature.h" #include "Body.h" #include "BodyPy.h" +#include "FeatureSketchBased.h" #include #include #include -#include "FeatureSketchBased.h" +#include using namespace PartDesign; @@ -192,7 +192,7 @@ const bool Body::isAllowed(const App::DocumentObject* f) return false; return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || - f->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId()) || + f->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); } @@ -214,7 +214,6 @@ Body* Body::findBodyOf(const App::DocumentObject* f) void Body::addFeature(App::DocumentObject *feature) { // Set the BaseFeature property - // Note: This is not strictly necessary for Datum features if (feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { App::DocumentObject* prevSolidFeature = getPrevSolidFeature(NULL, true); if (prevSolidFeature != NULL) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 18b58d84edda..519f7486af1a 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -91,13 +91,13 @@ class Body : public Part::BodyBase /** * Return true if the given feature is a solid feature allowed in a Body. Currently this is only valid * for features derived from PartDesign::Feature - * Return false if the given feature is a Sketch or a PartDesign::Datum feature + * Return false if the given feature is a Sketch or a Part::Datum feature */ static const bool isSolidFeature(const App::DocumentObject* f); /** * Return true if the given feature is allowed in a Body. Currently allowed are - * all features derived from PartDesign::Feature and PartDesign::Datum and sketches + * all features derived from PartDesign::Feature and Part::Datum and sketches */ static const bool isAllowed(const App::DocumentObject* f); diff --git a/src/Mod/PartDesign/App/BodyPyImp.cpp b/src/Mod/PartDesign/App/BodyPyImp.cpp index f66754810648..195b88fd407a 100644 --- a/src/Mod/PartDesign/App/BodyPyImp.cpp +++ b/src/Mod/PartDesign/App/BodyPyImp.cpp @@ -3,7 +3,6 @@ #include "Mod/Part/App/Part2DObject.h" #include "Mod/PartDesign/App/Body.h" -#include "Mod/PartDesign/App/DatumFeature.h" // inclusion of the generated files (generated out of ItemPy.xml) #include "BodyPy.h" diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 725c2cc8a913..9578300e51d1 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -39,8 +39,12 @@ SET(Features_SRCS SOURCE_GROUP("Features" FILES ${Features_SRCS}) SET(DatumFeatures_SRCS - DatumFeature.cpp - DatumFeature.h + DatumPlane.cpp + DatumPlane.h + DatumLine.cpp + DatumLine.h + DatumPoint.cpp + DatumPoint.h ) SOURCE_GROUP("DatumFeatures" FILES ${DatumFeatures_SRCS}) diff --git a/src/Mod/PartDesign/App/DatumFeature.cpp b/src/Mod/PartDesign/App/DatumFeature.cpp deleted file mode 100644 index e9268c050d2b..000000000000 --- a/src/Mod/PartDesign/App/DatumFeature.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Jan Rheinländer * - * * - * 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 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -#endif - -#include -#include -#include "DatumFeature.h" -#include -#include -#include -#include "Mod/Part/App/PrimitiveFeature.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -using namespace PartDesign; - -PROPERTY_SOURCE_ABSTRACT(PartDesign::Datum, App::GeoFeature) - -Datum::Datum(void) -{ - ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); - ADD_PROPERTY(Offset,(0.0)); - ADD_PROPERTY(Angle,(0.0)); - touch(); -} - -Datum::~Datum() -{ -} - - -App::DocumentObjectExecReturn *Datum::execute(void) -{ - References.touch(); - return StdReturn; -} - -// Note: We don't distinguish between e.g. datum lines and edges here -#define PLANE QObject::tr("DPLANE") -#define LINE QObject::tr("DLINE") -#define POINT QObject::tr("DPOINT") -#define ANGLE QObject::tr("Angle") - -void Datum::onChanged(const App::Property* prop) -{ - - if (prop == &References) { - refTypes.clear(); - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - - for (int r = 0; r < refs.size(); r++) - refTypes.insert(getRefType(refs[r], refnames[r])); - - if (fabs(Angle.getValue()) > Precision::Confusion()) - refTypes.insert(ANGLE); - } else if (prop == &Angle) { - // Zero value counts as angle not defined - if (fabs(Angle.getValue()) > Precision::Confusion()) - refTypes.insert(ANGLE); - else - refTypes.erase(ANGLE); - } - - App::GeoFeature::onChanged(prop); -} - -void Datum::onDocumentRestored() -{ - // This seems to be the only way to make the ViewProvider display the datum feature - References.touch(); - App::GeoFeature::onDocumentRestored(); -} - -const QString Datum::getRefType(const App::DocumentObject* obj, const std::string& subname) -{ - Base::Type type = obj->getTypeId(); - - if ((type == App::Plane::getClassTypeId()) || (type == PartDesign::Plane::getClassTypeId())) - return PLANE; - else if (type == PartDesign::Line::getClassTypeId()) - return LINE; - else if (type == PartDesign::Point::getClassTypeId()) - return POINT; - else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { - // Note: For now, only planar references are possible - if (subname.size() > 4 && subname.substr(0,4) == "Face") - return PLANE; - else if (subname.size() > 4 && subname.substr(0,4) == "Edge") - return LINE; - else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") - return POINT; - } - - throw Base::Exception("PartDesign::Datum::getRefType(): Illegal object type"); -} - -// ================================ Initialize the hints ===================== - -std::map, std::set > Point::hints = std::map, std::set >(); - -void Point::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - key.insert(POINT); - hints[key] = DONE; // POINT -> DONE. Point from another point or vertex - - key.clear(); value.clear(); - key.insert(LINE); - value.insert(LINE); value.insert(PLANE); - hints[key] = value; // LINE -> LINE or PLANE - - key.clear(); value.clear(); - key.insert(LINE); key.insert(LINE); - hints[key] = DONE; // {LINE, LINE} -> DONE. Point from two lines or edges - - key.clear(); value.clear(); - key.insert(LINE); key.insert(PLANE); - hints[key] = DONE; // {LINE, PLANE} -> DONE. Point from line and plane - - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(PLANE); value.insert(LINE); - hints[key] = value; // PLANE -> PLANE or LINE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); - value.insert(PLANE); - hints[key] = value; // {PLANE, PLANE} -> PLANE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); key.insert(PLANE); - hints[key] = DONE; // {PLANE, PLANE, PLANE} -> DONE. Point from three planes - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} - -std::map, std::set > Line::hints = std::map, std::set >(); - -void Line::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - key.insert(LINE); - hints[key] = DONE; // LINE -> DONE. Line from another line or edge - - key.clear(); value.clear(); - key.insert(POINT); - value.insert(POINT); - hints[key] = value; // POINT -> POINT - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); - hints[key] = DONE; // {POINT, POINT} -> DONE. Line from two points or vertices - - key.clear(); value.clear(); - key.insert(PLANE); - value.insert(PLANE); - hints[key] = value; // PLANE -> PLANE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(PLANE); - hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); - hints[key] = value; -} - -std::map, std::set > Plane::hints = std::map, std::set >(); - -void Plane::initHints() -{ - std::set DONE; - DONE.insert(QObject::tr("Done")); - - std::multiset key; - std::set value; - key.insert(PLANE); - hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face - - key.clear(); value.clear(); - key.insert(POINT); - value.insert(POINT); value.insert(LINE); - hints[key] = value; // POINT -> POINT or LINE - - key.clear(); value.clear(); - key.insert(POINT); key.insert(LINE); - hints[key] = DONE; // {POINT, LINE} -> DONE. Plane from point/vertex and line/edge - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); - value.insert(POINT); - hints[key] = value; // {POINT, POINT} -> POINT - - key.clear(); value.clear(); - key.insert(POINT); key.insert(POINT); key.insert(POINT); - hints[key] = DONE; // {POINT, POINT, POINT} -> DONE. Plane from 3 points or vertices - - key.clear(); value.clear(); - key.insert(LINE); - value.insert(POINT); value.insert(PLANE); value.insert(ANGLE); - hints[key] = value; // LINE -> POINT or PLANE or ANGLE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(LINE); - value.insert(ANGLE); - hints[key] = value; // {PLANE, LINE} -> ANGLE - - key.clear(); value.clear(); - key.insert(PLANE); key.insert(ANGLE); - value.insert(LINE); - hints[key] = value; // {PLANE, ANGLE} -> LINE - - key.clear(); value.clear(); - key.insert(ANGLE); key.insert(LINE); - value.insert(PLANE); - hints[key] = value; // {ANGLE, LINE} -> PLANE - - key.clear(); value.clear(); - key.insert(LINE); key.insert(PLANE); key.insert(ANGLE); - hints[key] = DONE; // {LINE, PLANE, ANGLE} -> DONE. Plane through line with angle to other plane - - - key.clear(); value.clear(); - value.insert(POINT); value.insert(LINE); value.insert(PLANE); value.insert(ANGLE); - hints[key] = value; -} - -// ============================================================================ - -PROPERTY_SOURCE(PartDesign::Point, PartDesign::Datum) - -Point::Point() -{ - ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,0)),"DatumPoint", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the datum point"); -} - -Point::~Point() -{ -} - -void Point::onChanged(const App::Property* prop) -{ - Datum::onChanged(prop); - - if (prop == &References) { - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - Base::Vector3d* point = NULL; - Handle_Geom_Curve c1 = NULL; - Handle_Geom_Curve c2 = NULL; - Handle_Geom_Surface s1 = NULL; - Handle_Geom_Surface s2 = NULL; - Handle_Geom_Surface s3 = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - point = new Base::Vector3d (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - Base::Vector3d base = l->_Base.getValue(); - Base::Vector3d dir = l->_Direction.getValue(); - if (c1.IsNull()) - c1 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); - else - c2 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - Base::Vector3d base = p->_Base.getValue(); - Base::Vector3d normal = p->_Normal.getValue(); - if (s1.IsNull()) - s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - else if (s2.IsNull()) - s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - else - s3 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - // Note: We only handle the three base planes here - gp_Pnt base(0,0,0); - gp_Dir normal; - if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) - normal = gp_Dir(0,0,1); - else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) - normal = gp_Dir(1,0,0); - else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) - normal = gp_Dir(0,1,0); - - if (s1.IsNull()) - s1 = new Geom_Plane(base, normal); - else if (s2.IsNull()) - s2 = new Geom_Plane(base, normal); - else - s3 = new Geom_Plane(base, normal); - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Point: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Point: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - Standard_Real first, last; - if (c1.IsNull()) - c1 = BRep_Tool::Curve(e, first, last); - else - c2 = BRep_Tool::Curve(e, first, last); - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - if (s1.IsNull()) - s1 = BRep_Tool::Surface(f); - else if (s2.IsNull()) - s2 = BRep_Tool::Surface(f); - else - s3 = BRep_Tool::Surface(f); - } - } else { - return; //"PartDesign::Point: Invalid reference type" - } - } - - if (point != NULL) { - // Point from vertex or other point. Nothing to be done - } else if (!c1.IsNull()) { - if (!c2.IsNull()) { - // Point from intersection of two curves - GeomAPI_ExtremaCurveCurve intersector(c1, c2); - if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) - return; // No intersection - // Note: We don't check for multiple intersection points - gp_Pnt p, p2; - intersector.Points(1, p, p2); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (!s1.IsNull()) { - GeomAPI_IntCS intersector(c1, s1); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - return; - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from curve and surface"); - - gp_Pnt p = intersector.Point(1); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else - return; - } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { - GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); - if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) - return; - if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection line for datum point from surfaces"); - Handle_Geom_Curve line = intersectorSS.Line(1); - - GeomAPI_IntCS intersector(line, s3); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - return; - if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from surfaces"); - - gp_Pnt p = intersector.Point(1); - point = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else { - return; - } - - _Point.setValue(*point); - _Point.touch(); // This triggers ViewProvider::updateData() - delete point; - } -} - - -const std::set Point::getHint() -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - - -PROPERTY_SOURCE(PartDesign::Line, PartDesign::Datum) - -Line::Line() -{ - ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumLine", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the line base point"); - ADD_PROPERTY_TYPE(_Direction,(Base::Vector3d(1,1,1)),"DatumLine", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the line direction"); -} - -Line::~Line() -{ -} - -void Line::onChanged(const App::Property *prop) -{ - Datum::onChanged(prop); - - if (prop == &References) { - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - Base::Vector3d* base = NULL; - Base::Vector3d* direction = NULL; - Base::Vector3d* p1 = NULL; - Base::Vector3d* p2 = NULL; - gp_Lin* line = NULL; - Handle_Geom_Surface s1 = NULL; - Handle_Geom_Surface s2 = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - if (p1 == NULL) - p1 = new Base::Vector3d (p->_Point.getValue()); - else - p2 = new Base::Vector3d (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - base = new Base::Vector3d (l->_Base.getValue()); - direction = new Base::Vector3d (l->_Direction.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - Base::Vector3d base = p->_Base.getValue(); - Base::Vector3d normal = p->_Normal.getValue(); - if (s1.IsNull()) - s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - else - s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - // Note: We only handle the three base planes here - gp_Pnt base(0,0,0); - gp_Dir normal; - if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) - normal = gp_Dir(0,0,1); - else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) - normal = gp_Dir(1,0,0); - else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) - normal = gp_Dir(0,1,0); - - if (s1.IsNull()) - s1 = new Geom_Plane(base, normal); - else - s2 = new Geom_Plane(base, normal); - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Line: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Line: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - if (p1 == NULL) - p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - else - p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - BRepAdaptor_Curve adapt(e); - if (adapt.GetType() != GeomAbs_Line) - return; // Non-linear edge - line = new gp_Lin(adapt.Line()); - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - if (s1.IsNull()) - s1 = BRep_Tool::Surface(f); - else - s2 = BRep_Tool::Surface(f); - } - } else { - return; //"PartDesign::Point: Invalid reference type" - } - } - - if ((base != NULL) && (direction != NULL)) { - // Line from other datum line. Nothing to be done - } else if ((p1 != NULL) && (p2 != NULL)) { - // Line from two points - base = new Base::Vector3d(*p1); - direction = new Base::Vector3d(*p2 - *p1); - } else if (line != NULL) { - // Line from gp_lin - base = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); - direction = new Base::Vector3d(line->Direction().X(), line->Direction().Y(), line->Direction().Z()); - } else if (!s1.IsNull() && !s2.IsNull()) { - GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); - if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) - return; - if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection line for datum point from surfaces"); - Handle_Geom_Line l = Handle_Geom_Line::DownCast(intersectorSS.Line(1)); - if (l.IsNull()) - return; // non-linear intersection curve - gp_Lin lin = l->Lin(); - base = new Base::Vector3d(lin.Location().X(), lin.Location().Y(), lin.Location().Z()); - direction = new Base::Vector3d(lin.Direction().X(), lin.Direction().Y(), lin.Direction().Z()); - } else { - return; - } - - _Base.setValue(*base); - _Direction.setValue(*direction); - _Base.touch(); // This triggers ViewProvider::updateData() - delete base; - delete direction; - if (p1 != NULL) delete p1; - if (p2 != NULL) delete p2; - if (line != NULL) delete line; - } -} - - -const std::set Line::getHint() -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} - - -PROPERTY_SOURCE(PartDesign::Plane, PartDesign::Datum) - -Plane::Plane() -{ -ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumPlane", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the plane base point"); -ADD_PROPERTY_TYPE(_Normal,(Base::Vector3d(1,1,1)),"DatumPlane", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the plane normal"); -} - -void Plane::onChanged(const App::Property *prop) -{ - Datum::onChanged(prop); - - if (prop == &References) { - std::set hint = getHint(); - if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) - return; // incomplete references - - // Extract the geometry of the references - std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); - Base::Vector3d* p1 = NULL; - Base::Vector3d* p2 = NULL; - Base::Vector3d* p3 = NULL; - Base::Vector3d* normal = NULL; - gp_Lin* line = NULL; - - for (int i = 0; i < refs.size(); i++) { - if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { - PartDesign::Point* p = static_cast(refs[i]); - if (p1 == NULL) - p1 = new Base::Vector3d (p->_Point.getValue()); - else if (p2 == NULL) - p2 = new Base::Vector3d (p->_Point.getValue()); - else - p3 = new Base::Vector3d (p->_Point.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { - PartDesign::Line* l = static_cast(refs[i]); - Base::Vector3d base = l->_Base.getValue(); - Base::Vector3d dir = l->_Direction.getValue(); - line = new gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); - } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - PartDesign::Plane* p = static_cast(refs[i]); - p1 = new Base::Vector3d(p->_Base.getValue()); - normal = new Base::Vector3d(p->_Normal.getValue()); - } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* p = static_cast(refs[i]); - // Note: We only handle the three base planes here - p1 = new Base::Vector3d(0,0,0); - normal = new Base::Vector3d; - if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) - *normal = Base::Vector3d(0,0,1); - else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) - *normal = Base::Vector3d(1,0,0); - else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) - *normal = Base::Vector3d(0,1,0); - } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - Part::Feature* feature = static_cast(refs[i]); - const TopoDS_Shape& sh = feature->Shape.getValue(); - if (sh.IsNull()) - return; // "PartDesign::Plane: Reference has NULL shape" - // Get subshape - TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); - if (subshape.IsNull()) - return; // "PartDesign::Plane: Reference has NULL subshape"; - - if (subshape.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v = TopoDS::Vertex(subshape); - gp_Pnt p = BRep_Tool::Pnt(v); - if (p1 == NULL) - p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - else if (p2 == NULL) - p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - else - p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - } else if (subshape.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge e = TopoDS::Edge(subshape); - BRepAdaptor_Curve adapt(e); - if (adapt.GetType() != GeomAbs_Line) - return; // Non-linear edge - line = new gp_Lin(adapt.Line()); - } else if (subshape.ShapeType() == TopAbs_FACE) { - TopoDS_Face f = TopoDS::Face(subshape); - BRepAdaptor_Surface adapt(f); - if (adapt.GetType() != GeomAbs_Plane) - return; // Non-planar face - gp_Pnt b = adapt.Plane().Location(); - gp_Dir d = adapt.Plane().Axis().Direction(); - p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); - normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); - } - } else { - return; //"PartDesign::Plane: Invalid reference type" - } - } - - *normal = normal->Normalize(); - - if ((line != NULL) && (normal != NULL) && (p1 != NULL) && (fabs(Angle.getValue()) > Precision::Confusion())) { - // plane from line, plane, and angle to plane - gp_Pnt p = line->Location(); - *p1 = Base::Vector3d(p.X(), p.Y(), p.Z()); - gp_Dir dir = line->Direction(); - Base::Rotation rot(Base::Vector3d(dir.X(), dir.Y(), dir.Z()), Angle.getValue() / 180.0 * M_PI); - rot.multVec(*normal, *normal); - } else if ((p1 != NULL) && (normal != NULL)) { - // plane from other plane. Nothing to be done - } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { - // Plane from three points - Base::Vector3d vec1 = *p2 - *p1; - Base::Vector3d vec2 = *p3 - *p1; - normal = new Base::Vector3d(vec1 % vec2); - } else if ((line != NULL) && (p1 != NULL)) { - // Plane from point and line - p2 = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); - gp_Pnt p(line->Location().X() + line->Direction().X(), line->Location().Y() + line->Direction().Y(), line->Location().Z() + line->Direction().Z()); - p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); - Base::Vector3d vec1 = *p2 - *p1; - Base::Vector3d vec2 = *p3 - *p1; - normal = new Base::Vector3d(vec1 % vec2); - } else { - return; - } - - if (fabs(Offset.getValue()) > Precision::Confusion()) - *p1 += Offset.getValue() * *normal; - - _Base.setValue(*p1); - _Normal.setValue(*normal); - _Base.touch(); // This triggers ViewProvider::updateData() - delete p1; - delete normal; - if (p2 != NULL) delete p2; - if (p3 != NULL) delete p3; - if (line != NULL) delete line; - } -} - - -const std::set Plane::getHint() -{ - if (hints.find(refTypes) != hints.end()) - return hints[refTypes]; - else - return std::set(); -} diff --git a/src/Mod/PartDesign/App/DatumFeature.h b/src/Mod/PartDesign/App/DatumFeature.h deleted file mode 100644 index ab4e357b90f4..000000000000 --- a/src/Mod/PartDesign/App/DatumFeature.h +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Jan Rheinländer * - * * - * 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 PARTDESIGN_DATUMFEATURE_H -#define PARTDESIGN_DATUMFEATURE_H - -#include -#include -#include - -namespace PartDesign -{ - -class PartDesignExport Datum : public App::GeoFeature -{ - PROPERTY_HEADER(PartDesign::Datum); - -public: - Datum(); - virtual ~Datum(); - - /// The references defining the datum object, e.g. three planes for a point, two planes for a line - App::PropertyLinkSubList References; - /// Offset and angle for defining planes - App::PropertyFloat Offset; - App::PropertyFloat Angle; - - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "PartDesignGui::ViewProviderDatum"; - } - - virtual const std::set getHint() = 0; - -protected: - void onChanged (const App::Property* prop); - void onDocumentRestored(); - -protected: - std::multiset refTypes; - - static const QString getRefType(const App::DocumentObject* obj, const std::string& subname); - -}; - -class PartDesignExport Point : public PartDesign::Datum -{ - PROPERTY_HEADER(PartDesign::Point); - -public: - App::PropertyVector _Point; - - Point(); - virtual ~Point(); - - const char* getViewProviderName(void) const { - return "PartDesignGui::ViewProviderDatumPoint"; - } - - static void initHints(); - const std::set getHint(); - -protected: - virtual void onChanged(const App::Property* prop); - -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; -}; - -class PartDesignExport Line : public PartDesign::Datum -{ - PROPERTY_HEADER(PartDesign::Line); - -public: - App::PropertyVector _Base; - App::PropertyVector _Direction; - - Line(); - virtual ~Line(); - - const char* getViewProviderName(void) const { - return "PartDesignGui::ViewProviderDatumLine"; - } - - static void initHints(); - const std::set getHint(); - -protected: - virtual void onChanged(const App::Property* prop); - -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; -}; - -class PartDesignExport Plane : public PartDesign::Datum -{ - PROPERTY_HEADER(PartDesign::Plane); - -public: - App::PropertyVector _Base; - App::PropertyVector _Normal; - - Plane(); - - const char* getViewProviderName(void) const { - return "PartDesignGui::ViewProviderDatumPlane"; - } - - static void initHints(); - const std::set getHint(); - -protected: - virtual void onChanged(const App::Property* prop); - -private: - // Hints on what further references are required/possible on this feature for a given set of references - static std::map, std::set > hints; -}; - -} //namespace PartDesign - - -#endif // PARTDESIGN_DATUMFEATURE_H diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp new file mode 100644 index 000000000000..f59e93220b5b --- /dev/null +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -0,0 +1,280 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include "DatumPoint.h" +#include "DatumLine.h" +#include "DatumPlane.h" +#include +#include +#include +#include "Mod/Part/App/PrimitiveFeature.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace PartDesign; + +// Note: We don't distinguish between e.g. datum lines and edges here +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") +#define ANGLE QObject::tr("Angle") + +std::map, std::set > Line::hints = std::map, std::set >(); + +void Line::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Done")); + + std::multiset key; + std::set value; + key.insert(LINE); + hints[key] = DONE; // LINE -> DONE. Line from another line or edge + + key.clear(); value.clear(); + key.insert(POINT); + value.insert(POINT); + hints[key] = value; // POINT -> POINT + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); + hints[key] = DONE; // {POINT, POINT} -> DONE. Line from two points or vertices + + key.clear(); value.clear(); + key.insert(PLANE); + value.insert(PLANE); + hints[key] = value; // PLANE -> PLANE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); + hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +PROPERTY_SOURCE(PartDesign::Line, Part::Datum) + +Line::Line() +{ + ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumLine", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the line base point"); + ADD_PROPERTY_TYPE(_Direction,(Base::Vector3d(1,1,1)),"DatumLine", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the line direction"); +} + +Line::~Line() +{ +} + +void Line::onChanged(const App::Property *prop) +{ + Datum::onChanged(prop); + + if (prop == &References) { + refTypes.clear(); + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + + for (int r = 0; r < refs.size(); r++) + refTypes.insert(getRefType(refs[r], refnames[r])); + + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + Base::Vector3d* base = NULL; + Base::Vector3d* direction = NULL; + Base::Vector3d* p1 = NULL; + Base::Vector3d* p2 = NULL; + gp_Lin* line = NULL; + Handle_Geom_Surface s1 = NULL; + Handle_Geom_Surface s2 = NULL; + + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + if (p1 == NULL) + p1 = new Base::Vector3d (p->_Point.getValue()); + else + p2 = new Base::Vector3d (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + base = new Base::Vector3d (l->_Base.getValue()); + direction = new Base::Vector3d (l->_Direction.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + Base::Vector3d base = p->_Base.getValue(); + Base::Vector3d normal = p->_Normal.getValue(); + if (s1.IsNull()) + s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + else + s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + // Note: We only handle the three base planes here + gp_Pnt base(0,0,0); + gp_Dir normal; + if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) + normal = gp_Dir(0,0,1); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + normal = gp_Dir(1,0,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) + normal = gp_Dir(0,1,0); + + if (s1.IsNull()) + s1 = new Geom_Plane(base, normal); + else + s2 = new Geom_Plane(base, normal); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Line: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Line: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + if (p1 == NULL) + p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + else + p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + BRepAdaptor_Curve adapt(e); + if (adapt.GetType() != GeomAbs_Line) + return; // Non-linear edge + line = new gp_Lin(adapt.Line()); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + if (s1.IsNull()) + s1 = BRep_Tool::Surface(f); + else + s2 = BRep_Tool::Surface(f); + } + } else { + return; //"PartDesign::Point: Invalid reference type" + } + } + + if ((base != NULL) && (direction != NULL)) { + // Line from other datum line. Nothing to be done + } else if ((p1 != NULL) && (p2 != NULL)) { + // Line from two points + base = new Base::Vector3d(*p1); + direction = new Base::Vector3d(*p2 - *p1); + } else if (line != NULL) { + // Line from gp_lin + base = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); + direction = new Base::Vector3d(line->Direction().X(), line->Direction().Y(), line->Direction().Z()); + } else if (!s1.IsNull() && !s2.IsNull()) { + GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); + if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) + return; + if (intersectorSS.NbLines() > 1) + Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Handle_Geom_Line l = Handle_Geom_Line::DownCast(intersectorSS.Line(1)); + if (l.IsNull()) + return; // non-linear intersection curve + gp_Lin lin = l->Lin(); + base = new Base::Vector3d(lin.Location().X(), lin.Location().Y(), lin.Location().Z()); + direction = new Base::Vector3d(lin.Direction().X(), lin.Direction().Y(), lin.Direction().Z()); + } else { + return; + } + + _Base.setValue(*base); + _Direction.setValue(*direction); + _Base.touch(); // This triggers ViewProvider::updateData() + + // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of + // Sketcher on the PartDesign module + BRepBuilderAPI_MakeEdge builder(gp_Lin(gp_Pnt(base->x, base->y, base->z), gp_Dir(direction->x, direction->y, direction->z))); + if (!builder.IsDone()) + return; + Shape.setValue(builder.Shape()); + + delete base; + delete direction; + if (p1 != NULL) delete p1; + if (p2 != NULL) delete p2; + if (line != NULL) delete line; + } + + Part::Datum::onChanged(prop); +} + + +const std::set Line::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} diff --git a/src/Mod/PartDesign/App/DatumLine.h b/src/Mod/PartDesign/App/DatumLine.h new file mode 100644 index 000000000000..6ca976106ea4 --- /dev/null +++ b/src/Mod/PartDesign/App/DatumLine.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 PARTDESIGN_DATUMLINE_H +#define PARTDESIGN_DATUMLINE_H + +#include +#include +#include +#include + +namespace PartDesign +{ + +class PartDesignExport Line : public Part::Datum +{ + PROPERTY_HEADER(PartDesign::Line); + +public: + App::PropertyVector _Base; + App::PropertyVector _Direction; + + Line(); + virtual ~Line(); + + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatumLine"; + } + + static void initHints(); + const std::set getHint(); + +protected: + virtual void onChanged(const App::Property* prop); + +private: + // Hints on what further references are required/possible on this feature for a given set of references + static std::map, std::set > hints; +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_DATUMLINE_H diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp new file mode 100644 index 000000000000..6c76913881ca --- /dev/null +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -0,0 +1,317 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include "DatumPoint.h" +#include "DatumLine.h" +#include "DatumPlane.h" +#include +#include +#include +#include "Mod/Part/App/PrimitiveFeature.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace PartDesign; + +// Note: We don't distinguish between e.g. datum lines and edges here +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") +#define ANGLE QObject::tr("Angle") + +std::map, std::set > Plane::hints = std::map, std::set >(); + +void Plane::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Done")); + + std::multiset key; + std::set value; + key.insert(PLANE); + hints[key] = DONE; // PLANE -> DONE. Plane from another plane or face + + key.clear(); value.clear(); + key.insert(POINT); + value.insert(POINT); value.insert(LINE); + hints[key] = value; // POINT -> POINT or LINE + + key.clear(); value.clear(); + key.insert(POINT); key.insert(LINE); + hints[key] = DONE; // {POINT, LINE} -> DONE. Plane from point/vertex and line/edge + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); + value.insert(POINT); + hints[key] = value; // {POINT, POINT} -> POINT + + key.clear(); value.clear(); + key.insert(POINT); key.insert(POINT); key.insert(POINT); + hints[key] = DONE; // {POINT, POINT, POINT} -> DONE. Plane from 3 points or vertices + + key.clear(); value.clear(); + key.insert(LINE); + value.insert(POINT); value.insert(PLANE); value.insert(ANGLE); + hints[key] = value; // LINE -> POINT or PLANE or ANGLE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(LINE); + value.insert(ANGLE); + hints[key] = value; // {PLANE, LINE} -> ANGLE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(ANGLE); + value.insert(LINE); + hints[key] = value; // {PLANE, ANGLE} -> LINE + + key.clear(); value.clear(); + key.insert(ANGLE); key.insert(LINE); + value.insert(PLANE); + hints[key] = value; // {ANGLE, LINE} -> PLANE + + key.clear(); value.clear(); + key.insert(LINE); key.insert(PLANE); key.insert(ANGLE); + hints[key] = DONE; // {LINE, PLANE, ANGLE} -> DONE. Plane through line with angle to other plane + + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); value.insert(ANGLE); + hints[key] = value; +} + +// ============================================================================ + +PROPERTY_SOURCE(PartDesign::Plane, Part::Datum) + +Plane::Plane() +{ +ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumPlane", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the plane base point"); +ADD_PROPERTY_TYPE(_Normal,(Base::Vector3d(1,1,1)),"DatumPlane", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the plane normal"); +} + +void Plane::onChanged(const App::Property *prop) +{ + Datum::onChanged(prop); + + if (prop == &Angle) { + // Zero value counts as angle not defined + if (fabs(Angle.getValue()) > Precision::Confusion()) + refTypes.insert(ANGLE); + else + refTypes.erase(ANGLE); + } + + if (prop == &References) { + refTypes.clear(); + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + + for (int r = 0; r < refs.size(); r++) + refTypes.insert(getRefType(refs[r], refnames[r])); + + if (fabs(Angle.getValue()) > Precision::Confusion()) + refTypes.insert(ANGLE); + + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + Base::Vector3d* p1 = NULL; + Base::Vector3d* p2 = NULL; + Base::Vector3d* p3 = NULL; + Base::Vector3d* normal = NULL; + gp_Lin* line = NULL; + + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + if (p1 == NULL) + p1 = new Base::Vector3d (p->_Point.getValue()); + else if (p2 == NULL) + p2 = new Base::Vector3d (p->_Point.getValue()); + else + p3 = new Base::Vector3d (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + Base::Vector3d base = l->_Base.getValue(); + Base::Vector3d dir = l->_Direction.getValue(); + line = new gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + p1 = new Base::Vector3d(p->_Base.getValue()); + normal = new Base::Vector3d(p->_Normal.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + // Note: We only handle the three base planes here + p1 = new Base::Vector3d(0,0,0); + normal = new Base::Vector3d; + if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) + *normal = Base::Vector3d(0,0,1); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + *normal = Base::Vector3d(1,0,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) + *normal = Base::Vector3d(0,1,0); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Plane: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Plane: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + if (p1 == NULL) + p1 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + else if (p2 == NULL) + p2 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + else + p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + BRepAdaptor_Curve adapt(e); + if (adapt.GetType() != GeomAbs_Line) + return; // Non-linear edge + line = new gp_Lin(adapt.Line()); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + BRepAdaptor_Surface adapt(f); + if (adapt.GetType() != GeomAbs_Plane) + return; // Non-planar face + gp_Pnt b = adapt.Plane().Location(); + gp_Dir d = adapt.Plane().Axis().Direction(); + p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); + normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); + } + } else { + return; //"PartDesign::Plane: Invalid reference type" + } + } + + if ((line != NULL) && (normal != NULL) && (p1 != NULL) && (fabs(Angle.getValue()) > Precision::Confusion())) { + // plane from line, plane, and angle to plane + *normal = normal->Normalize(); + gp_Pnt p = line->Location(); + *p1 = Base::Vector3d(p.X(), p.Y(), p.Z()); + gp_Dir dir = line->Direction(); + Base::Rotation rot(Base::Vector3d(dir.X(), dir.Y(), dir.Z()), Angle.getValue() / 180.0 * M_PI); + rot.multVec(*normal, *normal); + } else if ((p1 != NULL) && (normal != NULL)) { + // plane from other plane. Nothing to be done + } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { + // Plane from three points + Base::Vector3d vec1 = *p2 - *p1; + Base::Vector3d vec2 = *p3 - *p1; + normal = new Base::Vector3d(vec1 % vec2); + } else if ((line != NULL) && (p1 != NULL)) { + // Plane from point and line + p2 = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); + gp_Pnt p(line->Location().X() + line->Direction().X(), line->Location().Y() + line->Direction().Y(), line->Location().Z() + line->Direction().Z()); + p3 = new Base::Vector3d(p.X(), p.Y(), p.Z()); + Base::Vector3d vec1 = *p2 - *p1; + Base::Vector3d vec2 = *p3 - *p1; + normal = new Base::Vector3d(vec1 % vec2); + } else { + return; + } + + *normal = normal->Normalize(); + + if (fabs(Offset.getValue()) > Precision::Confusion()) + *p1 += Offset.getValue() * *normal; + + _Base.setValue(*p1); + _Normal.setValue(*normal); + _Base.touch(); // This triggers ViewProvider::updateData() + + // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of + // Sketcher on the PartDesign module + BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(p1->x, p1->y, p1->z), gp_Dir(normal->x, normal->y, normal->z))); + if (!builder.IsDone()) + return; + Shape.setValue(builder.Shape()); + + delete p1; + delete normal; + if (p2 != NULL) delete p2; + if (p3 != NULL) delete p3; + if (line != NULL) delete line; + } + + Part::Datum::onChanged(prop); +} + + +const std::set Plane::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} diff --git a/src/Mod/PartDesign/App/DatumPlane.h b/src/Mod/PartDesign/App/DatumPlane.h new file mode 100644 index 000000000000..03e2026b3f10 --- /dev/null +++ b/src/Mod/PartDesign/App/DatumPlane.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 PARTDESIGN_DATUMPLANE_H +#define PARTDESIGN_DATUMPLANE_H + +#include +#include +#include + +namespace PartDesign +{ + +class PartDesignExport Plane : public Part::Datum +{ + PROPERTY_HEADER(PartDesign::Plane); + +public: + App::PropertyVector _Base; + App::PropertyVector _Normal; + + Plane(); + + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatumPlane"; + } + + static void initHints(); + const std::set getHint(); + +protected: + virtual void onChanged(const App::Property* prop); + +private: + // Hints on what further references are required/possible on this feature for a given set of references + static std::map, std::set > hints; +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_DATUMPLANE_H diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp new file mode 100644 index 000000000000..e9f5d338787b --- /dev/null +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -0,0 +1,331 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include +#include "DatumPoint.h" +#include "DatumLine.h" +#include "DatumPlane.h" +#include +#include +#include +#include "Mod/Part/App/PrimitiveFeature.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +using namespace PartDesign; + +// Note: We don't distinguish between e.g. datum lines and edges here +#define PLANE QObject::tr("DPLANE") +#define LINE QObject::tr("DLINE") +#define POINT QObject::tr("DPOINT") +#define ANGLE QObject::tr("Angle") + +// ================================ Initialize the hints ===================== + +std::map, std::set > Point::hints = std::map, std::set >(); + +void Point::initHints() +{ + std::set DONE; + DONE.insert(QObject::tr("Done")); + + std::multiset key; + std::set value; + key.insert(POINT); + hints[key] = DONE; // POINT -> DONE. Point from another point or vertex + + key.clear(); value.clear(); + key.insert(LINE); + value.insert(LINE); value.insert(PLANE); + hints[key] = value; // LINE -> LINE or PLANE + + key.clear(); value.clear(); + key.insert(LINE); key.insert(LINE); + hints[key] = DONE; // {LINE, LINE} -> DONE. Point from two lines or edges + + key.clear(); value.clear(); + key.insert(LINE); key.insert(PLANE); + hints[key] = DONE; // {LINE, PLANE} -> DONE. Point from line and plane + + key.clear(); value.clear(); + key.insert(PLANE); + value.insert(PLANE); value.insert(LINE); + hints[key] = value; // PLANE -> PLANE or LINE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); + value.insert(PLANE); + hints[key] = value; // {PLANE, PLANE} -> PLANE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(PLANE); key.insert(PLANE); + hints[key] = DONE; // {PLANE, PLANE, PLANE} -> DONE. Point from three planes + + key.clear(); value.clear(); + value.insert(POINT); value.insert(LINE); value.insert(PLANE); + hints[key] = value; +} + +// ============================================================================ + +PROPERTY_SOURCE(PartDesign::Point, Part::Datum) + +Point::Point() +{ + ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,0)),"DatumPoint", + App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), + "Coordinates of the datum point"); +} + +Point::~Point() +{ +} + +void Point::onChanged(const App::Property* prop) +{ + if (prop == &References) { + refTypes.clear(); + std::vector refs = References.getValues(); + std::vector refnames = References.getSubValues(); + + for (int r = 0; r < refs.size(); r++) + refTypes.insert(getRefType(refs[r], refnames[r])); + + std::set hint = getHint(); + if (!((hint.size() == 1) && (hint.find(QObject::tr("Done")) != hint.end()))) + return; // incomplete references + + // Extract the geometry of the references + Base::Vector3d* point = NULL; + Handle_Geom_Curve c1 = NULL; + Handle_Geom_Curve c2 = NULL; + Handle_Geom_Surface s1 = NULL; + Handle_Geom_Surface s2 = NULL; + Handle_Geom_Surface s3 = NULL; + + for (int i = 0; i < refs.size(); i++) { + if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* p = static_cast(refs[i]); + point = new Base::Vector3d (p->_Point.getValue()); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* l = static_cast(refs[i]); + Base::Vector3d base = l->_Base.getValue(); + Base::Vector3d dir = l->_Direction.getValue(); + if (c1.IsNull()) + c1 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); + else + c2 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); + } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* p = static_cast(refs[i]); + Base::Vector3d base = p->_Base.getValue(); + Base::Vector3d normal = p->_Normal.getValue(); + if (s1.IsNull()) + s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + else if (s2.IsNull()) + s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + else + s3 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* p = static_cast(refs[i]); + // Note: We only handle the three base planes here + gp_Pnt base(0,0,0); + gp_Dir normal; + if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) + normal = gp_Dir(0,0,1); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + normal = gp_Dir(1,0,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) + normal = gp_Dir(0,1,0); + + if (s1.IsNull()) + s1 = new Geom_Plane(base, normal); + else if (s2.IsNull()) + s2 = new Geom_Plane(base, normal); + else + s3 = new Geom_Plane(base, normal); + } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* feature = static_cast(refs[i]); + const TopoDS_Shape& sh = feature->Shape.getValue(); + if (sh.IsNull()) + return; // "PartDesign::Point: Reference has NULL shape" + // Get subshape + TopoDS_Shape subshape = feature->Shape.getShape().getSubShape(refnames[i].c_str()); + if (subshape.IsNull()) + return; // "PartDesign::Point: Reference has NULL subshape"; + + if (subshape.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v = TopoDS::Vertex(subshape); + gp_Pnt p = BRep_Tool::Pnt(v); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else if (subshape.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge e = TopoDS::Edge(subshape); + Standard_Real first, last; + if (c1.IsNull()) + c1 = BRep_Tool::Curve(e, first, last); + else + c2 = BRep_Tool::Curve(e, first, last); + } else if (subshape.ShapeType() == TopAbs_FACE) { + TopoDS_Face f = TopoDS::Face(subshape); + if (s1.IsNull()) + s1 = BRep_Tool::Surface(f); + else if (s2.IsNull()) + s2 = BRep_Tool::Surface(f); + else + s3 = BRep_Tool::Surface(f); + } + } else { + return; //"PartDesign::Point: Invalid reference type" + } + } + + if (point != NULL) { + // Point from vertex or other point. Nothing to be done + } else if (!c1.IsNull()) { + if (!c2.IsNull()) { + // Point from intersection of two curves + GeomAPI_ExtremaCurveCurve intersector(c1, c2); + if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) + return; // No intersection + // Note: We don't check for multiple intersection points + gp_Pnt p, p2; + intersector.Points(1, p, p2); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else if (!s1.IsNull()) { + GeomAPI_IntCS intersector(c1, s1); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from curve and surface"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else + return; + } else if (!s1.IsNull() && !s2.IsNull() && !s3.IsNull()) { + GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); + if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) + return; + if (intersectorSS.NbLines() > 1) + Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Handle_Geom_Curve line = intersectorSS.Line(1); + + GeomAPI_IntCS intersector(line, s3); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum point from surfaces"); + + gp_Pnt p = intersector.Point(1); + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); + } else { + return; + } + + _Point.setValue(*point); + _Point.touch(); // This triggers ViewProvider::updateData() + + // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of + // Sketcher on the PartDesign module + BRepBuilderAPI_MakeVertex builder(gp_Pnt(point->x, point->y, point->z)); + if (!builder.IsDone()) + return; + Shape.setValue(builder.Shape()); + + delete point; + } + + Part::Datum::onChanged(prop); +} + + +const std::set Point::getHint() +{ + if (hints.find(refTypes) != hints.end()) + return hints[refTypes]; + else + return std::set(); +} + +namespace PartDesign { + +const QString getRefType(const App::DocumentObject* obj, const std::string& subname) +{ + Base::Type type = obj->getTypeId(); + + if ((type == App::Plane::getClassTypeId()) || (type == PartDesign::Plane::getClassTypeId())) + return PLANE; + else if (type == PartDesign::Line::getClassTypeId()) + return LINE; + else if (type == PartDesign::Point::getClassTypeId()) + return POINT; + else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { + // Note: For now, only planar references are possible + if (subname.size() > 4 && subname.substr(0,4) == "Face") + return PLANE; + else if (subname.size() > 4 && subname.substr(0,4) == "Edge") + return LINE; + else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") + return POINT; + } + + throw Base::Exception("Part::Datum::getRefType(): Illegal object type"); +} + +} diff --git a/src/Mod/PartDesign/App/DatumPoint.h b/src/Mod/PartDesign/App/DatumPoint.h new file mode 100644 index 000000000000..e36abf1a3652 --- /dev/null +++ b/src/Mod/PartDesign/App/DatumPoint.h @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 PARTDESIGN_DATUMPOINT_H +#define PARTDESIGN_DATUMPOINT_H + +#include +#include +#include +#include + +namespace PartDesign +{ + +class PartDesignExport Point : public Part::Datum +{ + PROPERTY_HEADER(PartDesign::Point); + +public: + App::PropertyVector _Point; + + Point(); + virtual ~Point(); + + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderDatumPoint"; + } + + static void initHints(); + const std::set getHint(); + + + +protected: + virtual void onChanged(const App::Property* prop); + +private: + // Hints on what further references are required/possible on this feature for a given set of references + static std::map, std::set > hints; +}; + +// This has to be declared somewhere... a good place would be Part::Datum but since the code requires +// access to PartDesign::Point etc. that's not possible +const QString getRefType(const App::DocumentObject* obj, const std::string& subname); + +} //namespace PartDesign + + +#endif // PARTDESIGN_DATUMPOINT_H diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index 2b26c6afe922..47b6930d3ea6 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -48,7 +48,9 @@ #include "ViewProviderPolarPattern.h" #include "ViewProviderScaled.h" #include "ViewProviderMultiTransform.h" -#include "ViewProviderDatum.h" +#include "ViewProviderDatumPoint.h" +#include "ViewProviderDatumLine.h" +#include "ViewProviderDatumPlane.h" // use a different name to CreateCommand() void CreatePartDesignCommands(void); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index f3a67b09b9f3..e9f868e8d2c2 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -106,6 +106,12 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderMultiTransform.h ViewProviderDatum.cpp ViewProviderDatum.h + ViewProviderDatumPoint.cpp + ViewProviderDatumPoint.h + ViewProviderDatumLine.cpp + ViewProviderDatumLine.h + ViewProviderDatumPlane.cpp + ViewProviderDatumPlane.h ) SOURCE_GROUP("ViewProvider" FILES ${PartDesignGuiViewProvider_SRCS}) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 48178f0b4b41..e5ea1da9fb69 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -63,13 +63,15 @@ #include #include -#include #include #include #include #include #include #include +#include +#include +#include #include "FeaturePickDialog.h" #include "Workbench.h" diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 6bec9ac3992d..60b25bf12c6a 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -34,7 +34,9 @@ #include #include #include -#include +#include +#include +#include #include "ReferenceSelection.h" #include "Workbench.h" @@ -49,8 +51,8 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c // Note: It is assumed that a Part has exactly 3 App::Plane objects at the root of the feature tree return true; - if (pObj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) { - // Allow selecting PartDesign::Datum features + if (pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + // Allow selecting Part::Datum features if (!ActivePartObject->hasFeature(pObj)) return false; diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index d608c854465e..132427f93980 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include "ReferenceSelection.h" #include "Workbench.h" @@ -62,7 +62,7 @@ const QString makeRefString(const App::DocumentObject* obj, const std::string& s return QObject::tr("No reference selected"); if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || - obj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) + obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) // App::Plane or Datum feature return QString::fromAscii(obj->getNameInDocument()); @@ -81,7 +81,7 @@ const QString makeRefString(const App::DocumentObject* obj, const std::string& s } void TaskDatumParameters::makeRefStrings(std::vector& refstrings, std::vector& refnames) { - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); refnames = pcDatum->References.getSubValues(); @@ -139,7 +139,7 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p ui->lineRef3->blockSignals(true); // Get the feature data - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); //std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); @@ -203,7 +203,7 @@ void TaskDatumParameters::updateUI() ui->spinOffset->setVisible(false); } - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); completed = false; @@ -308,7 +308,7 @@ void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) return; // Note: The validity checking has already been done in ReferenceSelection.cpp - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); App::DocumentObject* selObj = pcDatum->getDocument()->getObject(msg.pObjectName); @@ -317,7 +317,7 @@ void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) // Remove subname for planes and datum features if (selObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || - selObj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) + selObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) subname = ""; // eliminate duplicate selections @@ -349,7 +349,7 @@ void TaskDatumParameters::onSelectionChanged(const Gui::SelectionChanges& msg) void TaskDatumParameters::onOffsetChanged(double val) { - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); pcDatum->Offset.setValue(val); pcDatum->getDocument()->recomputeFeature(pcDatum); updateUI(); @@ -357,7 +357,7 @@ void TaskDatumParameters::onOffsetChanged(double val) void TaskDatumParameters::onAngleChanged(double val) { - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); pcDatum->Angle.setValue(val); pcDatum->getDocument()->recomputeFeature(pcDatum); updateUI(); @@ -365,14 +365,14 @@ void TaskDatumParameters::onAngleChanged(double val) void TaskDatumParameters::onCheckFlip(bool on) { - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); //pcDatum->Reversed.setValue(on); pcDatum->getDocument()->recomputeFeature(pcDatum); } void TaskDatumParameters::onButtonRef(const bool pressed, const int idx) { - // Note: Even if there is no solid, App::Plane and PartDesign::Datum can still be selected + // Note: Even if there is no solid, App::Plane and Part::Datum can still be selected App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); if (pressed) { @@ -410,7 +410,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) if (text.length() == 0) { // Reference was removed // Update the reference list - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); std::vector newrefs; @@ -439,7 +439,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) QStringList parts = text.split(QChar::fromAscii(':')); if (parts.length() < 2) parts.push_back(QString::fromAscii("")); - // Check whether this is the name of an App::Plane or PartDesign::Datum feature + // Check whether this is the name of an App::Plane or Part::Datum feature App::DocumentObject* obj = DatumView->getObject()->getDocument()->getObject(parts[0].toAscii()); if (obj == NULL) return; @@ -448,7 +448,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { // everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) subElement = ""; - } else if (obj->getTypeId().isDerivedFrom(PartDesign::Datum::getClassTypeId())) { + } else if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { if (!PartDesignGui::ActivePartObject->hasFeature(obj)) return; subElement = ""; @@ -484,7 +484,7 @@ void TaskDatumParameters::onRefName(const QString& text, const int idx) subElement = ss.str(); } - PartDesign::Datum* pcDatum = static_cast(DatumView->getObject()); + Part::Datum* pcDatum = static_cast(DatumView->getObject()); std::vector refs = pcDatum->References.getValues(); std::vector refnames = pcDatum->References.getSubValues(); if (idx < refs.size()) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 46773c7cf0cf..badcc51766fc 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -52,7 +52,9 @@ #include "ViewProviderDatum.h" #include "TaskDatumParameters.h" #include "Workbench.h" -#include +#include +#include +#include #include #include #include @@ -77,12 +79,12 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) { ViewProviderGeometryObject::attach(obj); - PartDesign::Datum* pcDatum = static_cast(getObject()); - if (pcDatum->getTypeId() == PartDesign::Plane::getClassTypeId()) + App::DocumentObject* o = getObject(); + if (o->getTypeId() == PartDesign::Plane::getClassTypeId()) datumType = QObject::tr("Plane"); - else if (pcDatum->getTypeId() == PartDesign::Line::getClassTypeId()) + else if (o->getTypeId() == PartDesign::Line::getClassTypeId()) datumType = QObject::tr("Line"); - else if (pcDatum->getTypeId() == PartDesign::Point::getClassTypeId()) + else if (o->getTypeId() == PartDesign::Point::getClassTypeId()) datumType = QObject::tr("Point"); SoSeparator* sep = new SoSeparator(); @@ -265,274 +267,3 @@ void ViewProviderDatum::unsetEdit(int ModNum) } } -PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPoint,PartDesignGui::ViewProviderDatum) - -ViewProviderDatumPoint::ViewProviderDatumPoint() -{ - SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 0; - pShapeSep->addChild(points); -} - -ViewProviderDatumPoint::~ViewProviderDatumPoint() -{ - -} - -void ViewProviderDatumPoint::updateData(const App::Property* prop) -{ - // Gets called whenever a property of the attached object changes - PartDesign::Point* pcDatum = static_cast(this->getObject()); - - if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3d p = pcDatum->_Point.getValue(); - SoMFVec3f v; - v.setNum(1); - v.set1Value(0, p.x, p.y, p.z); - SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - - SoVertexProperty* vprop; - if (points->vertexProperty.getValue() == NULL) { - vprop = new SoVertexProperty(); - vprop->vertex = v; - points->vertexProperty = vprop; - } else { - vprop = static_cast(points->vertexProperty.getValue()); - vprop->vertex = v; - } - - points->numPoints = 1; - } - - ViewProviderDatum::updateData(prop); -} - -PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProviderDatum) - -ViewProviderDatumLine::ViewProviderDatumLine() -{ - SoMaterial* material = new SoMaterial(); - material->diffuseColor.setValue(0.9f, 0.9f, 0.13); - material->transparency.setValue(0.2); - pShapeSep->addChild(material); -} - -ViewProviderDatumLine::~ViewProviderDatumLine() -{ - -} - -void ViewProviderDatumLine::updateData(const App::Property* prop) -{ - // Gets called whenever a property of the attached object changes - PartDesign::Line* pcDatum = static_cast(this->getObject()); - - if (strcmp(prop->getName(),"_Base") == 0) { - Base::Vector3d base = pcDatum->_Base.getValue(); - Base::Vector3d dir = pcDatum->_Direction.getValue(); - - // Get limits of the line from bounding box of the body - PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); - if (body == NULL) - return; - Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); - if (tipSolid == NULL) - return; - Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); - bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); - Base::Vector3d p1, p2; - if (bbox.IsInBox(base)) { - bbox.IntersectionPoint(base, dir, p1, Precision::Confusion()); - bbox.IntersectionPoint(base, -dir, p2, Precision::Confusion()); - } else { - bbox.IntersectWithLine(base, dir, p1, p2); - if ((p1 == Base::Vector3d(0,0,0)) && (p2 == Base::Vector3d(0,0,0))) - bbox.IntersectWithLine(base, -dir, p1, p2); - } - - // Display the line - SoMFVec3f v; - v.setNum(2); - v.set1Value(0, p1.x, p1.y, p1.z); - v.set1Value(1, p2.x, p2.y, p2.z); - SoMFInt32 idx; - idx.setNum(1); - idx.set1Value(0, 2); - - SoLineSet* lineSet; - SoVertexProperty* vprop; - - if (pShapeSep->getNumChildren() == 1) { - lineSet = new SoLineSet(); - vprop = new SoVertexProperty(); - vprop->vertex = v; - lineSet->vertexProperty = vprop; - lineSet->numVertices = idx; - pShapeSep->addChild(lineSet); - } else { - lineSet = static_cast(pShapeSep->getChild(1)); - vprop = static_cast(lineSet->vertexProperty.getValue()); - vprop->vertex = v; - lineSet->numVertices = idx; - } - } - - ViewProviderDatum::updateData(prop); -} - -PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProviderDatum) - -ViewProviderDatumPlane::ViewProviderDatumPlane() -{ - SoMaterial* material = new SoMaterial(); - material->diffuseColor.setValue(0.9f, 0.9f, 0.13); - material->transparency.setValue(0.2); - pShapeSep->addChild(material); -} - -ViewProviderDatumPlane::~ViewProviderDatumPlane() -{ - -} - -void ViewProviderDatumPlane::updateData(const App::Property* prop) -{ - // Gets called whenever a property of the attached object changes - PartDesign::Plane* pcDatum = static_cast(this->getObject()); - - if (strcmp(prop->getName(),"_Base") == 0) { - Base::Vector3d base = pcDatum->_Base.getValue(); - Base::Vector3d normal = pcDatum->_Normal.getValue(); - - // Get limits of the plane from bounding box of the body - PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); - if (body == NULL) - return; - Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); - if (tipSolid == NULL) - return; - Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); - bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); - - // Calculate intersection of plane with bounding box edges - // TODO: This can be a lot more efficient if we do the maths ourselves, e.g. - // http://cococubed.asu.edu/code_pages/raybox.shtml - // http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf - Handle_Geom_Plane plane = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - std::vector points; - - for (int i = 0; i < 12; i++) { - // Get the edge of the bounding box - Base::Vector3d p1, p2; - bbox.CalcDistance(i, p1, p2); - Base::Vector3d ldir = p2 - p1; - Handle_Geom_Line line = new Geom_Line(gp_Pnt(p1.x, p1.y, p1.z), gp_Dir(ldir.x, ldir.y, ldir.z)); - GeomAPI_IntCS intersector(line, plane); - if (!intersector.IsDone() || (intersector.NbPoints() == 0)) - continue; - gp_Pnt pnt = intersector.Point(1); - Base::Vector3d point(pnt.X(), pnt.Y(), pnt.Z()); - - // Check whether intersection is on the bbox edge (bbox.IsInside() always tests false) - double edgeLength = (p1 - p2).Length(); - double l1 = (p1 - point).Length(); - double l2 = (p2 - point).Length(); - if (fabs(edgeLength - l1 - l2) > 0.001) - continue; - - // Check for duplicates - bool duplicate = false; - for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { - if ((point - *p).Sqr() < Precision::Confusion()) { - duplicate = true; - break; - } - } - if (!duplicate) - points.push_back(point); - } - - if (points.size() < 3) - return; - - // Sort the points to get a proper polygon, see http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf p.5 - if (points.size() > 3) { - // Longest component of normal vector - int longest; - if (normal.x > normal.y) - if (normal.x > normal.z) - longest = 0; // x is longest - else - longest = 2; // z is longest - else - if (normal.y > normal.z) - longest = 1; // y is longest - else - longest = 2; // z is longest - - // mean value for intersection points - Base::Vector3d m; - for (std::vector::iterator p = points.begin(); p != points.end(); p++) - m += *p; - m /= points.size(); - - // Sort by angles - double a[points.size()]; - for (int i = 0; i < points.size() - 1; i++) { - if (longest == 0) - a[i] = atan2(points[i].z - m.z, points[i].y - m.y); - else if (longest == 1) - a[i] = atan2(points[i].z - m.z, points[i].x - m.x); - else - a[i] = atan2(points[i].y - m.y, points[i].x - m.x); - - for (int k = i+1; k < points.size(); k++) { - if (longest == 0) - a[k] = atan2(points[k].z - m.z, points[k].y - m.y); - else if (longest == 1) - a[k] = atan2(points[k].z - m.z, points[k].x - m.x); - else - a[k] = atan2(points[k].y - m.y, points[k].x - m.x); - - if (a[k] < a[i]) { - Base::Vector3d temp = points[i]; - points[i] = points[k]; - points[k] = temp; - a[i] = a[k]; - } - } - } - } - - // Display the plane - SoMFVec3f v; - v.setNum(points.size()); - for (int p = 0; p < points.size(); p++) - v.set1Value(p, points[p].x, points[p].y, points[p].z); - SoMFInt32 idx; - idx.setNum(1); - idx.set1Value(0, points.size()); - - SoFaceSet* faceSet; - SoVertexProperty* vprop; - - if (pShapeSep->getNumChildren() == 1) { - faceSet = new SoFaceSet(); - vprop = new SoVertexProperty(); - vprop->vertex = v; - faceSet->vertexProperty = vprop; - faceSet->numVertices = idx; - pShapeSep->addChild(faceSet); - } else { - faceSet = static_cast(pShapeSep->getChild(1)); - vprop = static_cast(faceSet->vertexProperty.getValue()); - vprop->vertex = v; - faceSet->numVertices = idx; - } - } - - ViewProviderDatum::updateData(prop); -} - - diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.h b/src/Mod/PartDesign/Gui/ViewProviderDatum.h index b2ef4f5b262a..c73c2183a336 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.h @@ -69,46 +69,6 @@ class PartDesignGuiExport ViewProviderDatum : public Gui::ViewProviderGeometryOb }; -class PartDesignGuiExport ViewProviderDatumPoint : public PartDesignGui::ViewProviderDatum -{ - PROPERTY_HEADER(PartDesignGui::ViewProviderDatumPoint); - -public: - /// Constructor - ViewProviderDatumPoint(); - virtual ~ViewProviderDatumPoint(); - - virtual void updateData(const App::Property*); - -}; - -class PartDesignGuiExport ViewProviderDatumLine : public PartDesignGui::ViewProviderDatum -{ - PROPERTY_HEADER(PartDesignGui::ViewProviderDatumLine); - -public: - /// Constructor - ViewProviderDatumLine(); - virtual ~ViewProviderDatumLine(); - - virtual void updateData(const App::Property*); - -}; - -class PartDesignGuiExport ViewProviderDatumPlane : public PartDesignGui::ViewProviderDatum -{ - PROPERTY_HEADER(PartDesignGui::ViewProviderDatumPlane); - -public: - /// Constructor - ViewProviderDatumPlane(); - virtual ~ViewProviderDatumPlane(); - - virtual void updateData(const App::Property*); - -}; - - } // namespace PartDesignGui diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp new file mode 100644 index 000000000000..00630a5e464b --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ViewProviderDatumLine.h" +#include "TaskDatumParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProviderDatum) + +ViewProviderDatumLine::ViewProviderDatumLine() +{ + SoMaterial* material = new SoMaterial(); + material->diffuseColor.setValue(0.9f, 0.9f, 0.13); + material->transparency.setValue(0.2); + pShapeSep->addChild(material); +} + +ViewProviderDatumLine::~ViewProviderDatumLine() +{ + +} + +void ViewProviderDatumLine::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + PartDesign::Line* pcDatum = static_cast(this->getObject()); + + if (strcmp(prop->getName(),"_Base") == 0) { + Base::Vector3d base = pcDatum->_Base.getValue(); + Base::Vector3d dir = pcDatum->_Direction.getValue(); + + // Get limits of the line from bounding box of the body + PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + if (body == NULL) + return; + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + return; + Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + Base::Vector3d p1, p2; + if (bbox.IsInBox(base)) { + bbox.IntersectionPoint(base, dir, p1, Precision::Confusion()); + bbox.IntersectionPoint(base, -dir, p2, Precision::Confusion()); + } else { + bbox.IntersectWithLine(base, dir, p1, p2); + if ((p1 == Base::Vector3d(0,0,0)) && (p2 == Base::Vector3d(0,0,0))) + bbox.IntersectWithLine(base, -dir, p1, p2); + } + + // Display the line + SoMFVec3f v; + v.setNum(2); + v.set1Value(0, p1.x, p1.y, p1.z); + v.set1Value(1, p2.x, p2.y, p2.z); + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, 2); + + SoLineSet* lineSet; + SoVertexProperty* vprop; + + if (pShapeSep->getNumChildren() == 1) { + lineSet = new SoLineSet(); + vprop = new SoVertexProperty(); + vprop->vertex = v; + lineSet->vertexProperty = vprop; + lineSet->numVertices = idx; + pShapeSep->addChild(lineSet); + } else { + lineSet = static_cast(pShapeSep->getChild(1)); + vprop = static_cast(lineSet->vertexProperty.getValue()); + vprop->vertex = v; + lineSet->numVertices = idx; + } + } + + ViewProviderDatum::updateData(prop); +} + diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.h b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.h new file mode 100644 index 000000000000..60e7fb2fee76 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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_ViewProviderDatumLine_H +#define PARTGUI_ViewProviderDatumLine_H + +#include "Gui/ViewProviderGeometryObject.h" +#include "ViewProviderDatum.h" + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderDatumLine : public PartDesignGui::ViewProviderDatum +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatumLine); + +public: + /// Constructor + ViewProviderDatumLine(); + virtual ~ViewProviderDatumLine(); + + virtual void updateData(const App::Property*); + +}; + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderDatumLine_H diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp new file mode 100644 index 000000000000..2265c72dbfa6 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ViewProviderDatumPlane.h" +#include "TaskDatumParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProviderDatum) + +ViewProviderDatumPlane::ViewProviderDatumPlane() +{ + SoMaterial* material = new SoMaterial(); + material->diffuseColor.setValue(0.9f, 0.9f, 0.13); + material->transparency.setValue(0.2); + pShapeSep->addChild(material); +} + +ViewProviderDatumPlane::~ViewProviderDatumPlane() +{ + +} + +void ViewProviderDatumPlane::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + PartDesign::Plane* pcDatum = static_cast(this->getObject()); + + if (strcmp(prop->getName(),"_Base") == 0) { + Base::Vector3d base = pcDatum->_Base.getValue(); + Base::Vector3d normal = pcDatum->_Normal.getValue(); + + // Get limits of the plane from bounding box of the body + PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + if (body == NULL) + return; + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + return; + Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + + // Calculate intersection of plane with bounding box edges + // TODO: This can be a lot more efficient if we do the maths ourselves, e.g. + // http://cococubed.asu.edu/code_pages/raybox.shtml + // http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf + Handle_Geom_Plane plane = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + std::vector points; + + for (int i = 0; i < 12; i++) { + // Get the edge of the bounding box + Base::Vector3d p1, p2; + bbox.CalcEdge(i, p1, p2); + Base::Vector3d ldir = p2 - p1; + Handle_Geom_Line line = new Geom_Line(gp_Pnt(p1.x, p1.y, p1.z), gp_Dir(ldir.x, ldir.y, ldir.z)); + GeomAPI_IntCS intersector(line, plane); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + continue; + gp_Pnt pnt = intersector.Point(1); + Base::Vector3d point(pnt.X(), pnt.Y(), pnt.Z()); + + // Check whether intersection is on the bbox edge (bbox.IsInside() always tests false) + double edgeLength = (p1 - p2).Length(); + double l1 = (p1 - point).Length(); + double l2 = (p2 - point).Length(); + if (fabs(edgeLength - l1 - l2) > 0.001) + continue; + + // Check for duplicates + bool duplicate = false; + for (std::vector::const_iterator p = points.begin(); p != points.end(); p++) { + if ((point - *p).Sqr() < Precision::Confusion()) { + duplicate = true; + break; + } + } + if (!duplicate) + points.push_back(point); + } + + if (points.size() < 3) + return; + + // Sort the points to get a proper polygon, see http://www.fho-emden.de/~hoffmann/cubeplane12112006.pdf p.5 + if (points.size() > 3) { + // Longest component of normal vector + int longest; + if (normal.x > normal.y) + if (normal.x > normal.z) + longest = 0; // x is longest + else + longest = 2; // z is longest + else + if (normal.y > normal.z) + longest = 1; // y is longest + else + longest = 2; // z is longest + + // mean value for intersection points + Base::Vector3d m; + for (std::vector::iterator p = points.begin(); p != points.end(); p++) + m += *p; + m /= points.size(); + + // Sort by angles + double a[points.size()]; + for (int i = 0; i < points.size() - 1; i++) { + if (longest == 0) + a[i] = atan2(points[i].z - m.z, points[i].y - m.y); + else if (longest == 1) + a[i] = atan2(points[i].z - m.z, points[i].x - m.x); + else + a[i] = atan2(points[i].y - m.y, points[i].x - m.x); + + for (int k = i+1; k < points.size(); k++) { + if (longest == 0) + a[k] = atan2(points[k].z - m.z, points[k].y - m.y); + else if (longest == 1) + a[k] = atan2(points[k].z - m.z, points[k].x - m.x); + else + a[k] = atan2(points[k].y - m.y, points[k].x - m.x); + + if (a[k] < a[i]) { + Base::Vector3d temp = points[i]; + points[i] = points[k]; + points[k] = temp; + a[i] = a[k]; + } + } + } + } + + // Display the plane + SoMFVec3f v; + v.setNum(points.size()); + for (int p = 0; p < points.size(); p++) + v.set1Value(p, points[p].x, points[p].y, points[p].z); + SoMFInt32 idx; + idx.setNum(1); + idx.set1Value(0, points.size()); + + SoFaceSet* faceSet; + SoLineSet* lineSet; + SoVertexProperty* vprop; + + if (pShapeSep->getNumChildren() == 1) { + faceSet = new SoFaceSet(); + vprop = new SoVertexProperty(); + vprop->vertex = v; + faceSet->vertexProperty = vprop; + faceSet->numVertices = idx; + pShapeSep->addChild(faceSet); + lineSet = new SoLineSet(); + lineSet->vertexProperty = vprop; + lineSet->numVertices = idx; + pShapeSep->addChild(lineSet); + } else { + faceSet = static_cast(pShapeSep->getChild(1)); + vprop = static_cast(faceSet->vertexProperty.getValue()); + vprop->vertex = v; + faceSet->numVertices = idx; + lineSet = static_cast(pShapeSep->getChild(2)); + vprop = static_cast(lineSet->vertexProperty.getValue()); + vprop->vertex = v; + lineSet->numVertices = idx; + } + } + + ViewProviderDatum::updateData(prop); +} + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.h b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.h new file mode 100644 index 000000000000..53c23ecb5354 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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_ViewProviderDatumPlane_H +#define PARTGUI_ViewProviderDatumPlane_H + +#include "Gui/ViewProviderGeometryObject.h" +#include "ViewProviderDatum.h" + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderDatumPlane : public PartDesignGui::ViewProviderDatum +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatumPlane); + +public: + /// Constructor + ViewProviderDatumPlane(); + virtual ~ViewProviderDatumPlane(); + + virtual void updateData(const App::Property*); + +}; + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderDatumPlane_H diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp new file mode 100644 index 000000000000..2ec1fe8ff817 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "ViewProviderDatumPoint.h" +#include "TaskDatumParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPoint,PartDesignGui::ViewProviderDatum) + +ViewProviderDatumPoint::ViewProviderDatumPoint() +{ + SoMarkerSet* points = new SoMarkerSet(); + points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; + points->numPoints = 0; + pShapeSep->addChild(points); +} + +ViewProviderDatumPoint::~ViewProviderDatumPoint() +{ + +} + +void ViewProviderDatumPoint::updateData(const App::Property* prop) +{ + // Gets called whenever a property of the attached object changes + PartDesign::Point* pcDatum = static_cast(this->getObject()); + + if (strcmp(prop->getName(),"_Point") == 0) { + Base::Vector3d p = pcDatum->_Point.getValue(); + SoMFVec3f v; + v.setNum(1); + v.set1Value(0, p.x, p.y, p.z); + SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); + + SoVertexProperty* vprop; + if (points->vertexProperty.getValue() == NULL) { + vprop = new SoVertexProperty(); + vprop->vertex = v; + points->vertexProperty = vprop; + } else { + vprop = static_cast(points->vertexProperty.getValue()); + vprop->vertex = v; + } + + points->numPoints = 1; + } + + ViewProviderDatum::updateData(prop); +} diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.h b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.h new file mode 100644 index 000000000000..68edadeca24d --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.h @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinlaender * + * * + * 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_ViewProviderDatumPoint_H +#define PARTGUI_ViewProviderDatumPoint_H + +#include "Gui/ViewProviderGeometryObject.h" +#include "ViewProviderDatum.h" + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderDatumPoint : public PartDesignGui::ViewProviderDatum +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDatumPoint); + +public: + /// Constructor + ViewProviderDatumPoint(); + virtual ~ViewProviderDatumPoint(); + + virtual void updateData(const App::Property*); + +}; + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderDatumPoint_H diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index bdba81f42fa4..02f278c780f9 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include using namespace PartDesignGui; @@ -262,7 +262,7 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con if (strcmp(recipient,"Tree") == 0) { if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + - Gui::Selection().countObjectsOfType(PartDesign::Datum::getClassTypeId()) + + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveTip"; } diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 7e75f2a34b11..318d2e044ecf 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +# include # include # include # include @@ -34,6 +35,7 @@ # include # include # include +# include # include # include # include @@ -41,6 +43,9 @@ # include # include # include +# include +# include +# include # include # include # include @@ -56,8 +61,10 @@ #include #include +#include + #include -#include +#include #include "SketchObject.h" #include "SketchObjectPy.h" @@ -119,15 +126,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) if (support == NULL) throw Base::Exception("Sketch support has been deleted"); - if (support->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { - // We don't want to handle this case in Part::Part2DObject because then Part would depend on PartDesign - PartDesign::Plane* plane = static_cast(support); - Base::Vector3d pos = plane->_Base.getValue(); - Base::Vector3d normal = plane->_Normal.getValue(); - this->Placement.setValue(Base::Placement(pos, Base::Rotation(Base::Vector3d(0,0,1), normal))); - } else { - this->positionBySupport(); - } + this->positionBySupport(); } catch (const Base::Exception& e) { return new App::DocumentObjectExecReturn(e.what()); @@ -2713,8 +2712,10 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) { - // so far only externals to the support of the sketch + // so far only externals to the support of the sketch and datum features if (Support.getValue() != Obj) + if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) && + !Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) return -1; // get the actual lists of the externals @@ -2889,6 +2890,56 @@ const Part::Geometry* SketchObject::getGeometry(int GeoId) const return 0; } +// Auxiliary method +Part::Geometry* projectLine(const BRepAdaptor_Curve& curve, const Handle(Geom_Plane)& gPlane, const Base::Placement& invPlm) +{ + double first = curve.FirstParameter(); + bool infinite = false; + if (fabs(first) > 1E99) { + // TODO: What is OCE's definition of Infinite? + // TODO: The clean way to do this is to handle a new sketch geometry Geom::Line + // but its a lot of work to implement... + first = -10000; + //infinite = true; + } + double last = curve.LastParameter(); + if (fabs(last) > 1E99) { + last = +10000; + //infinite = true; + } + + gp_Pnt P1 = curve.Value(first); + gp_Pnt P2 = curve.Value(last); + + GeomAPI_ProjectPointOnSurf proj1(P1,gPlane); + P1 = proj1.NearestPoint(); + GeomAPI_ProjectPointOnSurf proj2(P2,gPlane); + P2 = proj2.NearestPoint(); + + Base::Vector3d p1(P1.X(),P1.Y(),P1.Z()); + Base::Vector3d p2(P2.X(),P2.Y(),P2.Z()); + invPlm.multVec(p1,p1); + invPlm.multVec(p2,p2); + + if (Base::Distance(p1,p2) < Precision::Confusion()) { + Base::Vector3d p = (p1 + p2) / 2; + Part::GeomPoint* point = new Part::GeomPoint(p); + point->Construction = true; + return point; + } + else if (!infinite) { + Part::GeomLineSegment* line = new Part::GeomLineSegment(); + line->setPoints(p1,p2); + line->Construction = true; + return line; + } else { + Part::GeomLine* line = new Part::GeomLine(); + line->setLine(p1, p2 - p1); + line->Construction = true; + return line; + } +} + bool SketchObject::evaluateSupport(void) { // returns false if the shape if broken, null or non-planar @@ -3028,18 +3079,39 @@ void SketchObject::rebuildExternalGeometry(void) ExternalGeo.push_back(VLine); for (int i=0; i < int(Objects.size()); i++) { const App::DocumentObject *Obj=Objects[i]; - const std::string SubElement=SubElements[i]; - - const Part::Feature *refObj=static_cast(Obj); - const Part::TopoShape& refShape=refObj->Shape.getShape(); + const std::string SubElement=SubElements[i]; TopoDS_Shape refSubShape; - try { - refSubShape = refShape.getSubShape(SubElement.c_str()); - } - catch (Standard_Failure) { - Handle_Standard_Failure e = Standard_Failure::Caught(); - throw Base::Exception(e->GetMessageString()); + + if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + const Part::Datum* datum = static_cast(Obj); + refSubShape = datum->Shape.getValue(); + } else if (Obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + try { + const Part::Feature *refObj=static_cast(Obj); + const Part::TopoShape& refShape=refObj->Shape.getShape(); + refSubShape = refShape.getSubShape(SubElement.c_str()); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } + } else if (Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + const App::Plane* pl = static_cast(Obj); + Base::Placement plm = pl->Placement.getValue(); + Base::Vector3d base = plm.getPosition(); + Base::Rotation rot = plm.getRotation(); + Base::Vector3d normal(0,0,1); + rot.multVec(normal, normal); + gp_Pln plane(gp_Pnt(base.x,base.y,base.z), gp_Dir(normal.x, normal.y, normal.z)); + BRepBuilderAPI_MakeFace fBuilder(plane); + if (!fBuilder.IsDone()) + throw Base::Exception("Sketcher: addExternal(): Failed to build face from App::Plane"); + + TopoDS_Face f = TopoDS::Face(fBuilder.Shape()); + refSubShape = f; + } else { + throw Base::Exception("Datum feature type is not yet supported as external geometry for a sketch"); } switch (refSubShape.ShapeType()) @@ -3049,8 +3121,27 @@ void SketchObject::rebuildExternalGeometry(void) const TopoDS_Face& face = TopoDS::Face(refSubShape); BRepAdaptor_Surface surface(face); if (surface.GetType() == GeomAbs_Plane) { + // Check that the plane is perpendicular to the sketch plane + Geom_Plane plane = surface.Plane(); + gp_Dir dnormal = plane.Axis().Direction(); + gp_Dir snormal = sketchPlane.Axis().Direction(); + if (fabs(dnormal.Angle(snormal) - M_PI_2) < Precision::Confusion()) { + // Get vector that is normal to both sketch plane normal and plane normal. This is the line's direction + gp_Dir lnormal = dnormal.Crossed(snormal); + BRepBuilderAPI_MakeEdge builder(gp_Lin(plane.Location(), lnormal)); + builder.Build(); + if (builder.IsDone()) { + const TopoDS_Edge& edge = TopoDS::Edge(builder.Shape()); + BRepAdaptor_Curve curve(edge); + if (curve.GetType() == GeomAbs_Line) { + ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); + } + } + + } + } else { + throw Base::Exception("Non-planar faces are not yet supported for external geometry of sketches"); } - throw Base::Exception("Faces are not yet supported for external geometry of sketches"); } break; case TopAbs_EDGE: @@ -3058,31 +3149,7 @@ void SketchObject::rebuildExternalGeometry(void) const TopoDS_Edge& edge = TopoDS::Edge(refSubShape); BRepAdaptor_Curve curve(edge); if (curve.GetType() == GeomAbs_Line) { - gp_Pnt P1 = curve.Value(curve.FirstParameter()); - gp_Pnt P2 = curve.Value(curve.LastParameter()); - - GeomAPI_ProjectPointOnSurf proj1(P1,gPlane); - P1 = proj1.NearestPoint(); - GeomAPI_ProjectPointOnSurf proj2(P2,gPlane); - P2 = proj2.NearestPoint(); - - Base::Vector3d p1(P1.X(),P1.Y(),P1.Z()); - Base::Vector3d p2(P2.X(),P2.Y(),P2.Z()); - invPlm.multVec(p1,p1); - invPlm.multVec(p2,p2); - - if (Base::Distance(p1,p2) < Precision::Confusion()) { - Base::Vector3d p = (p1 + p2) / 2; - Part::GeomPoint* point = new Part::GeomPoint(p); - point->Construction = true; - ExternalGeo.push_back(point); - } - else { - Part::GeomLineSegment* line = new Part::GeomLineSegment(); - line->setPoints(p1,p2); - line->Construction = true; - ExternalGeo.push_back(line); - } + ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); } else if (curve.GetType() == GeomAbs_Circle) { gp_Dir vec1 = sketchPlane.Axis().Direction(); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp.orig b/src/Mod/Sketcher/App/SketchObject.cpp.orig new file mode 100644 index 000000000000..b3180b83aa36 --- /dev/null +++ b/src/Mod/Sketcher/App/SketchObject.cpp.orig @@ -0,0 +1,4180 @@ +/*************************************************************************** +<<<<<<< ef369d31e9c7931d6b64b7c59697c263887085f8 + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2008 * +======= + * Copyright (c) Juergen Riegel (juergen.riegel@web.de) 2008 * +>>>>>>> Moved generic Datum class to Part module to avoid Sketcher dependency on PartDesign + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif // #ifndef _PreComp_ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "SketchObject.h" +#include "SketchObjectPy.h" +#include "Sketch.h" + +using namespace Sketcher; +using namespace Base; + + +PROPERTY_SOURCE(Sketcher::SketchObject, Part::Part2DObject) + + +SketchObject::SketchObject() +{ + ADD_PROPERTY_TYPE(Geometry, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch geometry"); + ADD_PROPERTY_TYPE(Constraints, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch constraints"); + ADD_PROPERTY_TYPE(ExternalGeometry,(0,0),"Sketch",(App::PropertyType)(App::Prop_None),"Sketch external geometry"); + + for (std::vector::iterator it=ExternalGeo.begin(); it != ExternalGeo.end(); ++it) + if (*it) delete *it; + ExternalGeo.clear(); + Part::GeomLineSegment *HLine = new Part::GeomLineSegment(); + Part::GeomLineSegment *VLine = new Part::GeomLineSegment(); + HLine->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)); + VLine->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(0,1,0)); + HLine->Construction = true; + VLine->Construction = true; + ExternalGeo.push_back(HLine); + ExternalGeo.push_back(VLine); + rebuildVertexIndex(); + + lastDoF=0; + lastHasConflict=false; + lastHasRedundancies=false; + lastSolverStatus=0; + lastSolveTime=0; + + solverNeedsUpdate=false; + + noRecomputes=false; + + ExpressionEngine.setValidator(boost::bind(&Sketcher::SketchObject::validateExpression, this, _1, _2)); + + constraintsRemovedConn = Constraints.signalConstraintsRemoved.connect(boost::bind(&Sketcher::SketchObject::constraintsRemoved, this, _1)); + constraintsRenamedConn = Constraints.signalConstraintsRenamed.connect(boost::bind(&Sketcher::SketchObject::constraintsRenamed, this, _1)); +} + +SketchObject::~SketchObject() +{ + for (std::vector::iterator it=ExternalGeo.begin(); it != ExternalGeo.end(); ++it) + if (*it) delete *it; + ExternalGeo.clear(); +} + +App::DocumentObjectExecReturn *SketchObject::execute(void) +{ + try { + App::DocumentObject* support = Support.getValue(); + if (support == NULL) + throw Base::Exception("Sketch support has been deleted"); + + this->positionBySupport(); + } + catch (const Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } + + // setup and diagnose the sketch + try { + rebuildExternalGeometry(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\nClear constraints to external geometry\n", e.what()); + // we cannot trust the constraints of external geometries, so remove them + delConstraintsToExternal(); + } + + // We should have an updated Sketcher geometry or this execute should not have happened + // therefore we update our sketch object geometry with the SketchObject one. + // + // set up a sketch (including dofs counting and diagnosing of conflicts) + lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + getExternalGeometryCount()); + lastHasConflict = solvedSketch.hasConflicts(); + lastHasRedundancies = solvedSketch.hasRedundancies(); + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant(); + + lastSolveTime=0.0; + lastSolverStatus=GCS::Failed; // Failure is default for notifying the user unless otherwise proven + + solverNeedsUpdate=false; + + if (lastDoF < 0) { // over-constrained sketch + std::string msg="Over-constrained sketch\n"; + appendConflictMsg(lastConflicting, msg); + return new App::DocumentObjectExecReturn(msg.c_str(),this); + } + if (lastHasConflict) { // conflicting constraints + std::string msg="Sketch with conflicting constraints\n"; + appendConflictMsg(lastConflicting, msg); + return new App::DocumentObjectExecReturn(msg.c_str(),this); + } + if (lastHasRedundancies) { // redundant constraints + std::string msg="Sketch with redundant constraints\n"; + appendRedundantMsg(lastRedundant, msg); + return new App::DocumentObjectExecReturn(msg.c_str(),this); + } + // solve the sketch + lastSolverStatus=solvedSketch.solve(); + lastSolveTime=solvedSketch.SolveTime; + + if (lastSolverStatus != 0) + return new App::DocumentObjectExecReturn("Solving the sketch failed",this); + + std::vector geomlist = solvedSketch.extractGeometry(); + Geometry.setValues(geomlist); + for (std::vector::iterator it=geomlist.begin(); it != geomlist.end(); ++it) + if (*it) delete *it; + + // this is not necessary for sketch representation in edit mode, unless we want to trigger an update of + // the objects that depend on this sketch (like pads) + Shape.setValue(solvedSketch.toShape()); + + return App::DocumentObject::StdReturn; +} + +int SketchObject::hasConflicts(void) const +{ + if (lastDoF < 0) // over-constrained sketch + return -2; + if (solvedSketch.hasConflicts()) // conflicting constraints + return -1; + + return 0; +} + +int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) +{ + // if updateGeoAfterSolving=false, the solver information is updated, but the Sketch is nothing + // updated. It is useful to avoid triggering an OnChange when the goeometry did not change but + // the solver needs to be updated. + + // We should have an updated Sketcher geometry or this solver should not have happened + // therefore we update our sketch object geometry with the SketchObject one. + // + // set up a sketch (including dofs counting and diagnosing of conflicts) + lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + getExternalGeometryCount()); + + solverNeedsUpdate=false; + + lastHasConflict = solvedSketch.hasConflicts(); + + int err=0; + if (lastDoF < 0) { // over-constrained sketch + err = -3; + // if lastDoF<0, then an over-constrained situation has ensued. + // Geometry is not to be updated, as geometry can not follow the constraints. + // However, solver information must be updated. + this->Constraints.touch(); + } + else if (lastHasConflict) { // conflicting constraints + err = -3; + } + else { + lastSolverStatus=solvedSketch.solve(); + if (lastSolverStatus != 0){ // solving + err = -2; + // if solver failed, geometry was never updated, but invalid constraints were likely added before + // solving (see solve in addConstraint), so solver information is definitely invalid. + this->Constraints.touch(); + + } + + } + + lastHasRedundancies = solvedSketch.hasRedundancies(); + + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant(); + lastSolveTime=solvedSketch.SolveTime; + + if (err == 0 && updateGeoAfterSolving) { + // set the newly solved geometry + std::vector geomlist = solvedSketch.extractGeometry(); + Geometry.setValues(geomlist); + for (std::vector::iterator it = geomlist.begin(); it != geomlist.end(); ++it) + if (*it) delete *it; + } + + return err; +} + +int SketchObject::setDatum(int ConstrId, double Datum) +{ + // set the changed value for the constraint + const std::vector &vals = this->Constraints.getValues(); + if (ConstrId < 0 || ConstrId >= int(vals.size())) + return -1; + ConstraintType type = vals[ConstrId]->Type; + if (type != Distance && + type != DistanceX && + type != DistanceY && + type != Radius && + type != Angle && + type != Tangent && //for tangent, value==0 is autodecide, value==Pi/2 is external and value==-Pi/2 is internal + type != Perpendicular && + type != SnellsLaw) + return -1; + + if ((type == Distance || type == Radius) && Datum <= 0) + return (Datum == 0) ? -5 : -4; + + // copy the list + std::vector newVals(vals); + // clone the changed Constraint + Constraint *constNew = vals[ConstrId]->clone(); + constNew->setValue(Datum); + newVals[ConstrId] = constNew; + this->Constraints.setValues(newVals); + delete constNew; + + int err = solve(); + if (err) + this->Constraints.setValues(vals); + + return err; +} + +int SketchObject::setDriving(int ConstrId, bool isdriving) +{ + const std::vector &vals = this->Constraints.getValues(); + + if (ConstrId < 0 || ConstrId >= int(vals.size())) + return -1; + + ConstraintType type = vals[ConstrId]->Type; + + if (type != Distance && + type != DistanceX && + type != DistanceY && + type != Radius && + type != Angle && + type != SnellsLaw) + return -2; + + if (!(vals[ConstrId]->First>=0 || vals[ConstrId]->Second>=0 || vals[ConstrId]->Third>=0) && isdriving==true) + return -3; // a constraint that does not have at least one element as not-external-geometry can never be driving. + + // copy the list + std::vector newVals(vals); + // clone the changed Constraint + Constraint *constNew = vals[ConstrId]->clone(); + constNew->isDriving = isdriving; + newVals[ConstrId] = constNew; + this->Constraints.setValues(newVals); + if (isdriving) + setExpression(Constraints.createPath(ConstrId), boost::shared_ptr()); + delete constNew; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; +} + +int SketchObject::getDriving(int ConstrId, bool &isdriving) +{ + const std::vector &vals = this->Constraints.getValues(); + + if (ConstrId < 0 || ConstrId >= int(vals.size())) + return -1; + + ConstraintType type = vals[ConstrId]->Type; + + if (type != Distance && + type != DistanceX && + type != DistanceY && + type != Radius && + type != Angle && + type != SnellsLaw) + return -1; + + isdriving=vals[ConstrId]->isDriving; + return 0; +} + +int SketchObject::toggleDriving(int ConstrId) +{ + const std::vector &vals = this->Constraints.getValues(); + + if (ConstrId < 0 || ConstrId >= int(vals.size())) + return -1; + + ConstraintType type = vals[ConstrId]->Type; + + if (type != Distance && + type != DistanceX && + type != DistanceY && + type != Radius && + type != Angle && + type != SnellsLaw) + return -2; + + if (!(vals[ConstrId]->First>=0 || vals[ConstrId]->Second>=0 || vals[ConstrId]->Third>=0) && vals[ConstrId]->isDriving==false) + return -3; // a constraint that does not have at least one element as not-external-geometry can never be driving. + + // copy the list + std::vector newVals(vals); + // clone the changed Constraint + Constraint *constNew = vals[ConstrId]->clone(); + constNew->isDriving = !constNew->isDriving; + newVals[ConstrId] = constNew; + this->Constraints.setValues(newVals); + if (constNew->isDriving) + setExpression(Constraints.createPath(ConstrId), boost::shared_ptr()); + delete constNew; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; +} + +int SketchObject::setUpSketch() +{ + return solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + getExternalGeometryCount()); +} + +int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toPoint, bool relative, bool updateGeoBeforeMoving) +{ + // if we are moving a point at SketchObject level, we need to start from a solved sketch + // if we have conflicts we can forget about moving. However, there is the possibility that we + // need to do programatically moves of new geometry that has not been solved yet and that because + // they were programmetically generated won't generate a conflict. This is the case of Fillet for + // example. This is why exceptionally, it may be required to update the sketch geometry to that of + // of SketchObject upon moving. => use updateGeometry parameter = true then + + + if(updateGeoBeforeMoving || solverNeedsUpdate) { + lastDoF = solvedSketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), + getExternalGeometryCount()); + + lastHasConflict = solvedSketch.hasConflicts(); + lastHasRedundancies = solvedSketch.hasRedundancies(); + lastConflicting=solvedSketch.getConflicting(); + lastRedundant=solvedSketch.getRedundant(); + + solverNeedsUpdate=false; + } + + if (lastDoF < 0) // over-constrained sketch + return -1; + if (lastHasConflict) // conflicting constraints + return -1; + + // move the point and solve + lastSolverStatus = solvedSketch.movePoint(GeoId, PosId, toPoint, relative); + + // moving the point can not result in a conflict that we did not have + // or a redundancy that we did not have before, or a change of DoF + + if (lastSolverStatus == 0) { + std::vector geomlist = solvedSketch.extractGeometry(); + Geometry.setValues(geomlist); + //Constraints.acceptGeometry(getCompleteGeometry()); + for (std::vector::iterator it=geomlist.begin(); it != geomlist.end(); ++it) { + if (*it) delete *it; + } + } + + return lastSolverStatus; +} + +Base::Vector3d SketchObject::getPoint(int GeoId, PointPos PosId) const +{ + if(!(GeoId == H_Axis || GeoId == V_Axis + || (GeoId <= getHighestCurveIndex() && GeoId >= -getExternalGeometryCount()) )) + throw Base::Exception("SketchObject::getPoint. Invalid GeoId was supplied."); + const Part::Geometry *geo = getGeometry(GeoId); + if (geo->getTypeId() == Part::GeomPoint::getClassTypeId()) { + const Part::GeomPoint *p = dynamic_cast(geo); + if (PosId == start || PosId == mid || PosId == end) + return p->getPoint(); + } else if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg = dynamic_cast(geo); + if (PosId == start) + return lineSeg->getStartPoint(); + else if (PosId == end) + return lineSeg->getEndPoint(); + } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle *circle = dynamic_cast(geo); + if (PosId == mid) + return circle->getCenter(); + } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + const Part::GeomEllipse *ellipse = dynamic_cast(geo); + if (PosId == mid) + return ellipse->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *aoc = dynamic_cast(geo); + if (PosId == start) + return aoc->getStartPoint(/*emulateCCW=*/true); + else if (PosId == end) + return aoc->getEndPoint(/*emulateCCW=*/true); + else if (PosId == mid) + return aoc->getCenter(); + } else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoc = dynamic_cast(geo); + if (PosId == start) + return aoc->getStartPoint(/*emulateCCW=*/true); + else if (PosId == end) + return aoc->getEndPoint(/*emulateCCW=*/true); + else if (PosId == mid) + return aoc->getCenter(); + } + + return Base::Vector3d(); +} + +int SketchObject::getAxisCount(void) const +{ + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + + int count=0; + for (std::vector::const_iterator geo=vals.begin(); + geo != vals.end(); geo++) + if ((*geo) && (*geo)->Construction && + (*geo)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) + count++; + + return count; +} + +Base::Axis SketchObject::getAxis(int axId) const +{ + if (axId == H_Axis || axId == V_Axis || axId == N_Axis) + return Part::Part2DObject::getAxis(axId); + + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + int count=0; + for (std::vector::const_iterator geo=vals.begin(); + geo != vals.end(); geo++) + if ((*geo) && (*geo)->Construction && + (*geo)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + if (count == axId) { + Part::GeomLineSegment *lineSeg = dynamic_cast(*geo); + Base::Vector3d start = lineSeg->getStartPoint(); + Base::Vector3d end = lineSeg->getEndPoint(); + return Base::Axis(start, end-start); + } + count++; + } + + return Base::Axis(); +} + +void SketchObject::acceptGeometry() +{ + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); +} + +bool SketchObject::isSupportedGeometry(const Part::Geometry *geo) const +{ + if (geo->getTypeId() == Part::GeomPoint::getClassTypeId() || + geo->getTypeId() == Part::GeomCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId() || + geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + return true; + } + if (geo->getTypeId() == Part::GeomTrimmedCurve::getClassTypeId()) { + Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast(geo->handle()); + Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(trim->BasisCurve()); + Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(trim->BasisCurve()); + if (!circle.IsNull() || !ellipse.IsNull()) { + return true; + } + } + return false; +} + +std::vector SketchObject::supportedGeometry(const std::vector &geoList) const +{ + std::vector supportedGeoList; + supportedGeoList.reserve(geoList.size()); + // read-in geometry that the sketcher cannot handle + for (std::vector::const_iterator it = geoList.begin(); it != geoList.end(); ++it) { + if (isSupportedGeometry(*it)) { + supportedGeoList.push_back(*it); + } + } + + return supportedGeoList; +} + +int SketchObject::addGeometry(const std::vector &geoList, bool construction/*=false*/) +{ + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + + std::vector< Part::Geometry * > newVals(vals); + for (std::vector::const_iterator it = geoList.begin(); it != geoList.end(); ++it) { + if(construction && (*it)->getTypeId() != Part::GeomPoint::getClassTypeId()) + const_cast(*it)->Construction = construction; + + newVals.push_back(*it); + } + Geometry.setValues(newVals); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + + return Geometry.getSize()-1; +} + +int SketchObject::addGeometry(const Part::Geometry *geo, bool construction/*=false*/) +{ + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + + std::vector< Part::Geometry * > newVals(vals); + Part::Geometry *geoNew = geo->clone(); + + if(geoNew->getTypeId() != Part::GeomPoint::getClassTypeId()) + geoNew->Construction = construction; + + newVals.push_back(geoNew); + Geometry.setValues(newVals); + Constraints.acceptGeometry(getCompleteGeometry()); + delete geoNew; + rebuildVertexIndex(); + + return Geometry.getSize()-1; +} + +int SketchObject::delGeometry(int GeoId) +{ + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + if (GeoId < 0 || GeoId >= int(vals.size())) + return -1; + + this->DeleteUnusedInternalGeometry(GeoId); + + std::vector< Part::Geometry * > newVals(vals); + newVals.erase(newVals.begin()+GeoId); + + // Find coincident points to replace the points of the deleted geometry + std::vector GeoIdList; + std::vector PosIdList; + for (PointPos PosId = start; PosId != mid; ) { + getDirectlyCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList); + if (GeoIdList.size() > 1) { + delConstraintOnPoint(GeoId, PosId, true /* only coincidence */); + transferConstraints(GeoIdList[0], PosIdList[0], GeoIdList[1], PosIdList[1]); + } + PosId = (PosId == start) ? end : mid; // loop through [start, end, mid] + } + + const std::vector< Constraint * > &constraints = this->Constraints.getValues(); + std::vector< Constraint * > newConstraints(0); + for (std::vector::const_iterator it = constraints.begin(); + it != constraints.end(); ++it) { + if ((*it)->First != GeoId && (*it)->Second != GeoId && (*it)->Third != GeoId) { + Constraint *copiedConstr = (*it)->clone(); + if (copiedConstr->First > GeoId) + copiedConstr->First -= 1; + if (copiedConstr->Second > GeoId) + copiedConstr->Second -= 1; + if (copiedConstr->Third > GeoId) + copiedConstr->Third -= 1; + newConstraints.push_back(copiedConstr); + } + } + + this->Geometry.setValues(newVals); + this->Constraints.setValues(newConstraints); + this->Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; +} + +int SketchObject::toggleConstruction(int GeoId) +{ + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + if (GeoId < 0 || GeoId >= int(vals.size())) + return -1; + + std::vector< Part::Geometry * > newVals(vals); + + Part::Geometry *geoNew = newVals[GeoId]->clone(); + geoNew->Construction = !geoNew->Construction; + newVals[GeoId]=geoNew; + + this->Geometry.setValues(newVals); + //this->Constraints.acceptGeometry(getCompleteGeometry()); <= This is not necessary for a toggle. Reducing redundant solving. Abdullah + solverNeedsUpdate=true; + return 0; +} + +int SketchObject::setConstruction(int GeoId, bool on) +{ + const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + if (GeoId < 0 || GeoId >= int(vals.size())) + return -1; + + std::vector< Part::Geometry * > newVals(vals); + + Part::Geometry *geoNew = newVals[GeoId]->clone(); + geoNew->Construction = on; + newVals[GeoId]=geoNew; + + this->Geometry.setValues(newVals); + //this->Constraints.acceptGeometry(getCompleteGeometry()); <= This is not necessary for a toggle. Reducing redundant solving. Abdullah + solverNeedsUpdate=true; + return 0; +} + +//ConstraintList is used only to make copies. +int SketchObject::addConstraints(const std::vector &ConstraintList) +{ + const std::vector< Constraint * > &vals = this->Constraints.getValues(); + + std::vector< Constraint * > newVals(vals); + newVals.insert(newVals.end(), ConstraintList.begin(), ConstraintList.end()); + + //test if tangent constraints have been added; AutoLockTangency. + std::vector< Constraint * > tbd;//list of temporary copies that need to be deleted + for(std::size_t i = newVals.size()-ConstraintList.size(); iType == Tangent || newVals[i]->Type == Perpendicular ){ + Constraint *constNew = newVals[i]->clone(); + AutoLockTangencyAndPerpty(constNew); + tbd.push_back(constNew); + newVals[i] = constNew; + } + } + + this->Constraints.setValues(newVals); + + //clean up - delete temporary copies of constraints that were made to affect the constraints + for(std::size_t i=0; iConstraints.getSize()-1; +} + +int SketchObject::addConstraint(const Constraint *constraint) +{ + const std::vector< Constraint * > &vals = this->Constraints.getValues(); + + std::vector< Constraint * > newVals(vals); + Constraint *constNew = constraint->clone(); + + if (constNew->Type == Tangent || constNew->Type == Perpendicular) + AutoLockTangencyAndPerpty(constNew); + + newVals.push_back(constNew); + this->Constraints.setValues(newVals); + delete constNew; + return this->Constraints.getSize()-1; +} + +int SketchObject::delConstraint(int ConstrId) +{ + const std::vector< Constraint * > &vals = this->Constraints.getValues(); + if (ConstrId < 0 || ConstrId >= int(vals.size())) + return -1; + + std::vector< Constraint * > newVals(vals); + newVals.erase(newVals.begin()+ConstrId); + this->Constraints.setValues(newVals); + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; +} + +int SketchObject::delConstraintOnPoint(int VertexId, bool onlyCoincident) +{ + int GeoId; + PointPos PosId; + if (VertexId == -1) { // RootPoint + GeoId = -1; + PosId = start; + } else + getGeoVertexIndex(VertexId, GeoId, PosId); + + return delConstraintOnPoint(GeoId, PosId, onlyCoincident); +} + +int SketchObject::delConstraintOnPoint(int GeoId, PointPos PosId, bool onlyCoincident) +{ + const std::vector &vals = this->Constraints.getValues(); + + // check if constraints can be redirected to some other point + int replaceGeoId=Constraint::GeoUndef; + PointPos replacePosId=Sketcher::none; + if (!onlyCoincident) { + for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it) { + if ((*it)->Type == Sketcher::Coincident) { + if ((*it)->First == GeoId && (*it)->FirstPos == PosId) { + replaceGeoId = (*it)->Second; + replacePosId = (*it)->SecondPos; + break; + } + else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) { + replaceGeoId = (*it)->First; + replacePosId = (*it)->FirstPos; + break; + } + } + } + } + + // remove or redirect any constraints associated with the given point + std::vector newVals(0); + for (std::vector::const_iterator it = vals.begin(); it != vals.end(); ++it) { + if ((*it)->Type == Sketcher::Coincident) { + if ((*it)->First == GeoId && (*it)->FirstPos == PosId) { + if (replaceGeoId != Constraint::GeoUndef && + (replaceGeoId != (*it)->Second || replacePosId != (*it)->SecondPos)) { // redirect this constraint + (*it)->First = replaceGeoId; + (*it)->FirstPos = replacePosId; + } + else + continue; // skip this constraint + } + else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) { + if (replaceGeoId != Constraint::GeoUndef && + (replaceGeoId != (*it)->First || replacePosId != (*it)->FirstPos)) { // redirect this constraint + (*it)->Second = replaceGeoId; + (*it)->SecondPos = replacePosId; + } + else + continue; // skip this constraint + } + } + else if (!onlyCoincident) { + if ((*it)->Type == Sketcher::Distance || + (*it)->Type == Sketcher::DistanceX || (*it)->Type == Sketcher::DistanceY) { + if ((*it)->First == GeoId && (*it)->FirstPos == none && + (PosId == start || PosId == end)) { + // remove the constraint even if it is not directly associated + // with the given point + continue; // skip this constraint + } + else if ((*it)->First == GeoId && (*it)->FirstPos == PosId) { + if (replaceGeoId != Constraint::GeoUndef) { // redirect this constraint + (*it)->First = replaceGeoId; + (*it)->FirstPos = replacePosId; + } + else + continue; // skip this constraint + } + else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) { + if (replaceGeoId != Constraint::GeoUndef) { // redirect this constraint + (*it)->Second = replaceGeoId; + (*it)->SecondPos = replacePosId; + } + else + continue; // skip this constraint + } + } + else if ((*it)->Type == Sketcher::PointOnObject) { + if ((*it)->First == GeoId && (*it)->FirstPos == PosId) { + if (replaceGeoId != Constraint::GeoUndef) { // redirect this constraint + (*it)->First = replaceGeoId; + (*it)->FirstPos = replacePosId; + } + else + continue; // skip this constraint + } + } + else if ((*it)->Type == Sketcher::Tangent) { + if (((*it)->First == GeoId && (*it)->FirstPos == PosId) || + ((*it)->Second == GeoId && (*it)->SecondPos == PosId)) { + // we could keep the tangency constraint by converting it + // to a simple one but it is not really worth + continue; // skip this constraint + } + } + else if ((*it)->Type == Sketcher::Symmetric) { + if (((*it)->First == GeoId && (*it)->FirstPos == PosId) || + ((*it)->Second == GeoId && (*it)->SecondPos == PosId)) { + continue; // skip this constraint + } + } + } + newVals.push_back(*it); + } + if (newVals.size() < vals.size()) { + this->Constraints.setValues(newVals); + + return 0; + } + + return -1; // no such constraint +} + +int SketchObject::transferConstraints(int fromGeoId, PointPos fromPosId, int toGeoId, PointPos toPosId) +{ + const std::vector &vals = this->Constraints.getValues(); + std::vector newVals(vals); + for (int i=0; i < int(newVals.size()); i++) { + if (vals[i]->First == fromGeoId && vals[i]->FirstPos == fromPosId && + !(vals[i]->Second == toGeoId && vals[i]->SecondPos == toPosId)) { + Constraint *constNew = newVals[i]->clone(); + constNew->First = toGeoId; + constNew->FirstPos = toPosId; + newVals[i] = constNew; + } else if (vals[i]->Second == fromGeoId && vals[i]->SecondPos == fromPosId && + !(vals[i]->First == toGeoId && vals[i]->FirstPos == toPosId)) { + Constraint *constNew = newVals[i]->clone(); + constNew->Second = toGeoId; + constNew->SecondPos = toPosId; + newVals[i] = constNew; + } + } + this->Constraints.setValues(newVals); + return 0; +} + +int SketchObject::fillet(int GeoId, PointPos PosId, double radius, bool trim) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; + + // Find the other geometry Id associated with the coincident point + std::vector GeoIdList; + std::vector PosIdList; + getDirectlyCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList); + + // only coincident points between two (non-external) edges can be filleted + if (GeoIdList.size() == 2 && GeoIdList[0] >= 0 && GeoIdList[1] >= 0) { + const Part::Geometry *geo1 = getGeometry(GeoIdList[0]); + const Part::Geometry *geo2 = getGeometry(GeoIdList[1]); + if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId() ) { + const Part::GeomLineSegment *lineSeg1 = dynamic_cast(geo1); + const Part::GeomLineSegment *lineSeg2 = dynamic_cast(geo2); + + Base::Vector3d midPnt1 = (lineSeg1->getStartPoint() + lineSeg1->getEndPoint()) / 2 ; + Base::Vector3d midPnt2 = (lineSeg2->getStartPoint() + lineSeg2->getEndPoint()) / 2 ; + return fillet(GeoIdList[0], GeoIdList[1], midPnt1, midPnt2, radius, trim); + } + } + + return -1; +} + +int SketchObject::fillet(int GeoId1, int GeoId2, + const Base::Vector3d& refPnt1, const Base::Vector3d& refPnt2, + double radius, bool trim) +{ + if (GeoId1 < 0 || GeoId1 > getHighestCurveIndex() || + GeoId2 < 0 || GeoId2 > getHighestCurveIndex()) + return -1; + + const Part::Geometry *geo1 = getGeometry(GeoId1); + const Part::Geometry *geo2 = getGeometry(GeoId2); + if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId() ) { + const Part::GeomLineSegment *lineSeg1 = dynamic_cast(geo1); + const Part::GeomLineSegment *lineSeg2 = dynamic_cast(geo2); + + Base::Vector3d filletCenter; + if (!Part::findFilletCenter(lineSeg1, lineSeg2, radius, refPnt1, refPnt2, filletCenter)) + return -1; + Base::Vector3d dir1 = lineSeg1->getEndPoint() - lineSeg1->getStartPoint(); + Base::Vector3d dir2 = lineSeg2->getEndPoint() - lineSeg2->getStartPoint(); + + // the intersection point will and two distances will be necessary later for trimming the lines + Base::Vector3d intersection, dist1, dist2; + + // create arc from known parameters and lines + int filletId; + Part::GeomArcOfCircle *arc = Part::createFilletGeometry(lineSeg1, lineSeg2, filletCenter, radius); + if (arc) { + // calculate intersection and distances before we invalidate lineSeg1 and lineSeg2 + if (!find2DLinesIntersection(lineSeg1, lineSeg2, intersection)) { + delete arc; + return -1; + } + dist1.ProjToLine(arc->getStartPoint(/*emulateCCW=*/true)-intersection, dir1); + dist2.ProjToLine(arc->getStartPoint(/*emulateCCW=*/true)-intersection, dir2); + Part::Geometry *newgeo = dynamic_cast(arc); + filletId = addGeometry(newgeo); + if (filletId < 0) { + delete arc; + return -1; + } + } + else + return -1; + + if (trim) { + PointPos PosId1 = (filletCenter-intersection)*dir1 > 0 ? start : end; + PointPos PosId2 = (filletCenter-intersection)*dir2 > 0 ? start : end; + + delConstraintOnPoint(GeoId1, PosId1, false); + delConstraintOnPoint(GeoId2, PosId2, false); + Sketcher::Constraint *tangent1 = new Sketcher::Constraint(); + Sketcher::Constraint *tangent2 = new Sketcher::Constraint(); + + tangent1->Type = Sketcher::Tangent; + tangent1->First = GeoId1; + tangent1->FirstPos = PosId1; + tangent1->Second = filletId; + + tangent2->Type = Sketcher::Tangent; + tangent2->First = GeoId2; + tangent2->FirstPos = PosId2; + tangent2->Second = filletId; + + if (dist1.Length() < dist2.Length()) { + tangent1->SecondPos = start; + tangent2->SecondPos = end; + movePoint(GeoId1, PosId1, arc->getStartPoint(/*emulateCCW=*/true),false,true); + movePoint(GeoId2, PosId2, arc->getEndPoint(/*emulateCCW=*/true),false,true); + } + else { + tangent1->SecondPos = end; + tangent2->SecondPos = start; + movePoint(GeoId1, PosId1, arc->getEndPoint(/*emulateCCW=*/true),false,true); + movePoint(GeoId2, PosId2, arc->getStartPoint(/*emulateCCW=*/true),false,true); + } + + addConstraint(tangent1); + addConstraint(tangent2); + delete tangent1; + delete tangent2; + } + delete arc; + + if(noRecomputes) // if we do not have a recompute after the geometry creation, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + return -1; +} + +int SketchObject::trim(int GeoId, const Base::Vector3d& point) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; + + const std::vector &geomlist = getInternalGeometry(); + const std::vector &constraints = this->Constraints.getValues(); + + int GeoId1=Constraint::GeoUndef, GeoId2=Constraint::GeoUndef; + Base::Vector3d point1, point2; + Part2DObject::seekTrimPoints(geomlist, GeoId, point, GeoId1, point1, GeoId2, point2); + if (GeoId1 < 0 && GeoId2 >= 0) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + } + + Part::Geometry *geo = geomlist[GeoId]; + if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg = dynamic_cast(geo); + Base::Vector3d startPnt = lineSeg->getStartPoint(); + Base::Vector3d endPnt = lineSeg->getEndPoint(); + Base::Vector3d dir = (endPnt - startPnt).Normalize(); + double length = (endPnt - startPnt)*dir; + double x0 = (point - startPnt)*dir; + if (GeoId1 >= 0 && GeoId2 >= 0) { + double x1 = (point1 - startPnt)*dir; + double x2 = (point2 - startPnt)*dir; + if (x1 > x2) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(x1,x2); + } + if (x1 >= 0.001*length && x2 <= 0.999*length) { + if (x1 < x0 && x2 > x0) { + int newGeoId = addGeometry(geo); + // go through all constraints and replace the point (GeoId,end) with (newGeoId,end) + transferConstraints(GeoId, end, newGeoId, end); + + movePoint(GeoId, end, point1,false,true); + movePoint(newGeoId, start, point2,false,true); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if (secondPos2 == Sketcher::none && (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset the second pos + newConstr->SecondPos = Sketcher::none; + + newConstr->Type = constrType2; + newConstr->First = newGeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + // Reset the second pos + newConstr->SecondPos = Sketcher::none; + + // new line segments colinear + newConstr->Type = Sketcher::Tangent; + newConstr->First = GeoId; + newConstr->FirstPos = none; + newConstr->Second = newGeoId; + addConstraint(newConstr); + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + } else if (x1 < 0.001*length) { // drop the first intersection point + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + } else if (x2 > 0.999*length) { // drop the second intersection point + } + else + return -1; + } + + if (GeoId1 >= 0) { + double x1 = (point1 - startPnt)*dir; + if (x1 >= 0.001*length && x1 <= 0.999*length) { + + ConstraintType constrType = Sketcher::PointOnObject; + PointPos secondPos = Sketcher::none; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if ((constr->First == GeoId1 && constr->Second == GeoId)) { + constrType = Sketcher::Coincident; + secondPos = constr->FirstPos; + delConstraintOnPoint(GeoId1, constr->FirstPos, false); + break; + } + } + + if (x1 > x0) { // trim line start + delConstraintOnPoint(GeoId, start, false); + movePoint(GeoId, start, point1,false,true); + + // constrain the trimming point on the corresponding geometry + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + else if (x1 < x0) { // trim line end + delConstraintOnPoint(GeoId, end, false); + movePoint(GeoId, end, point1,false,true); + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + } + } + } else if (geo->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle *circle = dynamic_cast(geo); + Base::Vector3d center = circle->getCenter(); + double theta0 = Base::fmod(atan2(point.y - center.y,point.x - center.x), 2.f*M_PI); + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1 = Base::fmod(atan2(point1.y - center.y, point1.x - center.x), 2.f*M_PI); + double theta2 = Base::fmod(atan2(point2.y - center.y, point2.x - center.x), 2.f*M_PI); + if (Base::fmod(theta1 - theta0, 2.f*M_PI) > Base::fmod(theta2 - theta0, 2.f*M_PI)) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 == theta0 || theta1 == theta2) + return -1; + else if (theta1 > theta2) + theta2 += 2.f*M_PI; + + // Trim Point between intersection points + + // Create a new arc to substitute Circle in geometry list and set parameters + Part::GeomArcOfCircle *geoNew = new Part::GeomArcOfCircle(); + geoNew->setCenter(center); + geoNew->setRadius(circle->getRadius()); + geoNew->setRange(theta1, theta2,/*emulateCCW=*/true); + + std::vector< Part::Geometry * > newVals(geomlist); + newVals[GeoId] = geoNew; + Geometry.setValues(newVals); + Constraints.acceptGeometry(getCompleteGeometry()); + delete geoNew; + rebuildVertexIndex(); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if(secondPos2 == Sketcher::none && (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + // Add Second Constraint + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + } else if (geo->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + const Part::GeomEllipse *ellipse = dynamic_cast(geo); + Base::Vector3d center = ellipse->getCenter(); + double theta0; + ellipse->closestParameter(point,theta0); + theta0 = Base::fmod(theta0, 2.f*M_PI); + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1; + ellipse->closestParameter(point1,theta1); + theta1 = Base::fmod(theta1, 2.f*M_PI); + double theta2; + ellipse->closestParameter(point2,theta2); + theta2 = Base::fmod(theta2, 2.f*M_PI); + if (Base::fmod(theta1 - theta0, 2.f*M_PI) > Base::fmod(theta2 - theta0, 2.f*M_PI)) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 == theta0 || theta1 == theta2) + return -1; + else if (theta1 > theta2) + theta2 += 2.f*M_PI; + + // Trim Point between intersection points + + // Create a new arc to substitute Circle in geometry list and set parameters + Part::GeomArcOfEllipse *geoNew = new Part::GeomArcOfEllipse(); + geoNew->setCenter(center); + geoNew->setMajorRadius(ellipse->getMajorRadius()); + geoNew->setMinorRadius(ellipse->getMinorRadius()); + geoNew->setMajorAxisDir(ellipse->getMajorAxisDir()); + geoNew->setRange(theta1, theta2, /*emulateCCW=*/true); + + std::vector< Part::Geometry * > newVals(geomlist); + newVals[GeoId] = geoNew; + Geometry.setValues(newVals); + Constraints.acceptGeometry(getCompleteGeometry()); + delete geoNew; + rebuildVertexIndex(); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if(secondPos2 == Sketcher::none && (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + // Add Second Constraint + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + } else if (geo->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *aoc = dynamic_cast(geo); + Base::Vector3d center = aoc->getCenter(); + double startAngle, endAngle; + aoc->getRange(startAngle, endAngle, /*emulateCCW=*/true); + double dir = (startAngle < endAngle) ? 1 : -1; // this is always == 1 + double arcLength = (endAngle - startAngle)*dir; + double theta0 = Base::fmod(atan2(point.y - center.y, point.x - center.x) - startAngle, 2.f*M_PI); // x0 + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1 = Base::fmod(atan2(point1.y - center.y, point1.x - center.x) - startAngle, 2.f*M_PI) * dir; // x1 + double theta2 = Base::fmod(atan2(point2.y - center.y, point2.x - center.x) - startAngle, 2.f*M_PI) * dir; // x2 + if (theta1 > theta2) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 >= 0.001*arcLength && theta2 <= 0.999*arcLength) { + // Trim Point between intersection points + if (theta1 < theta0 && theta2 > theta0) { + int newGeoId = addGeometry(geo); + // go through all constraints and replace the point (GeoId,end) with (newGeoId,end) + transferConstraints(GeoId, end, newGeoId, end); + + Part::GeomArcOfCircle *aoc1 = dynamic_cast(geomlist[GeoId]); + Part::GeomArcOfCircle *aoc2 = dynamic_cast(geomlist[newGeoId]); + aoc1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true); + aoc2->setRange(startAngle + theta2, endAngle, /*emulateCCW=*/true); + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + + // Build Constraints associated with new pair of arcs + newConstr->Type = Sketcher::Equal; + newConstr->First = GeoId; + newConstr->Second = newGeoId; + addConstraint(newConstr); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && + (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if (secondPos2 == Sketcher::none && + (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + newConstr->Type = constrType2; + newConstr->First = newGeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + newConstr->Type = Sketcher::Coincident; + newConstr->First = GeoId; + newConstr->FirstPos = Sketcher::mid; + newConstr->Second = newGeoId; + newConstr->SecondPos = Sketcher::mid; + addConstraint(newConstr); + + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } else + return -1; + } else if (theta1 < 0.001*arcLength) { // drop the second intersection point + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + } else if (theta2 > 0.999*arcLength) { + } + else + return -1; + } + + if (GeoId1 >= 0) { + + ConstraintType constrType = Sketcher::PointOnObject; + PointPos secondPos = Sketcher::none; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if ((constr->First == GeoId1 && constr->Second == GeoId)) { + constrType = Sketcher::Coincident; + secondPos = constr->FirstPos; + delConstraintOnPoint(GeoId1, constr->FirstPos, false); + break; + } + } + + double theta1 = Base::fmod(atan2(point1.y - center.y, point1.x - center.x) - startAngle, 2.f*M_PI) * dir; // x1 + if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) { + if (theta1 > theta0) { // trim arc start + delConstraintOnPoint(GeoId, start, false); + Part::GeomArcOfCircle *aoc1 = dynamic_cast(geomlist[GeoId]); + aoc1->setRange(startAngle + theta1, endAngle, /*emulateCCW=*/true); + // constrain the trimming point on the corresponding geometry + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + else { // trim arc end + delConstraintOnPoint(GeoId, end, false); + Part::GeomArcOfCircle *aoc1 = dynamic_cast(geomlist[GeoId]); + aoc1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true); + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + } + } + } else if (geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + const Part::GeomArcOfEllipse *aoe = dynamic_cast(geo); + Base::Vector3d center = aoe->getCenter(); + double startAngle, endAngle; + aoe->getRange(startAngle, endAngle,/*emulateCCW=*/true); + double dir = (startAngle < endAngle) ? 1 : -1; // this is always == 1 + double arcLength = (endAngle - startAngle)*dir; + double theta0 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point.x-center.x)*aoe->getMajorAxisDir().y-(point.y-center.y)*aoe->getMajorAxisDir().x), + aoe->getMinorRadius()*((point.x-center.x)*aoe->getMajorAxisDir().x+(point.y-center.y)*aoe->getMajorAxisDir().y) + )- startAngle, 2.f*M_PI); // x0 + if (GeoId1 >= 0 && GeoId2 >= 0) { + double theta1 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().y-(point1.y-center.y)*aoe->getMajorAxisDir().x), + aoe->getMinorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().x+(point1.y-center.y)*aoe->getMajorAxisDir().y) + )- startAngle, 2.f*M_PI) * dir; // x1 + double theta2 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point2.x-center.x)*aoe->getMajorAxisDir().y-(point2.y-center.y)*aoe->getMajorAxisDir().x), + aoe->getMinorRadius()*((point2.x-center.x)*aoe->getMajorAxisDir().x+(point2.y-center.y)*aoe->getMajorAxisDir().y) + )- startAngle, 2.f*M_PI) * dir; // x2 + + if (theta1 > theta2) { + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + std::swap(theta1,theta2); + } + if (theta1 >= 0.001*arcLength && theta2 <= 0.999*arcLength) { + // Trim Point between intersection points + if (theta1 < theta0 && theta2 > theta0) { + int newGeoId = addGeometry(geo); + // go through all constraints and replace the point (GeoId,end) with (newGeoId,end) + transferConstraints(GeoId, end, newGeoId, end); + + Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); + Part::GeomArcOfEllipse *aoe2 = dynamic_cast(geomlist[newGeoId]); + aoe1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true); + aoe2->setRange(startAngle + theta2, endAngle, /*emulateCCW=*/true); + + // constrain the trimming points on the corresponding geometries + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + + // Build Constraints associated with new pair of arcs + newConstr->Type = Sketcher::Equal; + newConstr->First = GeoId; + newConstr->Second = newGeoId; + addConstraint(newConstr); + + PointPos secondPos1 = Sketcher::none, secondPos2 = Sketcher::none; + ConstraintType constrType1 = Sketcher::PointOnObject, constrType2 = Sketcher::PointOnObject; + + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if (secondPos1 == Sketcher::none && + (constr->First == GeoId1 && constr->Second == GeoId)) { + constrType1= Sketcher::Coincident; + secondPos1 = constr->FirstPos; + } else if (secondPos2 == Sketcher::none && + (constr->First == GeoId2 && constr->Second == GeoId)) { + constrType2 = Sketcher::Coincident; + secondPos2 = constr->FirstPos; + } + } + + newConstr->Type = constrType1; + newConstr->First = GeoId; + newConstr->FirstPos = end; + newConstr->Second = GeoId1; + + if (constrType1 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos1; + delConstraintOnPoint(GeoId1, secondPos1, false); + } + + addConstraint(newConstr); + + // Reset secondpos in case it was set previously + newConstr->SecondPos = Sketcher::none; + + newConstr->Type = constrType2; + newConstr->First = newGeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId2; + + if (constrType2 == Sketcher::Coincident) { + newConstr->SecondPos = secondPos2; + delConstraintOnPoint(GeoId2, secondPos2, false); + } + + addConstraint(newConstr); + + newConstr->Type = Sketcher::Coincident; + newConstr->First = GeoId; + newConstr->FirstPos = Sketcher::mid; + newConstr->Second = newGeoId; + newConstr->SecondPos = Sketcher::mid; + addConstraint(newConstr); + + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } else + return -1; + } else if (theta1 < 0.001*arcLength) { // drop the second intersection point + std::swap(GeoId1,GeoId2); + std::swap(point1,point2); + } else if (theta2 > 0.999*arcLength) { + } else + return -1; + } + + if (GeoId1 >= 0) { + + ConstraintType constrType = Sketcher::PointOnObject; + PointPos secondPos = Sketcher::none; + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + Constraint *constr = *(it); + if ((constr->First == GeoId1 && constr->Second == GeoId)) { + constrType = Sketcher::Coincident; + secondPos = constr->FirstPos; + delConstraintOnPoint(GeoId1, constr->FirstPos, false); + break; + } + } + + double theta1 = Base::fmod( + atan2(-aoe->getMajorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().y-(point1.y-center.y)*aoe->getMajorAxisDir().x), + aoe->getMinorRadius()*((point1.x-center.x)*aoe->getMajorAxisDir().x+(point1.y-center.y)*aoe->getMajorAxisDir().y) + )- startAngle, 2.f*M_PI) * dir; // x1 + + if (theta1 >= 0.001*arcLength && theta1 <= 0.999*arcLength) { + if (theta1 > theta0) { // trim arc start + delConstraintOnPoint(GeoId, start, false); + Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); + aoe1->setRange(startAngle + theta1, endAngle, /*emulateCCW=*/true); + // constrain the trimming point on the corresponding geometry + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = constrType; + newConstr->First = GeoId; + newConstr->FirstPos = start; + newConstr->Second = GeoId1; + + if (constrType == Sketcher::Coincident) + newConstr->SecondPos = secondPos; + + addConstraint(newConstr); + delete newConstr; + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; + } + else { // trim arc end + delConstraintOnPoint(GeoId, end, false); + Part::GeomArcOfEllipse *aoe1 = dynamic_cast(geomlist[GeoId]); + aoe1->setRange(startAngle, startAngle + theta1, /*emulateCCW=*/true); + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + return 0; + } + } + } + } + + return -1; +} + +int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, Sketcher::PointPos refPosId/*=Sketcher::none*/) +{ + const std::vector< Part::Geometry * > &geovals = getInternalGeometry(); + std::vector< Part::Geometry * > newgeoVals(geovals); + + const std::vector< Constraint * > &constrvals = this->Constraints.getValues(); + std::vector< Constraint * > newconstrVals(constrvals); + + int cgeoid = getHighestCurveIndex()+1; + + std::map geoIdMap; + std::map isStartEndInverted; + + // reference is a line + if(refPosId == Sketcher::none) { + const Part::Geometry *georef = getGeometry(refGeoId); + if(georef->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { + Base::Console().Error("Reference for symmetric is neither a point nor a line.\n"); + return -1; + } + + const Part::GeomLineSegment *refGeoLine = static_cast(georef); + //line + Base::Vector3d refstart = refGeoLine->getStartPoint(); + Base::Vector3d vectline = refGeoLine->getEndPoint()-refstart; + + for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) { + const Part::Geometry *geo = getGeometry(*it); + Part::Geometry *geosym = geo->clone(); + + // Handle Geometry + if(geosym->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ + Part::GeomLineSegment *geosymline = static_cast(geosym); + Base::Vector3d sp = geosymline->getStartPoint(); + Base::Vector3d ep = geosymline->getEndPoint(); + + geosymline->setPoints(sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp), + ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep)); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomCircle::getClassTypeId()){ + Part::GeomCircle *geosymcircle = static_cast(geosym); + Base::Vector3d cp = geosymcircle->getCenter(); + + geosymcircle->setCenter(cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp)); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + Part::GeomArcOfCircle *geoaoc = static_cast(geosym); + Base::Vector3d sp = geoaoc->getStartPoint(true); + Base::Vector3d ep = geoaoc->getEndPoint(true); + Base::Vector3d cp = geoaoc->getCenter(); + + Base::Vector3d ssp = sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp); + Base::Vector3d sep = ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep); + Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp); + + double theta1 = Base::fmod(atan2(sep.y - scp.y, sep.x - scp.x), 2.f*M_PI); + double theta2 = Base::fmod(atan2(ssp.y - scp.y, ssp.x - scp.x), 2.f*M_PI); + + geoaoc->setCenter(scp); + geoaoc->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, true)); + } + else if(geosym->getTypeId() == Part::GeomEllipse::getClassTypeId()){ + Part::GeomEllipse *geosymellipse = static_cast(geosym); + Base::Vector3d cp = geosymellipse->getCenter(); + + Base::Vector3d majdir = geosymellipse->getMajorAxisDir(); + double majord=geosymellipse->getMajorRadius(); + double minord=geosymellipse->getMinorRadius(); + double df= sqrt(majord*majord-minord*minord); + Base::Vector3d f1 = cp + df * majdir; + + Base::Vector3d sf1 = f1+2.0*(f1.Perpendicular(refGeoLine->getStartPoint(),vectline)-f1); + Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp); + + geosymellipse->setMajorAxisDir(sf1-scp); + + geosymellipse->setCenter(scp); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){ + Part::GeomArcOfEllipse *geosymaoe = static_cast(geosym); + Base::Vector3d cp = geosymaoe->getCenter(); + Base::Vector3d sp = geosymaoe->getStartPoint(true); + Base::Vector3d ep = geosymaoe->getEndPoint(true); + + Base::Vector3d majdir = geosymaoe->getMajorAxisDir(); + double majord=geosymaoe->getMajorRadius(); + double minord=geosymaoe->getMinorRadius(); + double df= sqrt(majord*majord-minord*minord); + Base::Vector3d f1 = cp + df * majdir; + + Base::Vector3d sf1 = f1+2.0*(f1.Perpendicular(refGeoLine->getStartPoint(),vectline)-f1); + Base::Vector3d scp = cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp); + Base::Vector3d ssp = sp+2.0*(sp.Perpendicular(refGeoLine->getStartPoint(),vectline)-sp); + Base::Vector3d sep = ep+2.0*(ep.Perpendicular(refGeoLine->getStartPoint(),vectline)-ep); + + geosymaoe->setMajorAxisDir(sf1-scp); + + geosymaoe->setCenter(scp); + + double theta1,theta2; + geosymaoe->closestParameter(sep,theta1); + geosymaoe->closestParameter(ssp,theta2); + + geosymaoe->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, true)); + } + else if(geosym->getTypeId() == Part::GeomPoint::getClassTypeId()){ + Part::GeomPoint *geosympoint = static_cast(geosym); + Base::Vector3d cp = geosympoint->getPoint(); + + geosympoint->setPoint(cp+2.0*(cp.Perpendicular(refGeoLine->getStartPoint(),vectline)-cp)); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else { + Base::Console().Error("Unsupported Geometry!! Just copying it.\n"); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + + newgeoVals.push_back(geosym); + geoIdMap.insert(std::make_pair(*it, cgeoid)); + cgeoid++; + } + } + else { //reference is a point + Vector3d refpoint; + const Part::Geometry *georef = getGeometry(refGeoId); + + if (georef->getTypeId() == Part::GeomPoint::getClassTypeId()) { + refpoint = static_cast(georef)->getPoint(); + } + else if ( refGeoId == -1 && refPosId == Sketcher::start) { + refpoint = Vector3d(0,0,0); + } + else { + switch(refPosId){ + case Sketcher::start: + if(georef->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ + const Part::GeomLineSegment *geosymline = static_cast(georef); + refpoint = geosymline->getStartPoint(); + } + else if(georef->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + const Part::GeomArcOfCircle *geoaoc = static_cast(georef); + refpoint = geoaoc->getStartPoint(true); + } + else if(georef->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){ + const Part::GeomArcOfEllipse *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getStartPoint(true); + } + break; + case Sketcher::end: + if(georef->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ + const Part::GeomLineSegment *geosymline = static_cast(georef); + refpoint = geosymline->getEndPoint(); + } + else if(georef->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + const Part::GeomArcOfCircle *geoaoc = static_cast(georef); + refpoint = geoaoc->getEndPoint(true); + } + else if(georef->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){ + const Part::GeomArcOfEllipse *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getEndPoint(true); + } + break; + case Sketcher::mid: + if(georef->getTypeId() == Part::GeomCircle::getClassTypeId()){ + const Part::GeomCircle *geosymcircle = static_cast(georef); + refpoint = geosymcircle->getCenter(); + } + else if(georef->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + const Part::GeomArcOfCircle *geoaoc = static_cast(georef); + refpoint = geoaoc->getCenter(); + } + else if(georef->getTypeId() == Part::GeomEllipse::getClassTypeId()){ + const Part::GeomEllipse *geosymellipse = static_cast(georef); + refpoint = geosymellipse->getCenter(); + } + else if(georef->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){ + const Part::GeomArcOfEllipse *geosymaoe = static_cast(georef); + refpoint = geosymaoe->getCenter(); + } + break; + default: + Base::Console().Error("Wrong PointPosId.\n"); + return -1; + } + } + + for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) { + const Part::Geometry *geo = getGeometry(*it); + Part::Geometry *geosym = geo->clone(); + + // Handle Geometry + if(geosym->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ + Part::GeomLineSegment *geosymline = static_cast(geosym); + Base::Vector3d sp = geosymline->getStartPoint(); + Base::Vector3d ep = geosymline->getEndPoint(); + Base::Vector3d ssp = sp + 2.0*(refpoint-sp); + Base::Vector3d sep = ep + 2.0*(refpoint-ep); + + geosymline->setPoints(ssp, sep); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomCircle::getClassTypeId()){ + Part::GeomCircle *geosymcircle = static_cast(geosym); + Base::Vector3d cp = geosymcircle->getCenter(); + + geosymcircle->setCenter(cp + 2.0*(refpoint-cp)); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + Part::GeomArcOfCircle *geoaoc = static_cast(geosym); + Base::Vector3d sp = geoaoc->getStartPoint(true); + Base::Vector3d ep = geoaoc->getEndPoint(true); + Base::Vector3d cp = geoaoc->getCenter(); + + Base::Vector3d ssp = sp + 2.0*(refpoint-sp); + Base::Vector3d sep = ep + 2.0*(refpoint-ep); + Base::Vector3d scp = cp + 2.0*(refpoint-cp); + + double theta1 = Base::fmod(atan2(ssp.y - scp.y, ssp.x - scp.x), 2.f*M_PI); + double theta2 = Base::fmod(atan2(sep.y - scp.y, sep.x - scp.x), 2.f*M_PI); + + geoaoc->setCenter(scp); + geoaoc->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomEllipse::getClassTypeId()){ + Part::GeomEllipse *geosymellipse = static_cast(geosym); + Base::Vector3d cp = geosymellipse->getCenter(); + + Base::Vector3d majdir = geosymellipse->getMajorAxisDir(); + double majord=geosymellipse->getMajorRadius(); + double minord=geosymellipse->getMinorRadius(); + double df= sqrt(majord*majord-minord*minord); + Base::Vector3d f1 = cp + df * majdir; + + Base::Vector3d sf1 = f1 + 2.0*(refpoint-f1); + Base::Vector3d scp = cp + 2.0*(refpoint-cp); + + geosymellipse->setMajorAxisDir(sf1-scp); + + geosymellipse->setCenter(scp); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){ + Part::GeomArcOfEllipse *geosymaoe = static_cast(geosym); + Base::Vector3d cp = geosymaoe->getCenter(); + Base::Vector3d sp = geosymaoe->getStartPoint(true); + Base::Vector3d ep = geosymaoe->getEndPoint(true); + + Base::Vector3d majdir = geosymaoe->getMajorAxisDir(); + double majord=geosymaoe->getMajorRadius(); + double minord=geosymaoe->getMinorRadius(); + double df= sqrt(majord*majord-minord*minord); + Base::Vector3d f1 = cp + df * majdir; + + Base::Vector3d sf1 = f1 + 2.0*(refpoint-f1); + Base::Vector3d scp = cp + 2.0*(refpoint-cp); + Base::Vector3d ssp = sp + 2.0*(refpoint-sp); + Base::Vector3d sep = ep + 2.0*(refpoint-ep); + + geosymaoe->setMajorAxisDir(sf1-scp); + + geosymaoe->setCenter(scp); + + double theta1,theta2; + geosymaoe->closestParameter(ssp,theta1); + geosymaoe->closestParameter(sep,theta2); + + geosymaoe->setRange(theta1,theta2,true); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else if(geosym->getTypeId() == Part::GeomPoint::getClassTypeId()){ + Part::GeomPoint *geosympoint = static_cast(geosym); + Base::Vector3d cp = geosympoint->getPoint(); + + geosympoint->setPoint(cp + 2.0*(refpoint-cp)); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + else { + Base::Console().Error("Unsupported Geometry!! Just copying it.\n"); + isStartEndInverted.insert(std::make_pair(*it, false)); + } + + newgeoVals.push_back(geosym); + geoIdMap.insert(std::make_pair(*it, cgeoid)); + cgeoid++; + } + } + + // add the geometry + Geometry.setValues(newgeoVals); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + + for (std::vector::const_iterator it = constrvals.begin(); it != constrvals.end(); ++it) { + + std::vector::const_iterator fit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->First); + + if(fit != geoIdList.end()) { // if First of constraint is in geoIdList + + if( (*it)->Second == Constraint::GeoUndef /*&& (*it)->Third == Constraint::GeoUndef*/) { + if( (*it)->Type != Sketcher::DistanceX && + (*it)->Type != Sketcher::DistanceY) { + + Constraint *constNew = (*it)->copy(); + + constNew->First = geoIdMap[(*it)->First]; + newconstrVals.push_back(constNew); + } + } + else { // other geoids intervene in this constraint + + std::vector::const_iterator sit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->Second); + + if(sit != geoIdList.end()) { // Second is also in the list + + if( (*it)->Third == Constraint::GeoUndef ) { + if((*it)->Type == Sketcher::Coincident || + (*it)->Type == Sketcher::Perpendicular || + (*it)->Type == Sketcher::Parallel || + (*it)->Type == Sketcher::Tangent || + (*it)->Type == Sketcher::Distance || + (*it)->Type == Sketcher::Equal || + (*it)->Type == Sketcher::Radius || + (*it)->Type == Sketcher::PointOnObject ){ + Constraint *constNew = (*it)->copy(); + + constNew->First = geoIdMap[(*it)->First]; + constNew->Second = geoIdMap[(*it)->Second]; + if(isStartEndInverted[(*it)->First]){ + if((*it)->FirstPos == Sketcher::start) + constNew->FirstPos = Sketcher::end; + else if((*it)->FirstPos == Sketcher::end) + constNew->FirstPos = Sketcher::start; + } + if(isStartEndInverted[(*it)->Second]){ + if((*it)->SecondPos == Sketcher::start) + constNew->SecondPos = Sketcher::end; + else if((*it)->SecondPos == Sketcher::end) + constNew->SecondPos = Sketcher::start; + } + + if (constNew->Type == Tangent || constNew->Type == Perpendicular) + AutoLockTangencyAndPerpty(constNew,true); + + newconstrVals.push_back(constNew); + } + } + else { + std::vector::const_iterator tit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->Third); + + if(tit != geoIdList.end()) { // Third is also in the list + Constraint *constNew = (*it)->copy(); + constNew->First = geoIdMap[(*it)->First]; + constNew->Second = geoIdMap[(*it)->Second]; + constNew->Third = geoIdMap[(*it)->Third]; + if(isStartEndInverted[(*it)->First]){ + if((*it)->FirstPos == Sketcher::start) + constNew->FirstPos = Sketcher::end; + else if((*it)->FirstPos == Sketcher::end) + constNew->FirstPos = Sketcher::start; + } + if(isStartEndInverted[(*it)->Second]){ + if((*it)->SecondPos == Sketcher::start) + constNew->SecondPos = Sketcher::end; + else if((*it)->SecondPos == Sketcher::end) + constNew->SecondPos = Sketcher::start; + } + if(isStartEndInverted[(*it)->Third]){ + if((*it)->ThirdPos == Sketcher::start) + constNew->ThirdPos = Sketcher::end; + else if((*it)->ThirdPos == Sketcher::end) + constNew->ThirdPos = Sketcher::start; + } + newconstrVals.push_back(constNew); + } + } + } + } + } + } + + if( newconstrVals.size() > constrvals.size() ) + Constraints.setValues(newconstrVals); + + return Geometry.getSize()-1; +} + +int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3d& displacement, bool clone /*=false*/, int csize/*=2*/, int rsize/*=1*/, + bool constraindisplacement /*= false*/, double perpscale /*= 1.0*/) +{ + const std::vector< Part::Geometry * > &geovals = getInternalGeometry(); + std::vector< Part::Geometry * > newgeoVals(geovals); + + const std::vector< Constraint * > &constrvals = this->Constraints.getValues(); + std::vector< Constraint * > newconstrVals(constrvals); + + int cgeoid = getHighestCurveIndex()+1; + + int iterfirstgeoid = -1 ; + + Base::Vector3d iterfirstpoint; + + int refgeoid = -1; + + int colrefgeoid = 0, rowrefgeoid = 0; + + int currentrowfirstgeoid= -1, prevrowstartfirstgeoid = -1, prevfirstgeoid = -1; + + Sketcher::PointPos refposId = Sketcher::none; + + std::map geoIdMap; + + Base::Vector3d perpendicularDisplacement = Base::Vector3d(perpscale*displacement.y,perpscale*-displacement.x,0); + + int x,y; + + for (y=0;ygetTypeId() == Part::GeomCircle::getClassTypeId() || + geo->getTypeId() == Part::GeomEllipse::getClassTypeId() ){ + refposId = Sketcher::mid; + } + else + refposId = Sketcher::start; + + continue; // the first element is already in place + } + else { + prevfirstgeoid = iterfirstgeoid; + + iterfirstgeoid = cgeoid; + + if( x == 0 ) { // if first element of second row + prevrowstartfirstgeoid = currentrowfirstgeoid; + currentrowfirstgeoid = cgeoid; + } + } + + for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) { + const Part::Geometry *geo = getGeometry(*it); + Part::Geometry *geocopy = geo->clone(); + + // Handle Geometry + if(geocopy->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ + Part::GeomLineSegment *geosymline = static_cast(geocopy); + Base::Vector3d ep = geosymline->getEndPoint(); + Base::Vector3d ssp = geosymline->getStartPoint()+double(x)*displacement+double(y)*perpendicularDisplacement; + + geosymline->setPoints( ssp, + ep+double(x)*displacement+double(y)*perpendicularDisplacement); + + if(it == geoIdList.begin()) + iterfirstpoint = ssp; + } + else if(geocopy->getTypeId() == Part::GeomCircle::getClassTypeId()){ + Part::GeomCircle *geosymcircle = static_cast(geocopy); + Base::Vector3d cp = geosymcircle->getCenter(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + + geosymcircle->setCenter(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = scp; + } + else if(geocopy->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + Part::GeomArcOfCircle *geoaoc = static_cast(geocopy); + Base::Vector3d cp = geoaoc->getCenter(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + + geoaoc->setCenter(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = geoaoc->getStartPoint(true); + } + else if(geocopy->getTypeId() == Part::GeomEllipse::getClassTypeId()){ + Part::GeomEllipse *geosymellipse = static_cast(geocopy); + Base::Vector3d cp = geosymellipse->getCenter(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + + geosymellipse->setCenter(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = scp; + } + else if(geocopy->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()){ + Part::GeomArcOfEllipse *geoaoe = static_cast(geocopy); + Base::Vector3d cp = geoaoe->getCenter(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + + geoaoe->setCenter(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = geoaoe->getStartPoint(true); + } + else if(geocopy->getTypeId() == Part::GeomPoint::getClassTypeId()){ + Part::GeomPoint *geopoint = static_cast(geocopy); + Base::Vector3d cp = geopoint->getPoint(); + Base::Vector3d scp = cp+double(x)*displacement+double(y)*perpendicularDisplacement; + geopoint->setPoint(scp); + + if(it == geoIdList.begin()) + iterfirstpoint = scp; + } + else { + Base::Console().Error("Unsupported Geometry!! Just skipping it.\n"); + continue; + } + + newgeoVals.push_back(geocopy); + geoIdMap.insert(std::make_pair(*it, cgeoid)); + cgeoid++; + } + + // handle geometry constraints + for (std::vector::const_iterator it = constrvals.begin(); it != constrvals.end(); ++it) { + + std::vector::const_iterator fit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->First); + + if(fit != geoIdList.end()) { // if First of constraint is in geoIdList + + if( (*it)->Second == Constraint::GeoUndef /*&& (*it)->Third == Constraint::GeoUndef*/) { + if( ((*it)->Type != Sketcher::DistanceX && (*it)->Type != Sketcher::DistanceY ) || + (*it)->FirstPos == Sketcher::none ) { // if it is not a point locking DistanceX/Y + if (((*it)->Type == Sketcher::DistanceX || + (*it)->Type == Sketcher::DistanceY || + (*it)->Type == Sketcher::Distance || + (*it)->Type == Sketcher::Radius ) && clone ) { + // Distances on a single Element are mapped to equality constraints in clone mode + Constraint *constNew = (*it)->copy(); + constNew->Type = Sketcher::Equal; + constNew->Second = geoIdMap[(*it)->First]; // first is already (*it->First) + newconstrVals.push_back(constNew); + } + else if ((*it)->Type == Sketcher::Angle && clone){ + // Angles on a single Element are mapped to parallel constraints in clone mode + Constraint *constNew = (*it)->copy(); + constNew->Type = Sketcher::Parallel; + constNew->Second = geoIdMap[(*it)->First]; // first is already (*it->First) + newconstrVals.push_back(constNew); + } + else { + Constraint *constNew = (*it)->copy(); + constNew->First = geoIdMap[(*it)->First]; + newconstrVals.push_back(constNew); + } + } + } + else { // other geoids intervene in this constraint + + std::vector::const_iterator sit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->Second); + + if(sit != geoIdList.end()) { // Second is also in the list + if( (*it)->Third == Constraint::GeoUndef ) { + if (((*it)->Type == Sketcher::DistanceX || + (*it)->Type == Sketcher::DistanceY || + (*it)->Type == Sketcher::Distance) && ((*it)->First == (*it)->Second) && clone ) { + // Distances on a two Elements, which must be points of the same line are mapped to equality constraints in clone mode + Constraint *constNew = (*it)->copy(); + constNew->Type = Sketcher::Equal; + constNew->FirstPos = Sketcher::none; + constNew->Second = geoIdMap[(*it)->First]; // first is already (*it->First) + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + } + else { + Constraint *constNew = (*it)->copy(); + constNew->First = geoIdMap[(*it)->First]; + constNew->Second = geoIdMap[(*it)->Second]; + newconstrVals.push_back(constNew); + } + } + else { + std::vector::const_iterator tit=std::find(geoIdList.begin(), geoIdList.end(), (*it)->Third); + + if(tit != geoIdList.end()) { // Third is also in the list + Constraint *constNew = (*it)->copy(); + constNew->First = geoIdMap[(*it)->First]; + constNew->Second = geoIdMap[(*it)->Second]; + constNew->Third = geoIdMap[(*it)->Third]; + + newconstrVals.push_back(constNew); + } + } + } + } + } + } + + // handle inter-geometry constraints + if(constraindisplacement){ + + // add a construction line + Part::GeomLineSegment *constrline= new Part::GeomLineSegment(); + + Base::Vector3d sp = getPoint(refgeoid,refposId)+ ( ( x == 0 )? + (double(x)*displacement+double(y-1)*perpendicularDisplacement): + (double(x-1)*displacement+double(y)*perpendicularDisplacement)); // position of the reference point + Base::Vector3d ep = iterfirstpoint; // position of the current instance corresponding point + constrline->setPoints(sp,ep); + constrline->Construction=true; + + newgeoVals.push_back(constrline); + + Constraint *constNew; + + if(x == 0) { // first element of a row + + // add coincidents for construction line + constNew = new Constraint(); + constNew->Type = Sketcher::Coincident; + constNew->First = prevrowstartfirstgeoid; + constNew->FirstPos = refposId; + constNew->Second = cgeoid; + constNew->SecondPos = Sketcher::start; + newconstrVals.push_back(constNew); + + constNew = new Constraint(); + constNew->Type = Sketcher::Coincident; + constNew->First = iterfirstgeoid; + constNew->FirstPos = refposId; + constNew->Second = cgeoid; + constNew->SecondPos = Sketcher::end; + newconstrVals.push_back(constNew); + + if( y == 1 ) { // it is the first added element of this row in the perpendicular to displacementvector direction + rowrefgeoid = cgeoid; + cgeoid++; + + // add length (or equal if perpscale==1) and perpendicular + if(perpscale==1.0) { + constNew = new Constraint(); + constNew->Type = Sketcher::Equal; + constNew->First = rowrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->Second = colrefgeoid; + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + } else { + constNew = new Constraint(); + constNew->Type = Sketcher::Distance; + constNew->First = rowrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->setValue(perpendicularDisplacement.Length()); + newconstrVals.push_back(constNew); + } + + constNew = new Constraint(); + constNew->Type = Sketcher::Perpendicular; + constNew->First = rowrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->Second = colrefgeoid; + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + } + else { // it is just one more element in the col direction + cgeoid++; + + // all other first rowers get an equality and perpendicular constraint + constNew = new Constraint(); + constNew->Type = Sketcher::Equal; + constNew->First = rowrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->Second = cgeoid-1; + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + + constNew = new Constraint(); + constNew->Type = Sketcher::Perpendicular; + constNew->First = cgeoid-1; + constNew->FirstPos = Sketcher::none; + constNew->Second = colrefgeoid; + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + } + } + else { // any element not being the first element of a row + + // add coincidents for construction line + constNew = new Constraint(); + constNew->Type = Sketcher::Coincident; + constNew->First = prevfirstgeoid; + constNew->FirstPos = refposId; + constNew->Second = cgeoid; + constNew->SecondPos = Sketcher::start; + newconstrVals.push_back(constNew); + + constNew = new Constraint(); + constNew->Type = Sketcher::Coincident; + constNew->First = iterfirstgeoid; + constNew->FirstPos = refposId; + constNew->Second = cgeoid; + constNew->SecondPos = Sketcher::end; + newconstrVals.push_back(constNew); + + if(y == 0 && x == 1) { // first element of the first row + colrefgeoid = cgeoid; + cgeoid++; + + // add length and Angle + constNew = new Constraint(); + constNew->Type = Sketcher::Distance; + constNew->First = colrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->setValue(displacement.Length()); + newconstrVals.push_back(constNew); + + constNew = new Constraint(); + constNew->Type = Sketcher::Angle; + constNew->First = colrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->setValue(atan2(displacement.y,displacement.x)); + newconstrVals.push_back(constNew); + } + else { // any other element + cgeoid++; + + // all other elements get an equality and parallel constraint + constNew = new Constraint(); + constNew->Type = Sketcher::Equal; + constNew->First = colrefgeoid; + constNew->FirstPos = Sketcher::none; + constNew->Second = cgeoid-1; + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + + constNew = new Constraint(); + constNew->Type = Sketcher::Parallel; + constNew->First = cgeoid-1; + constNew->FirstPos = Sketcher::none; + constNew->Second = colrefgeoid; + constNew->SecondPos = Sketcher::none; + newconstrVals.push_back(constNew); + } + } + } + + geoIdMap.clear(); // after each creation reset map so that the key-value is univoque + } + } + + Geometry.setValues(newgeoVals); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + + if( newconstrVals.size() > constrvals.size() ) + Constraints.setValues(newconstrVals); + + return Geometry.getSize()-1; + +} + +int SketchObject::ExposeInternalGeometry(int GeoId) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; + + const Part::Geometry *geo = getGeometry(GeoId); + // Only for supported types + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + // First we search what has to be restored + bool major=false; + bool minor=false; + bool focus1=false; + bool focus2=false; + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + major=true; + break; + case Sketcher::EllipseMinorDiameter: + minor=true; + break; + case Sketcher::EllipseFocus1: + focus1=true; + break; + case Sketcher::EllipseFocus2: + focus2=true; + break; + default: + return -1; + } + } + } + + int currentgeoid= getHighestCurveIndex(); + int incrgeo= 0; + + Base::Vector3d center; + double majord; + double minord; + Base::Vector3d majdir; + + std::vector igeo; + std::vector icon; + + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId()){ + const Part::GeomEllipse *ellipse = static_cast(geo); + + center=ellipse->getCenter(); + majord=ellipse->getMajorRadius(); + minord=ellipse->getMinorRadius(); + majdir=ellipse->getMajorAxisDir(); + } + else { + const Part::GeomArcOfEllipse *aoe = static_cast(geo); + + center=aoe->getCenter(); + majord=aoe->getMajorRadius(); + minord=aoe->getMinorRadius(); + majdir=aoe->getMajorAxisDir(); + } + + Base::Vector3d mindir = Vector3d(-majdir.y, majdir.x); + + Base::Vector3d majorpositiveend = center + majord * majdir; + Base::Vector3d majornegativeend = center - majord * majdir; + Base::Vector3d minorpositiveend = center + minord * mindir; + Base::Vector3d minornegativeend = center - minord * mindir; + + double df= sqrt(majord*majord-minord*minord); + + Base::Vector3d focus1P = center + df * majdir; + Base::Vector3d focus2P = center - df * majdir; + + if(!major) + { + Part::GeomLineSegment *lmajor = new Part::GeomLineSegment(); + lmajor->setPoints(majorpositiveend,majornegativeend); + + igeo.push_back(lmajor); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMajorDiameter; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->Second = GeoId; + + icon.push_back(newConstr); + incrgeo++; + } + if(!minor) + { + Part::GeomLineSegment *lminor = new Part::GeomLineSegment(); + lminor->setPoints(minorpositiveend,minornegativeend); + + igeo.push_back(lminor); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseMinorDiameter; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->Second = GeoId; + + icon.push_back(newConstr); + incrgeo++; + } + if(!focus1) + { + Part::GeomPoint *pf1 = new Part::GeomPoint(); + pf1->setPoint(focus1P); + + igeo.push_back(pf1); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus1; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->FirstPos = Sketcher::start; + newConstr->Second = GeoId; + + icon.push_back(newConstr); + incrgeo++; + } + if(!focus2) + { + Part::GeomPoint *pf2 = new Part::GeomPoint(); + pf2->setPoint(focus2P); + igeo.push_back(pf2); + + Sketcher::Constraint *newConstr = new Sketcher::Constraint(); + newConstr->Type = Sketcher::InternalAlignment; + newConstr->AlignmentType = EllipseFocus2; + newConstr->First = currentgeoid+incrgeo+1; + newConstr->FirstPos = Sketcher::start; + newConstr->Second = GeoId; + + icon.push_back(newConstr); + } + + this->addGeometry(igeo,true); + this->addConstraints(icon); + + for (std::vector::iterator it=igeo.begin(); it != igeo.end(); ++it) + if (*it) + delete *it; + + for (std::vector::iterator it=icon.begin(); it != icon.end(); ++it) + if (*it) + delete *it; + + icon.clear(); + igeo.clear(); + + return incrgeo; //number of added elements + } + else + return -1; // not supported type +} + +int SketchObject::DeleteUnusedInternalGeometry(int GeoId) +{ + if (GeoId < 0 || GeoId > getHighestCurveIndex()) + return -1; + + const Part::Geometry *geo = getGeometry(GeoId); + // Only for supported types + if(geo->getTypeId() == Part::GeomEllipse::getClassTypeId() || geo->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + + int majorelementindex=-1; + int minorelementindex=-1; + int focus1elementindex=-1; + int focus2elementindex=-1; + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + if((*it)->Type == Sketcher::InternalAlignment && (*it)->Second == GeoId) + { + switch((*it)->AlignmentType){ + case Sketcher::EllipseMajorDiameter: + majorelementindex=(*it)->First; + break; + case Sketcher::EllipseMinorDiameter: + minorelementindex=(*it)->First; + break; + case Sketcher::EllipseFocus1: + focus1elementindex=(*it)->First; + break; + case Sketcher::EllipseFocus2: + focus2elementindex=(*it)->First; + break; + default: + return -1; + } + } + } + + // Hide unused geometry here + int majorconstraints=0; // number of constraints associated to the geoid of the major axis + int minorconstraints=0; + int focus1constraints=0; + int focus2constraints=0; + + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin(); + it != vals.end(); ++it) { + + if((*it)->Second == majorelementindex || (*it)->First == majorelementindex || (*it)->Third == majorelementindex) + majorconstraints++; + else if((*it)->Second == minorelementindex || (*it)->First == minorelementindex || (*it)->Third == minorelementindex) + minorconstraints++; + else if((*it)->Second == focus1elementindex || (*it)->First == focus1elementindex || (*it)->Third == focus1elementindex) + focus1constraints++; + else if((*it)->Second == focus2elementindex || (*it)->First == focus2elementindex || (*it)->Third == focus2elementindex) + focus2constraints++; + } + + std::vector delgeometries; + + // those with less than 2 constraints must be removed + if(focus2constraints<2) + delgeometries.push_back(focus2elementindex); + + if(focus1constraints<2) + delgeometries.push_back(focus1elementindex); + + if(minorconstraints<2) + delgeometries.push_back(minorelementindex); + + if(majorconstraints<2) + delgeometries.push_back(majorelementindex); + + std::sort(delgeometries.begin(), delgeometries.end()); // indices over an erased element get automatically updated!! + + if(delgeometries.size()>0) + { + for (std::vector::reverse_iterator it=delgeometries.rbegin(); it!=delgeometries.rend(); ++it) { + delGeometry(*it); + } + } + + return delgeometries.size(); //number of deleted elements + } + else + return -1; // not supported type +} + +int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) +{ + // so far only externals to the support of the sketch and datum features + if (Support.getValue() != Obj) + if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) && + !Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + return -1; + + // get the actual lists of the externals + std::vector Objects = ExternalGeometry.getValues(); + std::vector SubElements = ExternalGeometry.getSubValues(); + + const std::vector originalObjects = Objects; + const std::vector originalSubElements = SubElements; + + std::vector::iterator it; + it = std::find(SubElements.begin(), SubElements.end(), SubName); + + // avoid duplicates + if (it != SubElements.end()) + return -1; + + // add the new ones + Objects.push_back(Obj); + SubElements.push_back(std::string(SubName)); + + // set the Link list. + ExternalGeometry.setValues(Objects,SubElements); + try { + rebuildExternalGeometry(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + // revert to original values + ExternalGeometry.setValues(originalObjects,originalSubElements); + return -1; + } + + solverNeedsUpdate=true; + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + return ExternalGeometry.getValues().size()-1; +} + +int SketchObject::delExternal(int ExtGeoId) +{ + // get the actual lists of the externals + std::vector Objects = ExternalGeometry.getValues(); + std::vector SubElements = ExternalGeometry.getSubValues(); + + if (ExtGeoId < 0 || ExtGeoId >= int(SubElements.size())) + return -1; + + const std::vector originalObjects = Objects; + const std::vector originalSubElements = SubElements; + + Objects.erase(Objects.begin()+ExtGeoId); + SubElements.erase(SubElements.begin()+ExtGeoId); + + const std::vector< Constraint * > &constraints = Constraints.getValues(); + std::vector< Constraint * > newConstraints(0); + int GeoId = -3 - ExtGeoId; + for (std::vector::const_iterator it = constraints.begin(); + it != constraints.end(); ++it) { + if ((*it)->First != GeoId && (*it)->Second != GeoId && (*it)->Third != GeoId) { + Constraint *copiedConstr = (*it)->clone(); + if (copiedConstr->First < GeoId && + copiedConstr->First != Constraint::GeoUndef) + copiedConstr->First += 1; + if (copiedConstr->Second < GeoId && + copiedConstr->Second != Constraint::GeoUndef) + copiedConstr->Second += 1; + if (copiedConstr->Third < GeoId && + copiedConstr->Third != Constraint::GeoUndef) + copiedConstr->Third += 1; + + newConstraints.push_back(copiedConstr); + } + } + + ExternalGeometry.setValues(Objects,SubElements); + try { + rebuildExternalGeometry(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + // revert to original values + ExternalGeometry.setValues(originalObjects,originalSubElements); + return -1; + } + + solverNeedsUpdate=true; + Constraints.setValues(newConstraints); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + return 0; +} + +int SketchObject::delAllExternal() +{ + // get the actual lists of the externals + std::vector Objects = ExternalGeometry.getValues(); + std::vector SubElements = ExternalGeometry.getSubValues(); + + const std::vector originalObjects = Objects; + const std::vector originalSubElements = SubElements; + + Objects.clear(); + + SubElements.clear(); + + const std::vector< Constraint * > &constraints = Constraints.getValues(); + std::vector< Constraint * > newConstraints(0); + + for (std::vector::const_iterator it = constraints.begin(); it != constraints.end(); ++it) { + if ((*it)->First > -3 && + ((*it)->Second > -3 || (*it)->Second == Constraint::GeoUndef ) && + ((*it)->Third > -3 || (*it)->Third == Constraint::GeoUndef) ) { + Constraint *copiedConstr = (*it)->clone(); + + newConstraints.push_back(copiedConstr); + } + } + + ExternalGeometry.setValues(Objects,SubElements); + try { + rebuildExternalGeometry(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + // revert to original values + ExternalGeometry.setValues(originalObjects,originalSubElements); + return -1; + } + + solverNeedsUpdate=true; + Constraints.setValues(newConstraints); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + return 0; +} + +int SketchObject::delConstraintsToExternal() +{ + const std::vector< Constraint * > &constraints = Constraints.getValuesForce(); + std::vector< Constraint * > newConstraints(0); + int GeoId = -3, NullId = -2000; + for (std::vector::const_iterator it = constraints.begin(); + it != constraints.end(); ++it) { + if ( (*it)->First > GeoId + && + ((*it)->Second > GeoId || (*it)->Second == NullId) + && + ((*it)->Third > GeoId || (*it)->Third == NullId)) { + newConstraints.push_back(*it); + } + } + + Constraints.setValues(newConstraints); + Constraints.acceptGeometry(getCompleteGeometry()); + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver + solve(); + + return 0; +} + +const Part::Geometry* SketchObject::getGeometry(int GeoId) const +{ + if (GeoId >= 0) { + const std::vector &geomlist = getInternalGeometry(); + if (GeoId < int(geomlist.size())) + return geomlist[GeoId]; + } + else if (GeoId <= -1 && -GeoId <= int(ExternalGeo.size())) + return ExternalGeo[-GeoId-1]; + + return 0; +} + +// Auxiliary method +Part::Geometry* projectLine(const BRepAdaptor_Curve& curve, const Handle(Geom_Plane)& gPlane, const Base::Placement& invPlm) +{ + double first = curve.FirstParameter(); + bool infinite = false; + if (fabs(first) > 1E99) { + // TODO: What is OCE's definition of Infinite? + // TODO: The clean way to do this is to handle a new sketch geometry Geom::Line + // but its a lot of work to implement... + first = -10000; + //infinite = true; + } + double last = curve.LastParameter(); + if (fabs(last) > 1E99) { + last = +10000; + //infinite = true; + } + + gp_Pnt P1 = curve.Value(first); + gp_Pnt P2 = curve.Value(last); + + GeomAPI_ProjectPointOnSurf proj1(P1,gPlane); + P1 = proj1.NearestPoint(); + GeomAPI_ProjectPointOnSurf proj2(P2,gPlane); + P2 = proj2.NearestPoint(); + + Base::Vector3d p1(P1.X(),P1.Y(),P1.Z()); + Base::Vector3d p2(P2.X(),P2.Y(),P2.Z()); + invPlm.multVec(p1,p1); + invPlm.multVec(p2,p2); + + if (Base::Distance(p1,p2) < Precision::Confusion()) { + Base::Vector3d p = (p1 + p2) / 2; + Part::GeomPoint* point = new Part::GeomPoint(p); + point->Construction = true; + return point; + } + else if (!infinite) { + Part::GeomLineSegment* line = new Part::GeomLineSegment(); + line->setPoints(p1,p2); + line->Construction = true; + return line; + } else { + Part::GeomLine* line = new Part::GeomLine(); + line->setLine(p1, p2 - p1); + line->Construction = true; + return line; + } +} + +bool SketchObject::evaluateSupport(void) +{ + // returns false if the shape if broken, null or non-planar + Part::Feature *part = static_cast(Support.getValue()); + if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return false; + + const std::vector &sub = Support.getSubValues(); + assert(sub.size()==1); + // get the selected sub shape (a Face) + const Part::TopoShape &shape = part->Shape.getShape(); + + if (shape._Shape.IsNull()) + return false; + + TopoDS_Shape sh; + try { + sh = shape.getSubShape(sub[0].c_str()); + } + catch (Standard_Failure) { + return false; + } + const TopoDS_Face &face = TopoDS::Face(sh); + if (face.IsNull()) + return false; + + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() != GeomAbs_Plane) + return false; // No planar face + + return true; +} + +void SketchObject::validateExternalLinks(void) +{ + std::vector Objects = ExternalGeometry.getValues(); + std::vector SubElements = ExternalGeometry.getSubValues(); + + bool rebuild = false ; + + for (int i=0; i < int(Objects.size()); i++) { + const App::DocumentObject *Obj=Objects[i]; + const std::string SubElement=SubElements[i]; + + const Part::Feature *refObj=static_cast(Obj); + const Part::TopoShape& refShape=refObj->Shape.getShape(); + + TopoDS_Shape refSubShape; + try { + refSubShape = refShape.getSubShape(SubElement.c_str()); + } + catch (Standard_Failure) { + rebuild = true ; + Objects.erase(Objects.begin()+i); + SubElements.erase(SubElements.begin()+i); + + const std::vector< Constraint * > &constraints = Constraints.getValues(); + std::vector< Constraint * > newConstraints(0); + int GeoId = -3 - i; + for (std::vector::const_iterator it = constraints.begin(); + it != constraints.end(); ++it) { + if ((*it)->First != GeoId && (*it)->Second != GeoId && (*it)->Third != GeoId) { + Constraint *copiedConstr = (*it)->clone(); + if (copiedConstr->First < GeoId && + copiedConstr->First != Constraint::GeoUndef) + copiedConstr->First += 1; + if (copiedConstr->Second < GeoId && + copiedConstr->Second != Constraint::GeoUndef) + copiedConstr->Second += 1; + if (copiedConstr->Third < GeoId && + copiedConstr->Third != Constraint::GeoUndef) + copiedConstr->Third += 1; + + newConstraints.push_back(copiedConstr); + } + } + + Constraints.setValues(newConstraints); + i--; // we deleted an item, so the next one took its place + } + } + + if (rebuild) { + ExternalGeometry.setValues(Objects,SubElements); + rebuildExternalGeometry(); + Constraints.acceptGeometry(getCompleteGeometry()); + rebuildVertexIndex(); + solve(true); // we have to update this sketch and everything depending on it. + } + +} + +void SketchObject::rebuildExternalGeometry(void) +{ + // get the actual lists of the externals + std::vector Objects = ExternalGeometry.getValues(); + std::vector SubElements = ExternalGeometry.getSubValues(); + + Base::Placement Plm = Placement.getValue(); + Base::Vector3d Pos = Plm.getPosition(); + Base::Rotation Rot = Plm.getRotation(); + Base::Vector3d dN(0,0,1); + Rot.multVec(dN,dN); + Base::Vector3d dX(1,0,0); + Rot.multVec(dX,dX); + + Base::Placement invPlm = Plm.inverse(); + Base::Matrix4D invMat = invPlm.toMatrix(); + gp_Trsf mov; + mov.SetValues(invMat[0][0],invMat[0][1],invMat[0][2],invMat[0][3], + invMat[1][0],invMat[1][1],invMat[1][2],invMat[1][3], + invMat[2][0],invMat[2][1],invMat[2][2],invMat[2][3] +#if OCC_VERSION_HEX < 0x060800 + , 0.00001, 0.00001 +#endif + ); //precision was removed in OCCT CR0025194 + + gp_Ax3 sketchAx3(gp_Pnt(Pos.x,Pos.y,Pos.z), + gp_Dir(dN.x,dN.y,dN.z), + gp_Dir(dX.x,dX.y,dX.z)); + gp_Pln sketchPlane(sketchAx3); + + Handle(Geom_Plane) gPlane = new Geom_Plane(sketchPlane); + BRepBuilderAPI_MakeFace mkFace(sketchPlane); + TopoDS_Shape aProjFace = mkFace.Shape(); + + for (std::vector::iterator it=ExternalGeo.begin(); it != ExternalGeo.end(); ++it) + if (*it) delete *it; + ExternalGeo.clear(); + Part::GeomLineSegment *HLine = new Part::GeomLineSegment(); + Part::GeomLineSegment *VLine = new Part::GeomLineSegment(); + HLine->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(1,0,0)); + VLine->setPoints(Base::Vector3d(0,0,0),Base::Vector3d(0,1,0)); + HLine->Construction = true; + VLine->Construction = true; + ExternalGeo.push_back(HLine); + ExternalGeo.push_back(VLine); + for (int i=0; i < int(Objects.size()); i++) { + const App::DocumentObject *Obj=Objects[i]; + const std::string SubElement=SubElements[i]; + + TopoDS_Shape refSubShape; + + if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + const Part::Datum* datum = static_cast(Obj); + refSubShape = datum->Shape.getValue(); + } else if (Obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + try { + const Part::Feature *refObj=static_cast(Obj); + const Part::TopoShape& refShape=refObj->Shape.getShape(); + refSubShape = refShape.getSubShape(SubElement.c_str()); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } + } else if (Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + const App::Plane* pl = static_cast(Obj); + Base::Placement plm = pl->Placement.getValue(); + Base::Vector3d base = plm.getPosition(); + Base::Rotation rot = plm.getRotation(); + Base::Vector3d normal(0,0,1); + rot.multVec(normal, normal); + gp_Pln plane(gp_Pnt(base.x,base.y,base.z), gp_Dir(normal.x, normal.y, normal.z)); + BRepBuilderAPI_MakeFace fBuilder(plane); + if (!fBuilder.IsDone()) + throw Base::Exception("Sketcher: addExternal(): Failed to build face from App::Plane"); + + TopoDS_Face f = TopoDS::Face(fBuilder.Shape()); + refSubShape = f; + } else { + throw Base::Exception("Datum feature type is not yet supported as external geometry for a sketch"); + } + + switch (refSubShape.ShapeType()) + { + case TopAbs_FACE: + { + const TopoDS_Face& face = TopoDS::Face(refSubShape); + BRepAdaptor_Surface surface(face); + if (surface.GetType() == GeomAbs_Plane) { + // Check that the plane is perpendicular to the sketch plane + Geom_Plane plane = surface.Plane(); + gp_Dir dnormal = plane.Axis().Direction(); + gp_Dir snormal = sketchPlane.Axis().Direction(); + if (fabs(dnormal.Angle(snormal) - M_PI_2) < Precision::Confusion()) { + // Get vector that is normal to both sketch plane normal and plane normal. This is the line's direction + gp_Dir lnormal = dnormal.Crossed(snormal); + BRepBuilderAPI_MakeEdge builder(gp_Lin(plane.Location(), lnormal)); + builder.Build(); + if (builder.IsDone()) { + const TopoDS_Edge& edge = TopoDS::Edge(builder.Shape()); + BRepAdaptor_Curve curve(edge); + if (curve.GetType() == GeomAbs_Line) { + ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); + } + } + + } + } else { + throw Base::Exception("Non-planar faces are not yet supported for external geometry of sketches"); + } + } + break; + case TopAbs_EDGE: + { + const TopoDS_Edge& edge = TopoDS::Edge(refSubShape); + BRepAdaptor_Curve curve(edge); + if (curve.GetType() == GeomAbs_Line) { + ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); + } + else if (curve.GetType() == GeomAbs_Circle) { + gp_Dir vec1 = sketchPlane.Axis().Direction(); + gp_Dir vec2 = curve.Circle().Axis().Direction(); + if (vec1.IsParallel(vec2, Precision::Confusion())) { + gp_Circ circle = curve.Circle(); + gp_Pnt cnt = circle.Location(); + gp_Pnt beg = curve.Value(curve.FirstParameter()); + gp_Pnt end = curve.Value(curve.LastParameter()); + + GeomAPI_ProjectPointOnSurf proj(cnt,gPlane); + cnt = proj.NearestPoint(); + circle.SetLocation(cnt); + cnt.Transform(mov); + circle.Transform(mov); + + if (beg.SquareDistance(end) < Precision::Confusion()) { + Part::GeomCircle* gCircle = new Part::GeomCircle(); + gCircle->setRadius(circle.Radius()); + gCircle->setCenter(Base::Vector3d(cnt.X(),cnt.Y(),cnt.Z())); + + gCircle->Construction = true; + ExternalGeo.push_back(gCircle); + } + else { + Part::GeomArcOfCircle* gArc = new Part::GeomArcOfCircle(); + Handle_Geom_Curve hCircle = new Geom_Circle(circle); + Handle_Geom_TrimmedCurve tCurve = new Geom_TrimmedCurve(hCircle, curve.FirstParameter(), + curve.LastParameter()); + gArc->setHandle(tCurve); + gArc->Construction = true; + ExternalGeo.push_back(gArc); + } + } + else { + // creates an ellipse + throw Base::Exception("Not yet supported geometry for external geometry"); + } + } + else { + try { + BRepOffsetAPI_NormalProjection mkProj(aProjFace); + mkProj.Add(edge); + mkProj.Build(); + const TopoDS_Shape& projShape = mkProj.Projection(); + if (!projShape.IsNull()) { + TopExp_Explorer xp; + for (xp.Init(projShape, TopAbs_EDGE); xp.More(); xp.Next()) { + TopoDS_Edge projEdge = TopoDS::Edge(xp.Current()); + TopLoc_Location loc(mov); + projEdge.Location(loc); + BRepAdaptor_Curve projCurve(projEdge); + if (projCurve.GetType() == GeomAbs_Line) { + gp_Pnt P1 = projCurve.Value(projCurve.FirstParameter()); + gp_Pnt P2 = projCurve.Value(projCurve.LastParameter()); + Base::Vector3d p1(P1.X(),P1.Y(),P1.Z()); + Base::Vector3d p2(P2.X(),P2.Y(),P2.Z()); + + if (Base::Distance(p1,p2) < Precision::Confusion()) { + Base::Vector3d p = (p1 + p2) / 2; + Part::GeomPoint* point = new Part::GeomPoint(p); + point->Construction = true; + ExternalGeo.push_back(point); + } + else { + Part::GeomLineSegment* line = new Part::GeomLineSegment(); + line->setPoints(p1,p2); + line->Construction = true; + ExternalGeo.push_back(line); + } + } + else if (projCurve.GetType() == GeomAbs_Circle) { + gp_Circ c = projCurve.Circle(); + gp_Pnt p = c.Location(); + gp_Pnt P1 = projCurve.Value(projCurve.FirstParameter()); + gp_Pnt P2 = projCurve.Value(projCurve.LastParameter()); + + if (P1.SquareDistance(P2) < Precision::Confusion()) { + Part::GeomCircle* circle = new Part::GeomCircle(); + circle->setRadius(c.Radius()); + circle->setCenter(Base::Vector3d(p.X(),p.Y(),p.Z())); + + circle->Construction = true; + ExternalGeo.push_back(circle); + } + else { + Part::GeomArcOfCircle* arc = new Part::GeomArcOfCircle(); + Handle_Geom_Curve curve = new Geom_Circle(c); + Handle_Geom_TrimmedCurve tCurve = new Geom_TrimmedCurve(curve, projCurve.FirstParameter(), + projCurve.LastParameter()); + arc->setHandle(tCurve); + arc->Construction = true; + ExternalGeo.push_back(arc); + } + } + else if (projCurve.GetType() == GeomAbs_Ellipse) { + gp_Elips e = projCurve.Ellipse(); + gp_Pnt p = e.Location(); + gp_Pnt P1 = projCurve.Value(projCurve.FirstParameter()); + gp_Pnt P2 = projCurve.Value(projCurve.LastParameter()); + + //gp_Dir normal = e.Axis().Direction(); + gp_Dir normal = gp_Dir(0,0,1); + gp_Ax2 xdirref(p, normal); + + if (P1.SquareDistance(P2) < Precision::Confusion()) { + Part::GeomEllipse* ellipse = new Part::GeomEllipse(); + Handle_Geom_Ellipse curve = new Geom_Ellipse(e); + ellipse->setHandle(curve); + ellipse->Construction = true; + ExternalGeo.push_back(ellipse); + } + else { + Part::GeomArcOfEllipse* aoe = new Part::GeomArcOfEllipse(); + Handle_Geom_Curve curve = new Geom_Ellipse(e); + Handle_Geom_TrimmedCurve tCurve = new Geom_TrimmedCurve(curve, projCurve.FirstParameter(), + projCurve.LastParameter()); + aoe->setHandle(tCurve); + aoe->Construction = true; + ExternalGeo.push_back(aoe); + } + } + else { + throw Base::Exception("Not yet supported geometry for external geometry"); + } + } + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Base::Exception(e->GetMessageString()); + } + } + } + break; + case TopAbs_VERTEX: + { + gp_Pnt P = BRep_Tool::Pnt(TopoDS::Vertex(refSubShape)); + GeomAPI_ProjectPointOnSurf proj(P,gPlane); + P = proj.NearestPoint(); + Base::Vector3d p(P.X(),P.Y(),P.Z()); + invPlm.multVec(p,p); + + Part::GeomPoint* point = new Part::GeomPoint(p); + point->Construction = true; + ExternalGeo.push_back(point); + } + break; + default: + throw Base::Exception("Unknown type of geometry"); + break; + } + } + + rebuildVertexIndex(); +} + +std::vector SketchObject::getCompleteGeometry(void) const +{ + std::vector vals=getInternalGeometry(); + vals.insert(vals.end(), ExternalGeo.rbegin(), ExternalGeo.rend()); // in reverse order + return vals; +} + +void SketchObject::rebuildVertexIndex(void) +{ + VertexId2GeoId.resize(0); + VertexId2PosId.resize(0); + int imax=getHighestCurveIndex(); + int i=0; + const std::vector< Part::Geometry * > geometry = getCompleteGeometry(); + if (geometry.size() <= 2) + return; + for (std::vector< Part::Geometry * >::const_iterator it = geometry.begin(); + it != geometry.end()-2; ++it, i++) { + if (i > imax) + i = -getExternalGeometryCount(); + if ((*it)->getTypeId() == Part::GeomPoint::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + } else if ((*it)->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(end); + } else if ((*it)->getTypeId() == Part::GeomCircle::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomEllipse::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(end); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); + } else if ((*it)->getTypeId() == Part::GeomArcOfEllipse::getClassTypeId()) { + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(start); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(end); + VertexId2GeoId.push_back(i); + VertexId2PosId.push_back(mid); + } + } +} + +const std::vector< std::map > SketchObject::getCoincidenceGroups() +{ + // this function is different from that in getCoincidentPoints in that: + // - getCoincidentPoints only considers direct coincidence (the points that are linked via a single coincidence) + // - this function provides an array of maps of points, each map containing the points that are coincident by virtue + // of any number of interrelated coincidence constraints (if coincidence 1-2 and coincidence 2-3, {1,2,3} are in that set) + + const std::vector< Sketcher::Constraint * > &vals = Constraints.getValues(); + + std::vector< std::map > coincidenttree; + // push the constraints + for (std::vector< Sketcher::Constraint * >::const_iterator it= vals.begin();it != vals.end(); ++it) { + if( (*it)->Type == Sketcher::Coincident ) { + int firstpresentin=-1; + int secondpresentin=-1; + + int i=0; + + for(std::vector< std::map >::const_iterator iti = coincidenttree.begin(); iti != coincidenttree.end(); ++iti,i++) { + // First + std::map::const_iterator filiterator; + filiterator = (*iti).find((*it)->First); + if( filiterator != (*iti).end()) { + if((*it)->FirstPos == (*filiterator).second) + firstpresentin = i; + } + // Second + filiterator = (*iti).find((*it)->Second); + if( filiterator != (*iti).end()) { + if((*it)->SecondPos == (*filiterator).second) + secondpresentin = i; + } + } + + if ( firstpresentin!=-1 && secondpresentin!=-1) { + // we have to merge those sets into one + coincidenttree[firstpresentin].insert(coincidenttree[secondpresentin].begin(), coincidenttree[secondpresentin].end()); + coincidenttree.erase(coincidenttree.begin()+secondpresentin); + } + else if ( firstpresentin==-1 && secondpresentin==-1 ) { + // we do not have any of the values, so create a setCursor + std::map tmp; + tmp.insert(std::pair((*it)->First,(*it)->FirstPos)); + tmp.insert(std::pair((*it)->Second,(*it)->SecondPos)); + coincidenttree.push_back(tmp); + } + else if ( firstpresentin != -1 ) { + // add to existing group + coincidenttree[firstpresentin].insert(std::pair((*it)->Second,(*it)->SecondPos)); + } + else { // secondpresentin != -1 + // add to existing group + coincidenttree[secondpresentin].insert(std::pair((*it)->First,(*it)->FirstPos)); + } + + } + } + + return coincidenttree; +} + +void SketchObject::isCoincidentWithExternalGeometry(int GeoId, bool &start_external, bool &mid_external, bool &end_external) { + + start_external=false; + mid_external=false; + end_external=false; + + const std::vector< std::map > coincidenttree = getCoincidenceGroups(); + + for(std::vector< std::map >::const_iterator it = coincidenttree.begin(); it != coincidenttree.end(); ++it) { + + std::map::const_iterator geoId1iterator; + + geoId1iterator = (*it).find(GeoId); + + if( geoId1iterator != (*it).end()) { + // If First is in this set and the first key in this ordered element key is external + if( (*it).begin()->first < 0 ) { + if( (*geoId1iterator).second == Sketcher::start ) + start_external=true; + else if ( (*geoId1iterator).second == Sketcher::mid ) + mid_external=true; + else if ( (*geoId1iterator).second == Sketcher::end ) + end_external=true; + } + } + } +} + +const std::map SketchObject::getAllCoincidentPoints(int GeoId, PointPos PosId) { + + const std::vector< std::map > coincidenttree = getCoincidenceGroups(); + + for(std::vector< std::map >::const_iterator it = coincidenttree.begin(); it != coincidenttree.end(); ++it) { + + std::map::const_iterator geoId1iterator; + + geoId1iterator = (*it).find(GeoId); + + if( geoId1iterator != (*it).end()) { + // If GeoId is in this set + + if ((*geoId1iterator).second == PosId) // and posId matches + return (*it); + } + } + + std::map empty; + + return empty; +} + + +void SketchObject::getDirectlyCoincidentPoints(int GeoId, PointPos PosId, std::vector &GeoIdList, + std::vector &PosIdList) +{ + const std::vector &constraints = this->Constraints.getValues(); + + GeoIdList.clear(); + PosIdList.clear(); + GeoIdList.push_back(GeoId); + PosIdList.push_back(PosId); + for (std::vector::const_iterator it=constraints.begin(); + it != constraints.end(); ++it) { + if ((*it)->Type == Sketcher::Coincident) { + if ((*it)->First == GeoId && (*it)->FirstPos == PosId) { + GeoIdList.push_back((*it)->Second); + PosIdList.push_back((*it)->SecondPos); + } + else if ((*it)->Second == GeoId && (*it)->SecondPos == PosId) { + GeoIdList.push_back((*it)->First); + PosIdList.push_back((*it)->FirstPos); + } + } + } + if (GeoIdList.size() == 1) { + GeoIdList.clear(); + PosIdList.clear(); + } +} + +void SketchObject::getDirectlyCoincidentPoints(int VertexId, std::vector &GeoIdList, + std::vector &PosIdList) +{ + int GeoId; + PointPos PosId; + getGeoVertexIndex(VertexId, GeoId, PosId); + getDirectlyCoincidentPoints(GeoId, PosId, GeoIdList, PosIdList); +} + +bool SketchObject::arePointsCoincident(int GeoId1, PointPos PosId1, + int GeoId2, PointPos PosId2) +{ + if (GeoId1 == GeoId2 && PosId1 == PosId2) + return true; + + const std::vector< std::map > coincidenttree = getCoincidenceGroups(); + + for(std::vector< std::map >::const_iterator it = coincidenttree.begin(); it != coincidenttree.end(); ++it) { + + std::map::const_iterator geoId1iterator; + + geoId1iterator = (*it).find(GeoId1); + + if( geoId1iterator != (*it).end()) { + // If First is in this set + std::map::const_iterator geoId2iterator; + + geoId2iterator = (*it).find(GeoId2); + + if( geoId2iterator != (*it).end()) { + // If Second is in this set + if ((*geoId1iterator).second == PosId1 && + (*geoId2iterator).second == PosId2) + return true; + } + } + } + + return false; +} + +void SketchObject::appendConflictMsg(const std::vector &conflicting, std::string &msg) +{ + std::stringstream ss; + if (msg.length() > 0) + ss << msg; + if (conflicting.size() > 0) { + if (conflicting.size() == 1) + ss << "Please remove the following constraint:\n"; + else + ss << "Please remove at least one of the following constraints:\n"; + ss << conflicting[0]; + for (unsigned int i=1; i < conflicting.size(); i++) + ss << ", " << conflicting[i]; + ss << "\n"; + } + msg = ss.str(); +} + +void SketchObject::appendRedundantMsg(const std::vector &redundant, std::string &msg) +{ + std::stringstream ss; + if (msg.length() > 0) + ss << msg; + if (redundant.size() > 0) { + if (redundant.size() == 1) + ss << "Please remove the following redundant constraint:\n"; + else + ss << "Please remove the following redundant constraints:\n"; + ss << redundant[0]; + for (unsigned int i=1; i < redundant.size(); i++) + ss << ", " << redundant[i]; + ss << "\n"; + } + msg = ss.str(); +} + +bool SketchObject::evaluateConstraint(const Constraint *constraint) const +{ + //if requireXXX, GeoUndef is treated as an error. If not requireXXX, + //GeoUndef is accepted. Index range checking is done on everything regardless. + bool requireFirst = true; + bool requireSecond = false; + bool requireThird = false; + + switch (constraint->Type) { + case Radius: + requireFirst = true; + break; + case Horizontal: + case Vertical: + requireFirst = true; + break; + case Distance: + case DistanceX: + case DistanceY: + requireFirst = true; + break; + case Coincident: + case Perpendicular: + case Parallel: + case Equal: + case PointOnObject: + case Tangent: + requireFirst = true; + requireSecond = true; + break; + case Symmetric: + requireFirst = true; + requireSecond = true; + requireThird = true; + break; + case Angle: + requireFirst = true; + break; + case SnellsLaw: + requireFirst = true; + requireSecond = true; + requireThird = true; + break; + default: + break; + } + + int intGeoCount = getHighestCurveIndex() + 1; + int extGeoCount = getExternalGeometryCount(); + + //the actual checks + bool ret = true; + int geoId; + geoId = constraint->First; + ret = ret && ((geoId == Constraint::GeoUndef && !requireFirst) + || + (geoId >= -extGeoCount && geoId < intGeoCount) ); + + geoId = constraint->Second; + ret = ret && ((geoId == Constraint::GeoUndef && !requireSecond) + || + (geoId >= -extGeoCount && geoId < intGeoCount) ); + + geoId = constraint->Third; + ret = ret && ((geoId == Constraint::GeoUndef && !requireThird) + || + (geoId >= -extGeoCount && geoId < intGeoCount) ); + + return ret; +} + +bool SketchObject::evaluateConstraints() const +{ + int intGeoCount = getHighestCurveIndex() + 1; + int extGeoCount = getExternalGeometryCount(); + + std::vector geometry = getCompleteGeometry(); + const std::vector& constraints = Constraints.getValuesForce(); + if (static_cast(geometry.size()) != extGeoCount + intGeoCount) + return false; + if (geometry.size() < 2) + return false; + + std::vector::const_iterator it; + for (it = constraints.begin(); it != constraints.end(); ++it) { + if (!evaluateConstraint(*it)) + return false; + } + + if(constraints.size()>0){ + if (!Constraints.scanGeometry(geometry)) return false; + } + + return true; +} + +void SketchObject::validateConstraints() +{ + std::vector geometry = getCompleteGeometry(); + const std::vector& constraints = Constraints.getValues(); + + std::vector newConstraints; + std::vector::const_iterator it; + for (it = constraints.begin(); it != constraints.end(); ++it) { + bool valid = evaluateConstraint(*it); + if (valid) + newConstraints.push_back(*it); + } + + if (newConstraints.size() != constraints.size()) { + Constraints.setValues(newConstraints); + acceptGeometry(); + } +} + +std::string SketchObject::validateExpression(const App::ObjectIdentifier &path, boost::shared_ptr expr) +{ + const App::Property * prop = path.getProperty(); + + assert(expr != 0); + + if (!prop) + return "Property not found"; + + if (prop == &Constraints) { + const Constraint * constraint = Constraints.getConstraint(path); + + if (!constraint->isDriving) + return "Reference constraints cannot be set!"; + } + + std::set deps; + expr->getDeps(deps); + + for (std::set::const_iterator i = deps.begin(); i != deps.end(); ++i) { + const App::Property * prop = (*i).getProperty(); + + if (prop == &Constraints) { + const Constraint * constraint = Constraints.getConstraint(*i); + + if (!constraint->isDriving) + return "Reference constraint from this sketch cannot be used in this expression."; + } + } + return ""; +} + +//This function is necessary for precalculation of an angle when adding +// an angle constraint. It is also used here, in SketchObject, to +// lock down the type of tangency/perpendicularity. +double SketchObject::calculateAngleViaPoint(int GeoId1, int GeoId2, double px, double py) +{ + // Temporary sketch based calculation. Slow, but guaranteed consistency with constraints. + Sketcher::Sketch sk; + + const Part::Geometry *p1=this->getGeometry(GeoId1); + const Part::Geometry *p2=this->getGeometry(GeoId2); + + if(p1!=0 && p2!=0) { + int i1 = sk.addGeometry(this->getGeometry(GeoId1)); + int i2 = sk.addGeometry(this->getGeometry(GeoId2)); + + return sk.calculateAngleViaPoint(i1,i2,px,py); + } + else + throw Base::Exception("Null geometry in calculateAngleViaPoint"); + +/* + // OCC-based calculation. It is faster, but it was removed due to problems + // with reversed geometry (clockwise arcs). More info in "Sketch: how to + // handle reversed external arcs?" forum thread + // http://forum.freecadweb.org/viewtopic.php?f=10&t=9130&sid=1b994fa1236db5ac2371eeb9a53de23f + + const Part::GeomCurve &g1 = *(dynamic_cast(this->getGeometry(GeoId1))); + const Part::GeomCurve &g2 = *(dynamic_cast(this->getGeometry(GeoId2))); + Base::Vector3d p(px, py, 0.0); + + double u1 = 0.0; + double u2 = 0.0; + if (! g1.closestParameterToBasicCurve(p, u1) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: closestParameter(curve1) failed!"); + if (! g2.closestParameterToBasicCurve(p, u2) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: closestParameter(curve2) failed!"); + + gp_Dir tan1, tan2; + if (! g1.tangent(u1,tan1) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: tangent1 failed!"); + if (! g2.tangent(u2,tan2) ) throw Base::Exception("SketchObject::calculateAngleViaPoint: tangent2 failed!"); + + assert(abs(tan1.Z())<0.0001); + assert(abs(tan2.Z())<0.0001); + + double ang = atan2(-tan2.X()*tan1.Y()+tan2.Y()*tan1.X(), tan2.X()*tan1.X() + tan2.Y()*tan1.Y()); + return ang; +*/ +} + +void SketchObject::constraintsRenamed(const std::map &renamed) +{ + ExpressionEngine.renameExpressions(renamed); + + getDocument()->renameObjectIdentifiers(renamed); +} + +void SketchObject::constraintsRemoved(const std::set &removed) +{ + std::set::const_iterator i = removed.begin(); + + while (i != removed.end()) { + ExpressionEngine.setValue(*i, boost::shared_ptr(), 0); + ++i; + } +} + +//Tests if the provided point lies exactly in a curve (satisfies +// point-on-object constraint). It is used to decide whether it is nesessary to +// constrain a point onto curves when 3-element selection tangent-via-point-like +// constraints are applied. +bool SketchObject::isPointOnCurve(int geoIdCurve, double px, double py) +{ + //DeepSOIC: this may be slow, but I wanted to reuse the existing code + Sketcher::Sketch sk; + int icrv = sk.addGeometry(this->getGeometry(geoIdCurve)); + Base::Vector3d pp; + pp.x = px; pp.y = py; + Part::GeomPoint p(pp); + int ipnt = sk.addPoint(p); + int icstr = sk.addPointOnObjectConstraint(ipnt, Sketcher::start, icrv); + double err = sk.calculateConstraintError(icstr); + return err*err < 10.0*sk.getSolverPrecision(); +} + +//This one was done just for fun to see to what precision the constraints are solved. +double SketchObject::calculateConstraintError(int ConstrId) +{ + Sketcher::Sketch sk; + const std::vector &clist = this->Constraints.getValues(); + if (ConstrId < 0 || ConstrId >= int(clist.size())) + return std::numeric_limits::quiet_NaN(); + + Constraint* cstr = clist[ConstrId]->clone(); + double result=0.0; + try{ + std::vector GeoIdList; + int g; + GeoIdList.push_back(cstr->First); + GeoIdList.push_back(cstr->Second); + GeoIdList.push_back(cstr->Third); + + //add only necessary geometry to the sketch + for(std::size_t i=0; igetGeometry(g)); + } + } + + cstr->First = GeoIdList[0]; + cstr->Second = GeoIdList[1]; + cstr->Third = GeoIdList[2]; + int icstr = sk.addConstraint(cstr); + result = sk.calculateConstraintError(icstr); + } catch(...) {//cleanup + delete cstr; + throw; + } + delete cstr; + return result; +} + +PyObject *SketchObject::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new SketchObjectPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +unsigned int SketchObject::getMemSize(void) const +{ + return 0; +} + +void SketchObject::Save(Writer &writer) const +{ + // save the father classes + Part::Part2DObject::Save(writer); +} + +void SketchObject::Restore(XMLReader &reader) +{ + // read the father classes + Part::Part2DObject::Restore(reader); +} + +void SketchObject::onChanged(const App::Property* prop) +{ + if (isRestoring() && prop == &Geometry) { + std::vector geom = Geometry.getValues(); + std::vector supportedGeom = supportedGeometry(geom); + // To keep upward compatibility ignore unsupported geometry types + if (supportedGeom.size() != geom.size()) { + Geometry.setValues(supportedGeom); + return; + } + } + if (prop == &Geometry || prop == &Constraints) { + Constraints.checkGeometry(getCompleteGeometry()); + } + else if (prop == &ExternalGeometry) { + // make sure not to change anything while restoring this object + if (!isRestoring()) { + // external geometry was cleared + if (ExternalGeometry.getSize() == 0) { + delConstraintsToExternal(); + } + } + } +#if 0 + // For now do not delete anything (#0001791). When changing the support + // face it might be better to check which external geometries can be kept. + else if (prop == &Support) { + // make sure not to change anything while restoring this object + if (!isRestoring()) { + // if support face has changed then clear the external geometry + delConstraintsToExternal(); + for (int i=0; i < getExternalGeometryCount(); i++) { + delExternal(0); + } + } + } +#endif + Part::Part2DObject::onChanged(prop); +} + +void SketchObject::onDocumentRestored() +{ + try { + if(Support.getValue()) { + validateExternalLinks(); + rebuildExternalGeometry(); + } + else { + rebuildVertexIndex(); + } + Constraints.acceptGeometry(getCompleteGeometry()); + } + catch (...) { + } +} + +void SketchObject::getGeoVertexIndex(int VertexId, int &GeoId, PointPos &PosId) const +{ + if (VertexId < 0 || VertexId >= int(VertexId2GeoId.size())) { + GeoId = Constraint::GeoUndef; + PosId = none; + return; + } + GeoId = VertexId2GeoId[VertexId]; + PosId = VertexId2PosId[VertexId]; +} + +int SketchObject::getVertexIndexGeoPos(int GeoId, PointPos PosId) const +{ + for(std::size_t i=0;i &vals = this->Constraints.getValues(); + + std::vector< Constraint * > newVals(vals);//modifiable copy of pointers array + + std::vector< Constraint * > tbd;//list of temporary Constraint copies that need to be deleted later + + for(std::size_t i = 0; iType == Tangent || newVals[i]->Type == Perpendicular ){ + //create a constraint copy, affect it, replace the pointer + cntToBeAffected++; + Constraint *constNew = newVals[i]->clone(); + bool ret = AutoLockTangencyAndPerpty(constNew, /*bForce=*/true, bLock); + if (ret) cntSuccess++; + tbd.push_back(constNew); + newVals[i] = constNew; + Base::Console().Log("Constraint%i will be affected\n", + i+1); + } + } + + this->Constraints.setValues(newVals); + + //clean up - delete temporary copies of constraints that were made to affect the constraints + for(std::size_t i=0; i &vals = this->Constraints.getValues(); + + std::vector< Constraint * > newVals(vals);//modifiable copy of pointers array + + std::vector< Constraint * > tbd;//list of temporary Constraint copies that need to be deleted later + + for(std::size_t ic = 0; icFirst; posId = newVals[ic]->FirstPos; break; + case 2: geoId=newVals[ic]->Second; posId = newVals[ic]->SecondPos; break; + case 3: geoId=newVals[ic]->Third; posId = newVals[ic]->ThirdPos; break; + } + + if ( geoId <= -3 && + (posId==Sketcher::start || posId==Sketcher::end)){ + //we are dealing with a link to an endpoint of external geom + Part::Geometry* g = this->ExternalGeo[-geoId-1]; + if (g->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()){ + const Part::GeomArcOfCircle *segm = dynamic_cast(g); + if(segm->isReversedInXY()){ + //Gotcha! a link to an endpoint of external arc that is reversed. + //create a constraint copy, affect it, replace the pointer + if (!affected) + constNew = newVals[ic]->clone(); + affected=true; + //Do the fix on temp vars + if(posId == Sketcher::start) + posId = Sketcher::end; + else if (posId == Sketcher::end) + posId = Sketcher::start; + } + } + } + if (!affected) continue; + //Propagate the fix made on temp vars to the constraint + switch (ig){ + case 1: constNew->First = geoId; constNew->FirstPos = posId; break; + case 2: constNew->Second = geoId; constNew->SecondPos = posId; break; + case 3: constNew->Third = geoId; constNew->ThirdPos = posId; break; + } + } + if (affected){ + cntToBeAffected++; + tbd.push_back(constNew); + newVals[ic] = constNew; + Base::Console().Log("Constraint%i will be affected\n", + ic+1); + }; + } + + if(!justAnalyze){ + this->Constraints.setValues(newVals); + Base::Console().Log("Swapped start/end of reversed external arcs in %i constraints\n", + cntToBeAffected); + } + + //clean up - delete temporary copies of constraints that were made to affect the constraints + for(std::size_t i=0; iType == Tangent || cstr->Type == Perpendicular); + if(cstr->getValue() != 0.0 && ! bForce) /*tangency type already set. If not bForce - don't touch.*/ + return true; + if(!bLock){ + cstr->setValue(0.0);//reset + } else { + //decide on tangency type. Write the angle value into the datum field of the constraint. + int geoId1, geoId2, geoIdPt; + PointPos posPt; + geoId1 = cstr->First; + geoId2 = cstr->Second; + geoIdPt = cstr->Third; + posPt = cstr->ThirdPos; + if (geoIdPt == Constraint::GeoUndef){//not tangent-via-point, try endpoint-to-endpoint... + geoIdPt = cstr->First; + posPt = cstr->FirstPos; + } + if (posPt == none){//not endpoint-to-curve and not endpoint-to-endpoint tangent (is simple tangency) + //no tangency lockdown is implemented for simple tangency. Do nothing. + return false; + } else { + Base::Vector3d p = getPoint(geoIdPt, posPt); + + //this piece of code is also present in Sketch.cpp, correct for offset + //and to do the autodecision for old sketches. + double angleOffset = 0.0;//the difference between the datum value and the actual angle to apply. (datum=angle+offset) + double angleDesire = 0.0;//the desired angle value (and we are to decide if 180* should be added to it) + if (cstr->Type == Tangent) {angleOffset = -M_PI/2; angleDesire = 0.0;} + if (cstr->Type == Perpendicular) {angleOffset = 0; angleDesire = M_PI/2;} + + double angleErr = calculateAngleViaPoint(geoId1, geoId2, p.x, p.y) - angleDesire; + + //bring angleErr to -pi..pi + if (angleErr > M_PI) angleErr -= M_PI*2; + if (angleErr < -M_PI) angleErr += M_PI*2; + + //the autodetector + if(fabs(angleErr) > M_PI/2 ) + angleDesire += M_PI; + + cstr->setValue(angleDesire + angleOffset); //external tangency. The angle stored is offset by Pi/2 so that a value of 0.0 is invalid and threated as "undecided". + } + } + } catch (Base::Exception& e){ + //failure to determine tangency type is not a big deal, so a warning. + Base::Console().Warning("Error in AutoLockTangency. %s \n", e.what()); + return false; + } + return true; +} + +void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::shared_ptr expr, const char * comment) +{ + DocumentObject::setExpression(path, expr, comment); + + if(noRecomputes) // if we do not have a recompute, the sketch must be solved to update the DoF of the solver, constraints and UI + solve(); +} + + +// Python Sketcher feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(Sketcher::SketchObjectPython, Sketcher::SketchObject) +template<> const char* Sketcher::SketchObjectPython::getViewProviderName(void) const { + return "SketcherGui::ViewProviderPython"; +} +template<> PyObject* Sketcher::SketchObjectPython::getPyObject(void) { + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new FeaturePythonPyT(this),true); + } + return Py::new_reference_to(PythonObject); +} +/// @endcond + +// explicit template instantiation +template class SketcherExport FeaturePythonT; +} diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index 328e0fe0b569..fa82d573a0e4 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -31,12 +31,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include // inclusion of the generated files (generated out of SketchObjectSFPy.xml) @@ -381,10 +383,20 @@ PyObject* SketchObjectPy::addExternal(PyObject *args) PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } - // check if it belongs to the sketch support - if (this->getSketchObjectPtr()->Support.getValue() != Obj) { + // check if it is a datum feature + // TODO: Allow selection only from Body which this sketch belongs to? + if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + // OK + } else if (Obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + if (this->getSketchObjectPtr()->Support.getValue() != Obj) { + std::stringstream str; + str << ObjectName << "is not supported by this sketch"; + PyErr_SetString(PyExc_ValueError, str.str().c_str()); + return 0; + } + } else if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { std::stringstream str; - str << ObjectName << "is not supported by this sketch"; + str << ObjectName << "must be a Part feature or a datum feature"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 3fc096e7845c..4f033ab33a26 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include #include "ViewProviderSketch.h" #include "DrawSketchHandler.h" @@ -4473,7 +4475,12 @@ namespace SketcherGui { { Sketcher::SketchObject *sketch = static_cast(object); App::DocumentObject *support = sketch->Support.getValue(); - // for the moment we allow external constraints only from the support + + // for the moment we allow external constraints only from the support and datum features + if(pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + return true; + if (pObj != support) return false; if (!sSubName || sSubName[0] == '\0') @@ -4582,8 +4589,13 @@ class DrawSketchHandlerExternal: public DrawSketchHandler virtual bool onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { + App::DocumentObject* obj = sketchgui->getObject()->getDocument()->getObject(msg.pObjectName); + if (obj == NULL) + throw Base::Exception("Sketcher: External geometry: Invalid object in selection"); std::string subName(msg.pSubName); - if ((subName.size() > 4 && subName.substr(0,4) == "Edge") || + if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || + (subName.size() > 4 && subName.substr(0,4) == "Edge") || (subName.size() > 6 && subName.substr(0,6) == "Vertex")) { try { Gui::Command::openCommand("Add external geometry"); From 02dfb8551d8dbd77acf358e5c9330189293ee372 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 4 May 2013 10:52:54 +0430 Subject: [PATCH 096/664] Moved some methods from PartDesign::Body to Part::BodyBase so the SketchObjects will be removed cleanly from the Body when deleted --- src/Mod/Part/App/BodyBase.cpp | 25 ++++++++++++++++++- src/Mod/Part/App/BodyBase.h | 19 ++++++++++++++ src/Mod/Part/Gui/ViewProvider.cpp | 25 +++++++++++++++++++ src/Mod/Part/Gui/ViewProvider.h | 4 ++- src/Mod/PartDesign/App/Body.cpp | 21 ---------------- src/Mod/PartDesign/App/Body.h | 9 +------ src/Mod/PartDesign/Gui/Command.cpp | 2 +- src/Mod/PartDesign/Gui/ViewProvider.cpp | 24 ------------------ src/Mod/PartDesign/Gui/ViewProvider.h | 2 -- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 2 +- .../PartDesign/Gui/ViewProviderDatumLine.cpp | 2 +- .../PartDesign/Gui/ViewProviderDatumPlane.cpp | 2 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 2 +- 13 files changed, 77 insertions(+), 62 deletions(-) diff --git a/src/Mod/Part/App/BodyBase.cpp b/src/Mod/Part/App/BodyBase.cpp index 8a5510f2f318..8474a0de71a9 100644 --- a/src/Mod/Part/App/BodyBase.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -25,6 +25,8 @@ #ifndef _PreComp_ #endif +#include +#include #include #include "BodyBase.h" @@ -55,4 +57,25 @@ App::DocumentObjectExecReturn *BodyBase::execute(void) return App::DocumentObject::StdReturn; } -} \ No newline at end of file +const bool BodyBase::hasFeature(const App::DocumentObject* f) const +{ + const std::vector features = Model.getValues(); + return std::find(features.begin(), features.end(), f) != features.end(); +} + +BodyBase* BodyBase::findBodyOf(const App::DocumentObject* f) +{ + App::Document* doc = App::GetApplication().getActiveDocument(); + if (doc != NULL) { + std::vector bodies = doc->getObjectsOfType(BodyBase::getClassTypeId()); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + BodyBase* body = static_cast(*b); + if (body->hasFeature(f)) + return body; + } + } + + return NULL; +} + +} diff --git a/src/Mod/Part/App/BodyBase.h b/src/Mod/Part/App/BodyBase.h index e17bf9ad0d88..6ed022060133 100644 --- a/src/Mod/Part/App/BodyBase.h +++ b/src/Mod/Part/App/BodyBase.h @@ -56,6 +56,25 @@ class PartExport BodyBase : public Part::Feature // return "PartDesignGui::ViewProviderBodyBase"; //} //@} + + // These methods are located here to avoid a dependency of ViewProviderSketchObject on PartDesign + /// Remove the feature from the body + virtual void removeFeature(App::DocumentObject* feature){} + + /// Return true if the feature belongs to this body + const bool hasFeature(const App::DocumentObject *f) const; + + /** + * Return the solid feature before the given feature, or before the Tip feature + * That is, sketches and datum features are skipped + * If inclusive is true, start or the Tip is returned if it is a solid feature + */ + virtual App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true){} + + /// Return the body which this feature belongs too, or NULL + static BodyBase* findBodyOf(const App::DocumentObject* f); + + }; } //namespace Part diff --git a/src/Mod/Part/Gui/ViewProvider.cpp b/src/Mod/Part/Gui/ViewProvider.cpp index 9e1261487769..e819feea677b 100644 --- a/src/Mod/Part/Gui/ViewProvider.cpp +++ b/src/Mod/Part/Gui/ViewProvider.cpp @@ -83,6 +83,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,7 @@ #include "ViewProvider.h" #include "SoFCShapeObject.h" +#include #include #include @@ -123,6 +125,29 @@ bool ViewProviderPart::doubleClicked(void) } } +bool ViewProviderPart::onDelete(const std::vector &) +{ + // Body feature housekeeping + Part::BodyBase* body = Part::BodyBase::findBodyOf(getObject()); + if (body != NULL) { + body->removeFeature(getObject()); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = body->Tip.getValue(); + App::DocumentObject* prev = body->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + // TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support + // 1. Delete + // 2. Suppress + // 3. Re-route + return true; +} + void ViewProviderPart::applyColor(const Part::ShapeHistory& hist, const std::vector& colBase, std::vector& colBool) diff --git a/src/Mod/Part/Gui/ViewProvider.h b/src/Mod/Part/Gui/ViewProvider.h index 5a11239e7216..a7314de892f6 100644 --- a/src/Mod/Part/Gui/ViewProvider.h +++ b/src/Mod/Part/Gui/ViewProvider.h @@ -31,7 +31,7 @@ #include #include -class SoSeparator; +class SoSeparator; namespace Part { struct ShapeHistory; } @@ -57,6 +57,8 @@ class PartGuiExport ViewProviderPart : public ViewProviderPartExt virtual ~ViewProviderPart(); virtual bool doubleClicked(void); + virtual bool onDelete(const std::vector &); + protected: void applyColor(const Part::ShapeHistory& hist, const std::vector& colBase, diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 4ed343a75013..5ed05e42bf46 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -165,12 +165,6 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const return *it; } -const bool Body::hasFeature(const App::DocumentObject* f) const -{ - const std::vector features = Model.getValues(); - return std::find(features.begin(), features.end(), f) != features.end(); -} - const bool Body::isAfterTip(const App::DocumentObject *f) { std::vector features = Model.getValues(); std::vector::const_iterator it = std::find(features.begin(), features.end(), f); @@ -196,21 +190,6 @@ const bool Body::isAllowed(const App::DocumentObject* f) f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); } -Body* Body::findBodyOf(const App::DocumentObject* f) -{ - App::Document* doc = App::GetApplication().getActiveDocument(); - if (doc != NULL) { - std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { - PartDesign::Body* body = static_cast(*b); - if (body->hasFeature(f)) - return body; - } - } - - return NULL; -} - void Body::addFeature(App::DocumentObject *feature) { // Set the BaseFeature property diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 519f7486af1a..909b928087ab 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -75,9 +75,6 @@ class Body : public Part::BodyBase // Return the shape of the feature preceding this feature //const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); - /// Return true if the feature belongs to this body - const bool hasFeature(const App::DocumentObject *f) const; - /// Return true if the feature is located after the current Tip feature const bool isAfterTip(const App::DocumentObject *f); @@ -87,7 +84,6 @@ class Body : public Part::BodyBase /// Remove the feature from the body void removeFeature(App::DocumentObject* feature); - /** * Return true if the given feature is a solid feature allowed in a Body. Currently this is only valid * for features derived from PartDesign::Feature @@ -99,10 +95,7 @@ class Body : public Part::BodyBase * Return true if the given feature is allowed in a Body. Currently allowed are * all features derived from PartDesign::Feature and Part::Datum and sketches */ - static const bool isAllowed(const App::DocumentObject* f); - - /// Return the body which this feature belongs too, or NULL - static Body* findBodyOf(const App::DocumentObject* f); + static const bool isAllowed(const App::DocumentObject* f); PyObject *getPyObject(void); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index e5ea1da9fb69..bbdec5054edc 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -179,7 +179,7 @@ void CmdPartDesignMoveTip::activated(int iMsg) if (!pcActiveBody->hasFeature(selFeature)) { // Switch to other body - pcActiveBody = PartDesign::Body::findBodyOf(selFeature); + pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); if (pcActiveBody != NULL) Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", pcActiveBody->getNameInDocument()); diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 7dc15728e1cc..89658c81a5e8 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -72,27 +72,3 @@ void ViewProvider::updateData(const App::Property* prop) } inherited::updateData(prop); } - -bool ViewProvider::onDelete(const std::vector &) -{ - // Body feature housekeeping - PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); - if (body != NULL) { - body->removeFeature(getObject()); - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = body->Tip.getValue(); - App::DocumentObject* prev = body->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - // TODO: Ask user what to do about dependent objects, e.g. Sketches that have this feature as their support - // 1. Delete - // 2. Suppress - // 3. Re-route - - return true; -} diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index fd023e0c2a07..178f84afd7ea 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -42,8 +42,6 @@ class PartDesignGuiExport ViewProvider : public PartGui::ViewProviderPart { virtual bool doubleClicked(void); void updateData(const App::Property*); - virtual bool onDelete(const std::vector &); - protected: std::string oldWb; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index badcc51766fc..c5aafe547d32 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -105,7 +105,7 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) bool ViewProviderDatum::onDelete(const std::vector &) { // Body feature housekeeping - PartDesign::Body* body = PartDesign::Body::findBodyOf(getObject()); + Part::BodyBase* body = Part::BodyBase::findBodyOf(getObject()); if (body != NULL) { body->removeFeature(getObject()); // Make the new Tip and the previous solid feature visible again diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp index 00630a5e464b..76b9be4ae39a 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp @@ -82,7 +82,7 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) Base::Vector3d dir = pcDatum->_Direction.getValue(); // Get limits of the line from bounding box of the body - PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + PartDesign::Body* body = static_cast(Part::BodyBase::findBodyOf(this->getObject())); if (body == NULL) return; Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index 2265c72dbfa6..44af8dddfacf 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -82,7 +82,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) Base::Vector3d normal = pcDatum->_Normal.getValue(); // Get limits of the plane from bounding box of the body - PartDesign::Body* body = PartDesign::Body::findBodyOf(this->getObject()); + PartDesign::Body* body = static_cast(Part::BodyBase::findBodyOf(this->getObject())); if (body == NULL) return; Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index a77323db2ecf..468ca2249419 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -4875,5 +4875,5 @@ bool ViewProviderSketch::onDelete(const std::vector &subList) return false; } // if not in edit delete the whole object - return true; + return PartGui::ViewProviderPart::onDelete(subList); } From a6431ee5cf007e7996bedf8e78b62c121049ca32 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 6 May 2013 11:39:53 +0430 Subject: [PATCH 097/664] Improved bounding box calculation for datum feature display size --- src/App/Plane.cpp | 4 +++ src/App/Plane.h | 3 ++ src/Gui/ViewProviderPlane.cpp | 2 +- src/Mod/PartDesign/App/Body.cpp | 36 +++++++++++++++++++ src/Mod/PartDesign/App/Body.h | 5 ++- .../PartDesign/Gui/ViewProviderDatumLine.cpp | 5 +-- .../PartDesign/Gui/ViewProviderDatumPlane.cpp | 8 ++--- 7 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/App/Plane.cpp b/src/App/Plane.cpp index 4e4ba42b5db3..c5d495b8b6ce 100644 --- a/src/App/Plane.cpp +++ b/src/App/Plane.cpp @@ -48,6 +48,10 @@ Plane::~Plane(void) { } +Base::BoundBox3d Plane::getBoundBox() +{ + return Base::BoundBox3d(-10, -10, -10, 10, 10, 10); +} diff --git a/src/App/Plane.h b/src/App/Plane.h index 33a1d5e7f456..51599054f870 100644 --- a/src/App/Plane.h +++ b/src/App/Plane.h @@ -53,6 +53,9 @@ class AppExport Plane: public App::GeoFeature virtual const char* getViewProviderName(void) const { return "Gui::ViewProviderPlane"; } + + /// Return the bounding box of the plane (this is always a fixed size) + static Base::BoundBox3d getBoundBox(); }; diff --git a/src/Gui/ViewProviderPlane.cpp b/src/Gui/ViewProviderPlane.cpp index 979469d19ca8..40f5672f3273 100644 --- a/src/Gui/ViewProviderPlane.cpp +++ b/src/Gui/ViewProviderPlane.cpp @@ -68,7 +68,7 @@ ViewProviderPlane::ViewProviderPlane() pMat = new SoMaterial(); pMat->ref(); - const float size = 2; + const float size = 10; // Note: If you change this, you need to also adapt App/Plane.cpp getBoundBox() static const SbVec3f verts[4] = { diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 5ed05e42bf46..d1a06fc4d406 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -25,12 +25,16 @@ #ifndef _PreComp_ #endif +#include #include #include "Feature.h" #include "Body.h" #include "BodyPy.h" #include "FeatureSketchBased.h" +#include "DatumPoint.h" +#include "DatumLine.h" +#include "DatumPlane.h" #include #include @@ -316,6 +320,38 @@ App::DocumentObjectExecReturn *Body::execute(void) return App::DocumentObject::StdReturn; } +Base::BoundBox3d Body::getBoundBox() +{ + Base::BoundBox3d result; + + Part::Feature* tipSolid = static_cast(getPrevSolidFeature()); + if (tipSolid != NULL) { + result = tipSolid->Shape.getShape().getBoundBox(); + } else { + result = App::Plane::getBoundBox(); + } + + std::vector model = Model.getValues(); + // TODO: In DatumLine and DatumPlane, recalculate the Base point to be as near as possible to the origin (0,0,0) + for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { + if ((*m)->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { + PartDesign::Point* point = static_cast(*m); + result.Add(point->_Point.getValue()); + } else if ((*m)->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* line = static_cast(*m); + result.Add(line->_Base.getValue()); + } else if ((*m)->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* plane = static_cast(*m); + result.Add(plane->_Base.getValue()); + } else if ((*m)->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + // Note: We only take into account the base planes here + result.Add(Base::Vector3d(0,0,0)); + } + } + + return result; +} + PyObject *Body::getPyObject(void) { if (PythonObject.is(Py::_None())){ diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 909b928087ab..dd07b0459fb7 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -95,7 +95,10 @@ class Body : public Part::BodyBase * Return true if the given feature is allowed in a Body. Currently allowed are * all features derived from PartDesign::Feature and Part::Datum and sketches */ - static const bool isAllowed(const App::DocumentObject* f); + static const bool isAllowed(const App::DocumentObject* f); + + /// Return the bounding box of the Tip Shape, taking into account datum features + Base::BoundBox3d getBoundBox(); PyObject *getPyObject(void); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp index 76b9be4ae39a..d490c0459b3e 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp @@ -85,10 +85,7 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) PartDesign::Body* body = static_cast(Part::BodyBase::findBodyOf(this->getObject())); if (body == NULL) return; - Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); - if (tipSolid == NULL) - return; - Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); + Base::BoundBox3d bbox = body->getBoundBox(); bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); Base::Vector3d p1, p2; if (bbox.IsInBox(base)) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index 44af8dddfacf..97ddf19979aa 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -85,11 +85,9 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) PartDesign::Body* body = static_cast(Part::BodyBase::findBodyOf(this->getObject())); if (body == NULL) return; - Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); - if (tipSolid == NULL) - return; - Base::BoundBox3d bbox = tipSolid->Shape.getShape().getBoundBox(); - bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); + Base::BoundBox3d bbox = body->getBoundBox(); + double dlength = bbox.CalcDiagonalLength(); + bbox.Enlarge(0.1 * dlength); // Calculate intersection of plane with bounding box edges // TODO: This can be a lot more efficient if we do the maths ourselves, e.g. From 2aea9bbf96ec40e00fa5492193e08961255c202a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 6 May 2013 12:14:12 +0430 Subject: [PATCH 098/664] Automatically adjust datum line/plane size to Body bounding box --- src/Mod/PartDesign/App/Body.cpp | 2 ++ src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index d1a06fc4d406..4c1682f6c3b4 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -292,6 +292,7 @@ void Body::removeFeature(App::DocumentObject* feature) App::DocumentObjectExecReturn *Body::execute(void) { + /* Base::Console().Error("Body '%s':\n", getNameInDocument()); App::DocumentObject* tip = Tip.getValue(); Base::Console().Error(" Tip: %s\n", (tip == NULL) ? "None" : tip->getNameInDocument()); @@ -307,6 +308,7 @@ App::DocumentObjectExecReturn *Body::execute(void) Base::Console().Error("\n"); } } + */ const Part::TopoShape& TipShape = getTipShape(); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index de5729fd3b64..a7dcb8feef6b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include "Base/Console.h" @@ -179,5 +181,22 @@ void ViewProviderBody::updateData(const App::Property* prop) } // Note: The Model property only changes by itself (without the Tip also changing) if a feature is deleted somewhere + // Update the visual size of datum lines and planes + PartDesign::Body* body = static_cast(getObject()); + std::vector features = body->Model.getValues(); + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + App::PropertyVector* baseProp = NULL; + if ((*f)->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) + baseProp = &(static_cast(*f)->_Base); + else if ((*f)->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) + baseProp = &(static_cast(*f)->_Base); + + if (baseProp != NULL) { + Gui::ViewProviderDocumentObject* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); + if (vp != NULL) + vp->updateData(baseProp); + } + } + PartGui::ViewProviderPart::updateData(prop); } From f6fb4814d19f65524515869b479a97eb7d842536 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 6 May 2013 12:14:42 +0430 Subject: [PATCH 099/664] Miscellaneous fixes --- src/Mod/PartDesign/App/DatumLine.cpp | 2 -- src/Mod/PartDesign/App/DatumPlane.cpp | 2 -- src/Mod/PartDesign/Gui/TaskDatumParameters.cpp | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index f59e93220b5b..37c7c5b317bb 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -130,8 +130,6 @@ Line::~Line() void Line::onChanged(const App::Property *prop) { - Datum::onChanged(prop); - if (prop == &References) { refTypes.clear(); std::vector refs = References.getValues(); diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index 6c76913881ca..f42f71339ce2 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -153,8 +153,6 @@ ADD_PROPERTY_TYPE(_Normal,(Base::Vector3d(1,1,1)),"DatumPlane", void Plane::onChanged(const App::Property *prop) { - Datum::onChanged(prop); - if (prop == &Angle) { // Zero value counts as angle not defined if (fabs(Angle.getValue()) > Precision::Confusion()) diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 132427f93980..bdb55c015acb 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -111,7 +111,7 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p connect(ui->spinAngle, SIGNAL(valueChanged(double)), this, SLOT(onAngleChanged(double))); connect(ui->checkBoxFlip, SIGNAL(toggled(bool)), - this, SLOT(onCheckBox1(bool))); + this, SLOT(onCheckFlip(bool))); connect(ui->buttonRef1, SIGNAL(pressed()), this, SLOT(onButtonRef1())); connect(ui->lineRef1, SIGNAL(textEdited(QString)), From 2c378a4f8cdae47804895bbdc0e231000a8e2933 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 6 May 2013 20:42:53 +0430 Subject: [PATCH 100/664] Add check in Document.cpp recompute() to check for invalid pointers --- src/App/Document.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 8238964c4e51..4bbd347b126a 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1755,7 +1755,7 @@ void Document::recompute() for (std::list::reverse_iterator i = make_order.rbegin();i != make_order.rend(); ++i) { DocumentObject* Cur = d->vertexMap[*i]; - if (!Cur) continue; + if (!Cur || !isIn(Cur)) continue; #ifdef FC_LOGFEATUREUPDATE std::clog << Cur->getNameInDocument() << " dep on:" ; #endif @@ -1820,7 +1820,7 @@ void Document::recompute() // reset all touched for (std::map::iterator it = d->vertexMap.begin(); it != d->vertexMap.end(); ++it) { - if (it->second) + if ((it->second) && isIn(it->second)) it->second->purgeTouched(); } d->vertexMap.clear(); From 0e8921c21f7b6d51db1d37ed7b271a92b76d6a9a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 9 May 2013 11:26:32 +0430 Subject: [PATCH 101/664] Simplified datum features by making use of the placement property --- src/Mod/PartDesign/App/Body.cpp | 7 +-- src/Mod/PartDesign/App/DatumLine.cpp | 51 +++++++++-------- src/Mod/PartDesign/App/DatumLine.h | 6 +- src/Mod/PartDesign/App/DatumPlane.cpp | 57 +++++++++++-------- src/Mod/PartDesign/App/DatumPlane.h | 7 ++- src/Mod/PartDesign/App/DatumPoint.cpp | 36 ++++++------ src/Mod/PartDesign/App/DatumPoint.h | 4 +- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 10 ++-- .../PartDesign/Gui/ViewProviderDatumLine.cpp | 9 ++- .../PartDesign/Gui/ViewProviderDatumPlane.cpp | 9 ++- .../PartDesign/Gui/ViewProviderDatumPoint.cpp | 36 +++++------- 11 files changed, 121 insertions(+), 111 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 4c1682f6c3b4..de1014f9b8ff 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -317,7 +317,6 @@ App::DocumentObjectExecReturn *Body::execute(void) return App::DocumentObject::StdReturn; Shape.setValue(TipShape); - return App::DocumentObject::StdReturn; } @@ -338,13 +337,13 @@ Base::BoundBox3d Body::getBoundBox() for (std::vector::const_iterator m = model.begin(); m != model.end(); m++) { if ((*m)->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { PartDesign::Point* point = static_cast(*m); - result.Add(point->_Point.getValue()); + result.Add(point->getPoint()); } else if ((*m)->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* line = static_cast(*m); - result.Add(line->_Base.getValue()); + result.Add(line->getBasePoint()); } else if ((*m)->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* plane = static_cast(*m); - result.Add(plane->_Base.getValue()); + result.Add(plane->getBasePoint()); } else if ((*m)->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { // Note: We only take into account the base planes here result.Add(Base::Vector3d(0,0,0)); diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index 37c7c5b317bb..bed809869c1d 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -116,12 +116,14 @@ PROPERTY_SOURCE(PartDesign::Line, Part::Datum) Line::Line() { - ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumLine", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the line base point"); - ADD_PROPERTY_TYPE(_Direction,(Base::Vector3d(1,1,1)),"DatumLine", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the line direction"); + // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of + // Sketcher on the PartDesign module + BRepBuilderAPI_MakeEdge builder(gp_Lin(gp_Pnt(0,0,0), gp_Dir(0,0,1))); + if (!builder.IsDone()) + return; + Shape.setValue(builder.Shape()); + + References.touch(); } Line::~Line() @@ -155,17 +157,17 @@ void Line::onChanged(const App::Property *prop) if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { PartDesign::Point* p = static_cast(refs[i]); if (p1 == NULL) - p1 = new Base::Vector3d (p->_Point.getValue()); + p1 = new Base::Vector3d (p->getPoint()); else - p2 = new Base::Vector3d (p->_Point.getValue()); + p2 = new Base::Vector3d (p->getPoint()); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* l = static_cast(refs[i]); - base = new Base::Vector3d (l->_Base.getValue()); - direction = new Base::Vector3d (l->_Direction.getValue()); + base = new Base::Vector3d (l->getBasePoint()); + direction = new Base::Vector3d (l->getDirection()); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* p = static_cast(refs[i]); - Base::Vector3d base = p->_Base.getValue(); - Base::Vector3d normal = p->_Normal.getValue(); + Base::Vector3d base = p->getBasePoint(); + Base::Vector3d normal = p->getNormal(); if (s1.IsNull()) s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); else @@ -247,16 +249,7 @@ void Line::onChanged(const App::Property *prop) return; } - _Base.setValue(*base); - _Direction.setValue(*direction); - _Base.touch(); // This triggers ViewProvider::updateData() - - // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of - // Sketcher on the PartDesign module - BRepBuilderAPI_MakeEdge builder(gp_Lin(gp_Pnt(base->x, base->y, base->z), gp_Dir(direction->x, direction->y, direction->z))); - if (!builder.IsDone()) - return; - Shape.setValue(builder.Shape()); + Placement.setValue(Base::Placement(*base, Base::Rotation(Base::Vector3d(0,0,1), *direction))); delete base; delete direction; @@ -268,7 +261,6 @@ void Line::onChanged(const App::Property *prop) Part::Datum::onChanged(prop); } - const std::set Line::getHint() { if (hints.find(refTypes) != hints.end()) @@ -276,3 +268,16 @@ const std::set Line::getHint() else return std::set(); } + +Base::Vector3d Line::getBasePoint() +{ + return Placement.getValue().getPosition(); +} + +Base::Vector3d Line::getDirection() +{ + Base::Rotation rot = Placement.getValue().getRotation(); + Base::Vector3d dir; + rot.multVec(Base::Vector3d(0,0,1), dir); + return dir; +} diff --git a/src/Mod/PartDesign/App/DatumLine.h b/src/Mod/PartDesign/App/DatumLine.h index 6ca976106ea4..a70956a26c6a 100644 --- a/src/Mod/PartDesign/App/DatumLine.h +++ b/src/Mod/PartDesign/App/DatumLine.h @@ -37,9 +37,6 @@ class PartDesignExport Line : public Part::Datum PROPERTY_HEADER(PartDesign::Line); public: - App::PropertyVector _Base; - App::PropertyVector _Direction; - Line(); virtual ~Line(); @@ -50,6 +47,9 @@ class PartDesignExport Line : public Part::Datum static void initHints(); const std::set getHint(); + Base::Vector3d getBasePoint(); + Base::Vector3d getDirection(); + protected: virtual void onChanged(const App::Property* prop); diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index f42f71339ce2..76408b61af03 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -131,7 +131,6 @@ void Plane::initHints() key.insert(LINE); key.insert(PLANE); key.insert(ANGLE); hints[key] = DONE; // {LINE, PLANE, ANGLE} -> DONE. Plane through line with angle to other plane - key.clear(); value.clear(); value.insert(POINT); value.insert(LINE); value.insert(PLANE); value.insert(ANGLE); hints[key] = value; @@ -143,12 +142,18 @@ PROPERTY_SOURCE(PartDesign::Plane, Part::Datum) Plane::Plane() { -ADD_PROPERTY_TYPE(_Base,(Base::Vector3d(0,0,0)),"DatumPlane", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the plane base point"); -ADD_PROPERTY_TYPE(_Normal,(Base::Vector3d(1,1,1)),"DatumPlane", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the plane normal"); + // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of + // Sketcher on the PartDesign module + BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(0,0,1))); + if (!builder.IsDone()) + return; + Shape.setValue(builder.Shape()); + + References.touch(); +} + +Plane::~Plane() +{ } void Plane::onChanged(const App::Property *prop) @@ -187,20 +192,20 @@ void Plane::onChanged(const App::Property *prop) if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { PartDesign::Point* p = static_cast(refs[i]); if (p1 == NULL) - p1 = new Base::Vector3d (p->_Point.getValue()); + p1 = new Base::Vector3d (p->getPoint()); else if (p2 == NULL) - p2 = new Base::Vector3d (p->_Point.getValue()); + p2 = new Base::Vector3d (p->getPoint()); else - p3 = new Base::Vector3d (p->_Point.getValue()); + p3 = new Base::Vector3d (p->getPoint()); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* l = static_cast(refs[i]); - Base::Vector3d base = l->_Base.getValue(); - Base::Vector3d dir = l->_Direction.getValue(); + Base::Vector3d base = l->getBasePoint(); + Base::Vector3d dir = l->getDirection(); line = new gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* p = static_cast(refs[i]); - p1 = new Base::Vector3d(p->_Base.getValue()); - normal = new Base::Vector3d(p->_Normal.getValue()); + p1 = new Base::Vector3d(p->getBasePoint()); + normal = new Base::Vector3d(p->getNormal()); } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { App::Plane* p = static_cast(refs[i]); // Note: We only handle the three base planes here @@ -284,16 +289,7 @@ void Plane::onChanged(const App::Property *prop) if (fabs(Offset.getValue()) > Precision::Confusion()) *p1 += Offset.getValue() * *normal; - _Base.setValue(*p1); - _Normal.setValue(*normal); - _Base.touch(); // This triggers ViewProvider::updateData() - - // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of - // Sketcher on the PartDesign module - BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(p1->x, p1->y, p1->z), gp_Dir(normal->x, normal->y, normal->z))); - if (!builder.IsDone()) - return; - Shape.setValue(builder.Shape()); + Placement.setValue(Base::Placement(*p1,Base::Rotation(Base::Vector3d(0,0,1), *normal))); delete p1; delete normal; @@ -313,3 +309,16 @@ const std::set Plane::getHint() else return std::set(); } + +Base::Vector3d Plane::getBasePoint() +{ + return Placement.getValue().getPosition(); +} + +Base::Vector3d Plane::getNormal() +{ + Base::Rotation rot = Placement.getValue().getRotation(); + Base::Vector3d normal; + rot.multVec(Base::Vector3d(0,0,1), normal); + return normal; +} diff --git a/src/Mod/PartDesign/App/DatumPlane.h b/src/Mod/PartDesign/App/DatumPlane.h index 03e2026b3f10..d64ed690044d 100644 --- a/src/Mod/PartDesign/App/DatumPlane.h +++ b/src/Mod/PartDesign/App/DatumPlane.h @@ -36,10 +36,8 @@ class PartDesignExport Plane : public Part::Datum PROPERTY_HEADER(PartDesign::Plane); public: - App::PropertyVector _Base; - App::PropertyVector _Normal; - Plane(); + virtual ~Plane(); const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderDatumPlane"; @@ -48,6 +46,9 @@ class PartDesignExport Plane : public Part::Datum static void initHints(); const std::set getHint(); + Base::Vector3d getBasePoint(); + Base::Vector3d getNormal(); + protected: virtual void onChanged(const App::Property* prop); diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp index e9f5d338787b..b54d98d2c4d3 100644 --- a/src/Mod/PartDesign/App/DatumPoint.cpp +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -129,9 +129,14 @@ PROPERTY_SOURCE(PartDesign::Point, Part::Datum) Point::Point() { - ADD_PROPERTY_TYPE(_Point,(Base::Vector3d(0,0,0)),"DatumPoint", - App::PropertyType(App::Prop_ReadOnly|App::Prop_Output), - "Coordinates of the datum point"); + // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of + // Sketcher on the PartDesign module + BRepBuilderAPI_MakeVertex builder(gp_Pnt(0,0,0)); + if (!builder.IsDone()) + return; + Shape.setValue(builder.Shape()); + + References.touch(); } Point::~Point() @@ -163,19 +168,19 @@ void Point::onChanged(const App::Property* prop) for (int i = 0; i < refs.size(); i++) { if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { PartDesign::Point* p = static_cast(refs[i]); - point = new Base::Vector3d (p->_Point.getValue()); + point = new Base::Vector3d (p->getPoint()); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* l = static_cast(refs[i]); - Base::Vector3d base = l->_Base.getValue(); - Base::Vector3d dir = l->_Direction.getValue(); + Base::Vector3d base = l->getBasePoint(); + Base::Vector3d dir = l->getDirection(); if (c1.IsNull()) c1 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); else c2 = new Geom_Line(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* p = static_cast(refs[i]); - Base::Vector3d base = p->_Base.getValue(); - Base::Vector3d normal = p->_Normal.getValue(); + Base::Vector3d base = p->getBasePoint(); + Base::Vector3d normal = p->getNormal(); if (s1.IsNull()) s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); else if (s2.IsNull()) @@ -278,15 +283,7 @@ void Point::onChanged(const App::Property* prop) return; } - _Point.setValue(*point); - _Point.touch(); // This triggers ViewProvider::updateData() - - // Create a shape, which will be used by the Sketcher. Them main function is to avoid a dependency of - // Sketcher on the PartDesign module - BRepBuilderAPI_MakeVertex builder(gp_Pnt(point->x, point->y, point->z)); - if (!builder.IsDone()) - return; - Shape.setValue(builder.Shape()); + Placement.setValue(Base::Placement(*point, Base::Rotation())); delete point; } @@ -294,6 +291,11 @@ void Point::onChanged(const App::Property* prop) Part::Datum::onChanged(prop); } +Base::Vector3d Point::getPoint() +{ + return Placement.getValue().getPosition(); +} + const std::set Point::getHint() { diff --git a/src/Mod/PartDesign/App/DatumPoint.h b/src/Mod/PartDesign/App/DatumPoint.h index e36abf1a3652..8f9be2b2da87 100644 --- a/src/Mod/PartDesign/App/DatumPoint.h +++ b/src/Mod/PartDesign/App/DatumPoint.h @@ -37,8 +37,6 @@ class PartDesignExport Point : public Part::Datum PROPERTY_HEADER(PartDesign::Point); public: - App::PropertyVector _Point; - Point(); virtual ~Point(); @@ -49,7 +47,7 @@ class PartDesignExport Point : public Part::Datum static void initHints(); const std::set getHint(); - + Base::Vector3d getPoint(); protected: virtual void onChanged(const App::Property* prop); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index a7dcb8feef6b..73a47eb72adb 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -185,16 +185,16 @@ void ViewProviderBody::updateData(const App::Property* prop) PartDesign::Body* body = static_cast(getObject()); std::vector features = body->Model.getValues(); for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { - App::PropertyVector* baseProp = NULL; + App::PropertyPlacement* plm = NULL; if ((*f)->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) - baseProp = &(static_cast(*f)->_Base); + plm = &(static_cast(*f)->Placement); else if ((*f)->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) - baseProp = &(static_cast(*f)->_Base); + plm = &(static_cast(*f)->Placement); - if (baseProp != NULL) { + if (plm != NULL) { Gui::ViewProviderDocumentObject* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(*f)); if (vp != NULL) - vp->updateData(baseProp); + vp->updateData(plm); } } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp index d490c0459b3e..79426eaff90d 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp @@ -77,15 +77,18 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) // Gets called whenever a property of the attached object changes PartDesign::Line* pcDatum = static_cast(this->getObject()); - if (strcmp(prop->getName(),"_Base") == 0) { - Base::Vector3d base = pcDatum->_Base.getValue(); - Base::Vector3d dir = pcDatum->_Direction.getValue(); + if (strcmp(prop->getName(),"Placement") == 0) { + Base::Placement plm = pcDatum->Placement.getValue(); + plm.invert(); + Base::Vector3d base(0,0,0); + Base::Vector3d dir(0,0,1); // Get limits of the line from bounding box of the body PartDesign::Body* body = static_cast(Part::BodyBase::findBodyOf(this->getObject())); if (body == NULL) return; Base::BoundBox3d bbox = body->getBoundBox(); + bbox = bbox.Transformed(plm.toMatrix()); bbox.Enlarge(0.1 * bbox.CalcDiagonalLength()); Base::Vector3d p1, p2; if (bbox.IsInBox(base)) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index 97ddf19979aa..a1bfb78cda0f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -77,15 +77,18 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) // Gets called whenever a property of the attached object changes PartDesign::Plane* pcDatum = static_cast(this->getObject()); - if (strcmp(prop->getName(),"_Base") == 0) { - Base::Vector3d base = pcDatum->_Base.getValue(); - Base::Vector3d normal = pcDatum->_Normal.getValue(); + if (strcmp(prop->getName(),"Placement") == 0) { + Base::Placement plm = pcDatum->Placement.getValue(); + plm.invert(); + Base::Vector3d base(0,0,0); + Base::Vector3d normal(0,0,1); // Get limits of the plane from bounding box of the body PartDesign::Body* body = static_cast(Part::BodyBase::findBodyOf(this->getObject())); if (body == NULL) return; Base::BoundBox3d bbox = body->getBoundBox(); + bbox = bbox.Transformed(plm.toMatrix()); double dlength = bbox.CalcDiagonalLength(); bbox.Enlarge(0.1 * dlength); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp index 2ec1fe8ff817..00885839237f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp @@ -62,39 +62,29 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPoint,PartDesignGui::ViewProvide ViewProviderDatumPoint::ViewProviderDatumPoint() { SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; - points->numPoints = 0; + points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; + SoMFVec3f v; + v.setNum(1); + v.set1Value(0, 0,0,0); + SoVertexProperty* vprop = new SoVertexProperty(); + vprop->vertex = v; + points->vertexProperty = vprop; + points->numPoints = 1; pShapeSep->addChild(points); } ViewProviderDatumPoint::~ViewProviderDatumPoint() { - } void ViewProviderDatumPoint::updateData(const App::Property* prop) { - // Gets called whenever a property of the attached object changes - PartDesign::Point* pcDatum = static_cast(this->getObject()); - - if (strcmp(prop->getName(),"_Point") == 0) { - Base::Vector3d p = pcDatum->_Point.getValue(); - SoMFVec3f v; - v.setNum(1); - v.set1Value(0, p.x, p.y, p.z); + if (strcmp(prop->getName(),"Placement") == 0) { + // The only reason to do this is to display the point in the correct position after loading the document SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); - - SoVertexProperty* vprop; - if (points->vertexProperty.getValue() == NULL) { - vprop = new SoVertexProperty(); - vprop->vertex = v; - points->vertexProperty = vprop; - } else { - vprop = static_cast(points->vertexProperty.getValue()); - vprop->vertex = v; - } - - points->numPoints = 1; + points->touch(); + //points->numPoints = 0; + //points->numPoints = 1; } ViewProviderDatum::updateData(prop); From fe2e490645120cb227289a8f212d50716cc7003b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 9 May 2013 17:25:43 +0430 Subject: [PATCH 102/664] Allow selecting back of base planes, miscellaneous fixes --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 2 +- src/Mod/Part/App/Part2DObject.cpp | 9 +++++---- src/Mod/PartDesign/App/Body.h | 2 +- src/Mod/PartDesign/App/CMakeLists.txt | 1 + src/Mod/PartDesign/Gui/Command.cpp | 13 +++++++------ src/Mod/PartDesign/Gui/FeaturePickDialog.cpp | 11 +++++++++++ src/Mod/PartDesign/Gui/FeaturePickDialog.h | 3 +++ src/Mod/PartDesign/Gui/FeaturePickDialog.ui | 18 ++++++++++++++++-- src/Mod/PartDesign/Gui/Workbench.cpp | 10 +++++----- src/Mod/Start/StartPage/PartDesign.py | 7 ++++--- 10 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index 22473a31904e..f9d0573bb090 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -46,7 +46,7 @@ App::Document *ActiveAppDoc =0; Gui::ViewProviderDocumentObject *ActiveVp =0; // The names of the base planes. Note: The user-visible label is different from this -const char* BaseplaneNames[3] = {"BaseplaneXY", "BaseplaneYZ", "BaseplaneXZ"}; +const char* BaseplaneNames[3] = {"BaseplaneXY", "BaseplaneXZ", "BaseplaneYZ"}; } diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index e6122d69fd28..b170d05d5fd2 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -90,10 +90,8 @@ void Part2DObject::positionBySupport(void) Base::Vector3d dir; Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); const std::vector &sub = Support.getSubValues(); - if (!sub.empty() && (sub[0] == "back")) { + if (!sub.empty() && (sub[0] == "back")) Reverse = true; - dir *= -1.0; - } // Set placement identical to the way it used to be done in the Sketcher::SketchOrientationDialog if (dir == Base::Vector3d(0,0,1)) { @@ -107,7 +105,10 @@ void Part2DObject::positionBySupport(void) Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Reverse ? -0.5 : 0.5,0.5,0.5, Reverse ? -0.5 : 0.5)); } - Reverse = false; // We already reversed... + if (Reverse) { + dir *= -1.0; + Reverse = false; // We already reversed... + } Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); Base::Vector3d pos = Place.getPosition(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index dd07b0459fb7..345a903082b5 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -33,7 +33,7 @@ namespace PartDesign class Feature; -class Body : public Part::BodyBase +class PartDesignExport Body : public Part::BodyBase { PROPERTY_HEADER(PartDesign::Body); diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 9578300e51d1..77d3cb68aa10 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -11,6 +11,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${Boost_INCLUDE_DIRS} ${OCC_INCLUDE_DIR} + ${QT_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS} ${XercesC_INCLUDE_DIRS} diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index bbdec5054edc..e074842a9d66 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -121,11 +121,11 @@ void CmdPartDesignBody::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[0]); doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XY-Plane").toStdString().c_str()); doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[1]); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),-90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); - doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); // ... and put them in the 'Origin' group doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", QObject::tr("Origin").toStdString().c_str()); for (unsigned i = 0; i < 3; i++) @@ -612,18 +612,19 @@ void CmdPartDesignNewSketch::activated(int iMsg) } // If there is more than one possibility, show dialog and let user pick plane + bool reversed = false; if (validPlanes > 1) { PartDesignGui::FeaturePickDialog Dlg(planes, status); if ((Dlg.exec() != QDialog::Accepted) || (planes = Dlg.getFeatures()).empty()) return; // Cancelled or nothing selected firstValidPlane = planes.begin(); + reversed = Dlg.getReverse(); } - // TODO: Allow user to choose front or back of the plane - App::Plane* plane = static_cast(*firstValidPlane); std::string FeatName = getUniqueObjectName("Sketch"); - std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", ['front'])"; + std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + + ", ['" + (reversed ? "back" : "front") + "'])"; openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp index dc53a3f0c9d1..9576b7bbac52 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp @@ -60,12 +60,14 @@ FeaturePickDialog::FeaturePickDialog(std::vector& objects, { ui->setupUi(this); + connect(ui->checkReverse, SIGNAL(toggled(bool)), this, SLOT(onCheckReverse(bool))); connect(ui->checkOtherBody, SIGNAL(toggled(bool)), this, SLOT(onCheckOtherBody(bool))); connect(ui->checkOtherFeature, SIGNAL(toggled(bool)), this, SLOT(onCheckOtherFeature(bool))); connect(ui->radioIndependent, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); connect(ui->radioDependent, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); connect(ui->radioXRef, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); + ui->checkReverse->setChecked(false); ui->checkOtherBody->setChecked(false); ui->checkOtherBody->setEnabled(false); // TODO: implement ui->checkOtherFeature->setChecked(false); @@ -114,6 +116,10 @@ void FeaturePickDialog::updateList() } } +void FeaturePickDialog::onCheckReverse(bool checked) +{ +} + void FeaturePickDialog::onCheckOtherFeature(bool checked) { ui->radioIndependent->setEnabled(checked); @@ -139,6 +145,11 @@ void FeaturePickDialog::onUpdate(bool) updateList(); } +bool FeaturePickDialog::getReverse() +{ + return ui->checkReverse->isChecked(); +} + std::vector FeaturePickDialog::getFeatures() { std::vector result; diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.h b/src/Mod/PartDesign/Gui/FeaturePickDialog.h index 87f0140a66a0..b8f4097ba4cd 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.h +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.h @@ -49,14 +49,17 @@ class FeaturePickDialog : public QDialog ~FeaturePickDialog(); std::vector getFeatures(); + bool getReverse(); void accept(); protected Q_SLOTS: + void onCheckReverse(bool); void onCheckOtherFeature(bool); void onCheckOtherBody(bool); void onUpdate(bool); + private: Ui_FeaturePickDialog* ui; diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.ui b/src/Mod/PartDesign/Gui/FeaturePickDialog.ui index 76e5e728af4a..47728c76b487 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.ui +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.ui @@ -7,7 +7,7 @@ 0 0 318 - 357 + 398 @@ -17,10 +17,24 @@ + + + + Reverse direction + + + + + + + Qt::Horizontal + + + - Allow sketch from other Body + Allow feature from other Body diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 02f278c780f9..d0daf7219f8f 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -162,10 +162,10 @@ void switchToDocument(const App::Document* doc) if (SketchVector == Base::Vector3d(0,0,1)) { Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", sketch->getNameInDocument(), BaseplaneNames[0], side.c_str()); - } else if (SketchVector == Base::Vector3d(1,0,0)) { + } else if (SketchVector == Base::Vector3d(0,1,0)) { Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", sketch->getNameInDocument(), BaseplaneNames[1], side.c_str()); - } else if (SketchVector == Base::Vector3d(0,1,0)) { + } else if (SketchVector == Base::Vector3d(1,0,0)) { Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", sketch->getNameInDocument(), BaseplaneNames[2], side.c_str()); } else { @@ -206,11 +206,11 @@ void switchToDocument(const App::Document* doc) Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[0]); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XY-Plane").toStdString().c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[1]); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); // ... and put them in the 'Origin' group Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", QObject::tr("Origin").toStdString().c_str()); for (unsigned i = 0; i < 3; i++) diff --git a/src/Mod/Start/StartPage/PartDesign.py b/src/Mod/Start/StartPage/PartDesign.py index fc77976f6dd6..8aa1c7b6b130 100644 --- a/src/Mod/Start/StartPage/PartDesign.py +++ b/src/Mod/Start/StartPage/PartDesign.py @@ -22,8 +22,9 @@ #*************************************************************************** import FreeCADGui -FreeCADGui.activateWorkbench("PartDesignWorkbench") +Gui.activateWorkbench("PartDesignWorkbench") App.newDocument() # Make the planes properly visible -FreeCADGui.activeDocument().activeView().viewAxometric() -FreeCADGui.SendMsgToActiveView("ViewFit") +#Gui.ActiveDocument.ActiveView.setCameraOrientation(App.ActiveDocument.BaseplaneXY.Placement.Rotation.Q) +#Gui.activeDocument().activeView().viewAxometric() +#Gui.SendMsgToActiveView("ViewFit") From ba17aa283988fc8652ebb41cda8062f3015c9d62 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 10 May 2013 14:22:02 +0430 Subject: [PATCH 103/664] Try to be consistent with sketch plane orientation PartDesign module <-> Sketcher module --- src/Mod/Part/App/Part2DObject.cpp | 27 +++++++++++++++------------ src/Mod/PartDesign/App/DatumPlane.cpp | 25 ++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index b170d05d5fd2..8bc7f56242bc 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -95,7 +95,10 @@ void Part2DObject::positionBySupport(void) // Set placement identical to the way it used to be done in the Sketcher::SketchOrientationDialog if (dir == Base::Vector3d(0,0,1)) { - Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Reverse ? -1.0 : 0.0, 0.0,0.0,0.0)); + if (Reverse) + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(-1.0, 0.0,0.0,0.0)); + else + Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation()); } else if (dir == Base::Vector3d(0,1,0)) { if (Reverse) Place = Base::Placement(Base::Vector3d(0,0,0),Base::Rotation(Base::Vector3d(0,sqrt(2.0)/2.0,sqrt(2.0)/2.0),M_PI)); @@ -113,18 +116,18 @@ void Part2DObject::positionBySupport(void) Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); Base::Vector3d pos = Place.getPosition(); plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); - } else if (support->getTypeId() == Part::Datum::getClassTypeId()) { + } else if (support->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + const std::vector &sub = Support.getSubValues(); + assert(sub.size()==1); + Part::Datum* pcDatum = static_cast(support); - TopoDS_Shape plane = pcDatum->Shape.getValue(); - if (plane.ShapeType() != TopAbs_FACE) - return; - BRepAdaptor_Surface adapt(TopoDS::Face(plane)); - if (adapt.GetType() != GeomAbs_Plane) - return; - gp_Pln pl = adapt.Plane(); - Base::Vector3d pos(pl.Location().X(), pl.Location().Y(), pl.Location().Z()); - Base::Vector3d normal(pl.Axis().Direction().X(), pl.Axis().Direction().Y(), pl.Axis().Direction().Z()); - this->Placement.setValue(Base::Placement(pos, Base::Rotation(Base::Vector3d(0,0,1), normal))); + Place = pcDatum->Placement.getValue(); + Base::Vector3d dir; + Place.getRotation().multVec(Base::Vector3d(0,0,1),dir); + if (!sub.empty() && (sub[0] == "back")) + dir *= -1.0; + Base::Vector3d pos = Place.getPosition(); + plane = gp_Pln(gp_Pnt(pos.x, pos.y, pos.z), gp_Dir(dir.x, dir.y, dir.z)); } else { Part::Feature *part = static_cast(support); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index 76408b61af03..676588bbf0b9 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -44,6 +44,7 @@ # include # include # include +# include # include # include # include @@ -213,10 +214,10 @@ void Plane::onChanged(const App::Property *prop) normal = new Base::Vector3d; if (strcmp(p->getNameInDocument(), "BaseplaneXY") == 0) *normal = Base::Vector3d(0,0,1); - else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) - *normal = Base::Vector3d(1,0,0); else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) *normal = Base::Vector3d(0,1,0); + else if (strcmp(p->getNameInDocument(), "BaseplaneYZ") == 0) + *normal = Base::Vector3d(1,0,0); } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Part::Feature* feature = static_cast(refs[i]); const TopoDS_Shape& sh = feature->Shape.getValue(); @@ -247,8 +248,26 @@ void Plane::onChanged(const App::Property *prop) BRepAdaptor_Surface adapt(f); if (adapt.GetType() != GeomAbs_Plane) return; // Non-planar face - gp_Pnt b = adapt.Plane().Location(); + + // Ensure that the front and back of the plane corresponds with the face's idea of front and back + bool reverse = (f.Orientation() == TopAbs_REVERSED); + gp_Pln plane = adapt.Plane(); + if (!plane.Direct()) { + // toggle if plane has a left-handed coordinate system + plane.UReverse(); + reverse = !reverse; + } gp_Dir d = adapt.Plane().Axis().Direction(); + if (reverse) d.Reverse(); + + // Ensure that the position of the placement corresponds to what the face would yield in + // Part2DObject::positionBySupport() + Base::Vector3d pos = feature->Placement.getValue().getPosition(); + gp_Pnt gp_pos(pos.x,pos.y,pos.z); + Handle (Geom_Plane) gPlane = new Geom_Plane(plane); + GeomAPI_ProjectPointOnSurf projector(gp_pos,gPlane); + gp_Pnt b = projector.NearestPoint(); + p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); } From bc7dff73394f6ceb451861ef458f7f5789124fcf Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 10 May 2013 15:32:13 +0430 Subject: [PATCH 104/664] Moved unsetEdit() to ViewProvider to avoid code duplication in all feature ViewProviders --- src/Mod/PartDesign/Gui/ViewProvider.cpp | 22 +++++++++++++++++++ src/Mod/PartDesign/Gui/ViewProvider.h | 2 ++ .../PartDesign/Gui/ViewProviderChamfer.cpp | 14 ------------ src/Mod/PartDesign/Gui/ViewProviderChamfer.h | 1 - src/Mod/PartDesign/Gui/ViewProviderDraft.cpp | 14 ------------ src/Mod/PartDesign/Gui/ViewProviderDraft.h | 1 - src/Mod/PartDesign/Gui/ViewProviderFillet.cpp | 14 ------------ src/Mod/PartDesign/Gui/ViewProviderFillet.h | 1 - src/Mod/PartDesign/Gui/ViewProviderGroove.cpp | 14 ------------ src/Mod/PartDesign/Gui/ViewProviderGroove.h | 3 +-- src/Mod/PartDesign/Gui/ViewProviderPad.cpp | 14 ------------ src/Mod/PartDesign/Gui/ViewProviderPad.h | 1 - src/Mod/PartDesign/Gui/ViewProviderPocket.cpp | 14 ------------ src/Mod/PartDesign/Gui/ViewProviderPocket.h | 1 - .../PartDesign/Gui/ViewProviderRevolution.cpp | 14 ------------ .../PartDesign/Gui/ViewProviderRevolution.h | 1 - 16 files changed, 25 insertions(+), 106 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 89658c81a5e8..dfe39e3eb938 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,27 @@ bool ViewProvider::doubleClicked(void) return true; } +void ViewProvider::unsetEdit(int ModNum) +{ + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + if ((PartDesignGui::ActivePartObject != NULL) && (oldTip != NULL)) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + } + oldTip = NULL; + } + else { + PartGui::ViewProviderPart::unsetEdit(ModNum); + oldTip = NULL; + } +} + void ViewProvider::updateData(const App::Property* prop) { if (prop->getTypeId() == Part::PropertyPartShape::getClassTypeId() && diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 178f84afd7ea..7dff03edb36a 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -43,6 +43,8 @@ class PartDesignGuiExport ViewProvider : public PartGui::ViewProviderPart { void updateData(const App::Property*); protected: + virtual void unsetEdit(int ModNum); + std::string oldWb; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp index 490c01b6931b..7be0f498f216 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp @@ -102,20 +102,6 @@ bool ViewProviderChamfer::setEdit(int ModNum) } } -void ViewProviderChamfer::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default ) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderChamfer::onDelete(const std::vector &s) { return ViewProvider::onDelete(s); diff --git a/src/Mod/PartDesign/Gui/ViewProviderChamfer.h b/src/Mod/PartDesign/Gui/ViewProviderChamfer.h index 4393f9a7df65..507a7bb0eb6b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderChamfer.h +++ b/src/Mod/PartDesign/Gui/ViewProviderChamfer.h @@ -46,7 +46,6 @@ class PartDesignGuiExport ViewProviderChamfer : public ViewProvider protected: virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp index 7d8b60f0770b..a4632d4dab35 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp @@ -102,20 +102,6 @@ bool ViewProviderDraft::setEdit(int ModNum) } } -void ViewProviderDraft::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default ) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderDraft::onDelete(const std::vector &s) { return ViewProvider::onDelete(s); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.h b/src/Mod/PartDesign/Gui/ViewProviderDraft.h index 07829d2eadd5..0709c8f40f16 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.h @@ -46,7 +46,6 @@ class PartDesignGuiExport ViewProviderDraft : public ViewProvider protected: virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp index 0882ce5760a3..db604d595f65 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp @@ -102,20 +102,6 @@ bool ViewProviderFillet::setEdit(int ModNum) } } -void ViewProviderFillet::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default ) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderFillet::onDelete(const std::vector &s) { return ViewProvider::onDelete(s); diff --git a/src/Mod/PartDesign/Gui/ViewProviderFillet.h b/src/Mod/PartDesign/Gui/ViewProviderFillet.h index 0c9a01ff1408..f2f80df7c2d7 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderFillet.h +++ b/src/Mod/PartDesign/Gui/ViewProviderFillet.h @@ -46,7 +46,6 @@ class PartDesignGuiExport ViewProviderFillet : public ViewProvider protected: virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp index cbfa9b3d3c5a..09b120110ed8 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp @@ -119,20 +119,6 @@ bool ViewProviderGroove::setEdit(int ModNum) } } -void ViewProviderGroove::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderGroove::onDelete(const std::vector &s) { // get the Sketch diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.h b/src/Mod/PartDesign/Gui/ViewProviderGroove.h index 6f02326e3066..c569d3dfca40 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderGroove.h +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.h @@ -47,8 +47,7 @@ class PartDesignGuiExport ViewProviderGroove : public ViewProvider virtual bool onDelete(const std::vector &); protected: - virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); + virtual bool setEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp index 131e8b1451d9..4204ca62dfa5 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp @@ -116,20 +116,6 @@ bool ViewProviderPad::setEdit(int ModNum) } } -void ViewProviderPad::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderPad::onDelete(const std::vector &s) { PartDesign::Pad* pcPad = static_cast(getObject()); diff --git a/src/Mod/PartDesign/Gui/ViewProviderPad.h b/src/Mod/PartDesign/Gui/ViewProviderPad.h index 597a140c683e..71fb2c334c22 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPad.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPad.h @@ -47,7 +47,6 @@ class PartDesignGuiExport ViewProviderPad : public ViewProvider protected: virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp index 4df05c235365..23d04a981b50 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp @@ -109,20 +109,6 @@ bool ViewProviderPocket::setEdit(int ModNum) } } -void ViewProviderPocket::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default ) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderPocket::onDelete(const std::vector &s) { // get the Sketch diff --git a/src/Mod/PartDesign/Gui/ViewProviderPocket.h b/src/Mod/PartDesign/Gui/ViewProviderPocket.h index 701cb77ff623..56e10d63f895 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPocket.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPocket.h @@ -47,7 +47,6 @@ class PartDesignGuiExport ViewProviderPocket : public ViewProvider protected: virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp index caa00dd8f0c4..05b18d4d91ae 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp @@ -119,20 +119,6 @@ bool ViewProviderRevolution::setEdit(int ModNum) } } -void ViewProviderRevolution::unsetEdit(int ModNum) -{ - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } -} - bool ViewProviderRevolution::onDelete(const std::vector &s) { // get the Sketch diff --git a/src/Mod/PartDesign/Gui/ViewProviderRevolution.h b/src/Mod/PartDesign/Gui/ViewProviderRevolution.h index faad403d5cb3..a2dbeaeaf6d1 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderRevolution.h +++ b/src/Mod/PartDesign/Gui/ViewProviderRevolution.h @@ -48,7 +48,6 @@ class PartDesignGuiExport ViewProviderRevolution : public ViewProvider protected: virtual bool setEdit(int ModNum); - virtual void unsetEdit(int ModNum); }; From 3b95517a70ad16f0d192c6da803b1761668aecbb Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 10 May 2013 15:33:26 +0430 Subject: [PATCH 105/664] Drop into insert mode when user double-clicks on a PartDesign feature in the Tree --- src/Mod/PartDesign/Gui/Command.cpp | 3 ++ src/Mod/PartDesign/Gui/ViewProvider.cpp | 11 +++++++ src/Mod/PartDesign/Gui/ViewProvider.h | 1 + src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 30 +++++++++++++++++++ src/Mod/PartDesign/Gui/ViewProviderDatum.h | 2 ++ .../Gui/ViewProviderTransformed.cpp | 11 ++++++- 6 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index e074842a9d66..fe0aa261a6d1 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -199,6 +199,9 @@ void CmdPartDesignMoveTip::activated(int iMsg) prevSolidFeature = pcActiveBody->getPrevSolidFeature(); if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + + // TOOD: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see + // others, so we would have to remember their state somehow } bool CmdPartDesignMoveTip::isActive(void) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index dfe39e3eb938..a0b9de8a885e 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -41,6 +41,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProvider,PartGui::ViewProviderPart) ViewProvider::ViewProvider() { + oldWb = ""; + oldTip = NULL; } ViewProvider::~ViewProvider() @@ -52,6 +54,15 @@ bool ViewProvider::doubleClicked(void) std::string Msg("Edit "); Msg += this->pcObject->Label.getValue(); Gui::Command::openCommand(Msg.c_str()); + if (PartDesignGui::ActivePartObject != NULL) { + // Drop into insert mode so that the user doesn't see all the geometry that comes later in the tree + // Also, this way the user won't be tempted to use future geometry as external references for the sketch + oldTip = ActivePartObject->Tip.getValue(); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + } else { + oldTip = NULL; + } + try { Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); } diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 7dff03edb36a..32926f154b0e 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -46,6 +46,7 @@ class PartDesignGuiExport ViewProvider : public PartGui::ViewProviderPart { virtual void unsetEdit(int ModNum); std::string oldWb; + App::DocumentObject* oldTip; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index c5aafe547d32..cbefe3883844 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -68,6 +68,9 @@ ViewProviderDatum::ViewProviderDatum() { pShapeSep = new SoSeparator(); pShapeSep->ref(); + + oldWb = ""; + oldTip = NULL; } ViewProviderDatum::~ViewProviderDatum() @@ -253,6 +256,24 @@ bool ViewProviderDatum::setEdit(int ModNum) } } +bool ViewProviderDatum::doubleClicked(void) +{ + std::string Msg("Edit "); + Msg += this->pcObject->Label.getValue(); + Gui::Command::openCommand(Msg.c_str()); + if (PartDesignGui::ActivePartObject != NULL) { + // Drop into insert mode so that the user doesn't see all the geometry that comes later in the tree + // Also, this way the user won't be tempted to use future geometry as external references for the sketch + oldTip = ActivePartObject->Tip.getValue(); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + } else { + oldTip = NULL; + } + + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); + return true; +} + void ViewProviderDatum::unsetEdit(int ModNum) { // return to the WB we were in before editing the PartDesign feature @@ -261,6 +282,15 @@ void ViewProviderDatum::unsetEdit(int ModNum) if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog Gui::Control().closeDialog(); + + if ((PartDesignGui::ActivePartObject != NULL) && (oldTip != NULL)) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + oldTip = NULL; + } else { + oldTip = NULL; + } } else { Gui::ViewProviderGeometryObject::unsetEdit(ModNum); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.h b/src/Mod/PartDesign/Gui/ViewProviderDatum.h index c73c2183a336..db4c48c9c2ae 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.h @@ -44,6 +44,7 @@ class PartDesignGuiExport ViewProviderDatum : public Gui::ViewProviderGeometryOb virtual void attach(App::DocumentObject *); virtual bool onDelete(const std::vector &); virtual void updateData(const App::Property* prop) { Gui::ViewProviderGeometryObject::updateData(prop); } + virtual bool doubleClicked(void); std::vector getDisplayModes(void) const; void setDisplayMode(const char* ModeName); @@ -66,6 +67,7 @@ class PartDesignGuiExport ViewProviderDatum : public Gui::ViewProviderGeometryOb protected: SoSeparator* pShapeSep; std::string oldWb; + App::DocumentObject* oldTip; }; diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index 60f2cfd6a289..249b229721fa 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -47,6 +47,7 @@ # include #endif +#include "Workbench.h" #include "ViewProviderTransformed.h" #include "TaskTransformedParameters.h" #include @@ -136,7 +137,15 @@ void ViewProviderTransformed::unsetEdit(int ModNum) if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); + Gui::Control().closeDialog(); + if ((PartDesignGui::ActivePartObject != NULL) && (oldTip != NULL)) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + oldTip = NULL; + } else { + oldTip = NULL; + } } else { PartGui::ViewProviderPart::unsetEdit(ModNum); From 6915d8b7342f5b88ce82b00d897fb7da35fa420a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 10 May 2013 20:56:35 +0430 Subject: [PATCH 106/664] Miscellaneous fixes --- src/Mod/Part/App/BodyBase.h | 3 ++- src/Mod/Part/App/CMakeLists.txt | 1 + src/Mod/Part/App/DatumFeature.cpp | 1 - src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp | 2 +- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 7 ++++--- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Mod/Part/App/BodyBase.h b/src/Mod/Part/App/BodyBase.h index 6ed022060133..dc0b2dfbaff8 100644 --- a/src/Mod/Part/App/BodyBase.h +++ b/src/Mod/Part/App/BodyBase.h @@ -69,7 +69,8 @@ class PartExport BodyBase : public Part::Feature * That is, sketches and datum features are skipped * If inclusive is true, start or the Tip is returned if it is a solid feature */ - virtual App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true){} + virtual App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true) + { return NULL; } /// Return the body which this feature belongs too, or NULL static BodyBase* findBodyOf(const App::DocumentObject* f); diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 8889304405ef..7c499acf11a4 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -16,6 +16,7 @@ include_directories( ${Boost_INCLUDE_DIRS} ${OCC_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS} + ${QT_INCLUDE_DIR} ${XercesC_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} ${FREETYPE_INCLUDE_DIRS} diff --git a/src/Mod/Part/App/DatumFeature.cpp b/src/Mod/Part/App/DatumFeature.cpp index a4fe088c3607..407288be0403 100644 --- a/src/Mod/Part/App/DatumFeature.cpp +++ b/src/Mod/Part/App/DatumFeature.cpp @@ -55,7 +55,6 @@ # include #endif -#include #include #include "DatumFeature.h" #include diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index a1bfb78cda0f..6f855c37c1e2 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -155,7 +155,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) m /= points.size(); // Sort by angles - double a[points.size()]; + std::vector a(points.size()); for (int i = 0; i < points.size() - 1; i++) { if (longest == 0) a[i] = atan2(points[i].z - m.z, points[i].y - m.y); diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 4f033ab33a26..49b1fca37828 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4486,9 +4486,9 @@ namespace SketcherGui { if (!sSubName || sSubName[0] == '\0') return false; std::string element(sSubName); - // for the moment we allow only edges and vertices if ((element.size() > 4 && element.substr(0,4) == "Edge") || - (element.size() > 6 && element.substr(0,6) == "Vertex")) { + (element.size() > 6 && element.substr(0,6) == "Vertex") || + (element.size() > 4 && element.substr(0,4) == "Face")) { return true; } return false; @@ -4596,7 +4596,8 @@ class DrawSketchHandlerExternal: public DrawSketchHandler if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || (subName.size() > 4 && subName.substr(0,4) == "Edge") || - (subName.size() > 6 && subName.substr(0,6) == "Vertex")) { + (subName.size() > 6 && subName.substr(0,6) == "Vertex") || + (subName.size() > 4 && subName.substr(0,4) == "Face")) { try { Gui::Command::openCommand("Add external geometry"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.addExternal(\"%s\",\"%s\")", From 0bcdb0511f90160c607edd817b706461562c7fce Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 11 May 2013 20:17:49 +0430 Subject: [PATCH 107/664] Added Reversed button to Pocket UI if the sketch plane is a datum plane --- src/Mod/PartDesign/App/Feature.cpp | 8 ++++++++ src/Mod/PartDesign/App/Feature.h | 2 ++ src/Mod/PartDesign/App/FeaturePocket.cpp | 3 +++ src/Mod/PartDesign/App/FeatureSketchBased.cpp | 8 ++++++++ src/Mod/PartDesign/App/FeatureSketchBased.h | 6 ++++-- src/Mod/PartDesign/Gui/TaskPocketParameters.cpp | 16 +++++++++++++--- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 1 + src/Mod/PartDesign/Gui/TaskPocketParameters.ui | 2 +- 8 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 01247100b971..40014cfae443 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -34,8 +34,10 @@ #include #include "App/Document.h" +#include "App/Plane.h" #include "Body.h" #include "Feature.h" +#include "Mod/Part/App/DatumFeature.h" #include @@ -106,4 +108,10 @@ const TopoDS_Shape& Feature::getBaseShape() const { return result; } +bool Feature::isDatum(const App::DocumentObject* feature) +{ + return feature->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + feature->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()); +} + } diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 3fe92e7619ae..050a73cea90c 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -64,6 +64,8 @@ class PartDesignExport Feature : public Part::Feature /// Grab any point from the given face static const gp_Pnt getPointFromFace(const TopoDS_Face& f); + /// Check whether the given feature is a datum feature + static bool isDatum(const App::DocumentObject* feature); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 35b7391179f3..17374f5e88b4 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -145,6 +145,9 @@ App::DocumentObjectExecReturn *Pocket::execute(void) TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); + if (Reversed.getValue()) + dir.Reverse(); + // Find a valid face to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 3a46b199443f..2114d447d339 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -930,6 +930,14 @@ bool SketchBased::isParallelPlane(const TopoDS_Shape& s1, const TopoDS_Shape& s2 return false; } +bool SketchBased::isSupportDatum() const +{ + Part::Feature* SupportObject = getSupport(); + if (SupportObject == NULL) + throw Base::Exception("No support in Sketch!"); + return isDatum(SupportObject); +} + TopoDS_Shape SketchBased::refineShapeIfActive(const TopoDS_Shape& oldShape) const { Base::Reference hGrp = App::GetApplication().GetUserParameter() diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 7284df649165..7bce5fb2a926 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -73,15 +73,17 @@ class PartDesignExport SketchBased : public PartDesign::Feature Part::Feature* getSupport() const; /// Returns the sketch support shape (if any) const TopoDS_Shape& getSupportShape() const; + /// Check whether the sketch support is a datum plane + bool isSupportDatum() const; /// retrieves the number of axes in the linked sketch (defined as construction lines) - int getSketchAxisCount(void) const; + int getSketchAxisCount(void) const; protected: void onChanged(const App::Property* prop); TopoDS_Face validateFace(const TopoDS_Face&) const; TopoDS_Shape makeFace(const std::vector&) const; - TopoDS_Shape makeFace(std::list&) const; // for internal use only + TopoDS_Shape makeFace(std::list&) const; // for internal use only bool isInside(const TopoDS_Wire&, const TopoDS_Wire&) const; bool isParallelPlane(const TopoDS_Shape&, const TopoDS_Shape&) const; bool isEqualGeometry(const TopoDS_Shape&, const TopoDS_Shape&) const; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 4e9bce7f8017..20c1967d6282 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -120,7 +120,6 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->changeMode->insertItem(2, tr("To first")); ui->changeMode->insertItem(3, tr("Up to face")); ui->changeMode->setCurrentIndex(index); - ui->checkBoxMidplane->setChecked(midplane); // Bind input fields to properties ui->pocketLength->bind(pcPocket->Length); @@ -131,6 +130,10 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->buttonFace->blockSignals(false); ui->lineFaceName->blockSignals(false); ui->changeMode->blockSignals(false); + + // Activate the Reverse option only if the support is a datum plane + ui->checkBoxReversed->setVisible(pcPocket->isSupportDatum()); + updateUI(index); //// check if the sketch has support @@ -152,6 +155,7 @@ void TaskPocketParameters::updateUI(int index) ui->pocketLength->selectAll(); QMetaObject::invokeMethod(ui->pocketLength, "setFocus", Qt::QueuedConnection); ui->checkBoxMidplane->setEnabled(true); + // Reverse only makes sense if Midplane is not true ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of dimension ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); @@ -167,8 +171,8 @@ void TaskPocketParameters::updateUI(int index) ui->pocketLength->setEnabled(false); ui->checkBoxMidplane->setEnabled(false); // Can't have a midplane to a single face ui->checkBoxReversed->setEnabled(false); // Will change the direction it seeks for its first face? - // Doesnt work so is currently disabled. Fix probably lies - // somwhere in IF block on line 125 of FeaturePocket.cpp + // Doesnt work so is currently disabled. Fix probably lies + // somwhere in IF block on line 125 of FeaturePocket.cpp ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); onButtonFace(false); @@ -366,6 +370,11 @@ double TaskPocketParameters::getLength(void) const return ui->pocketLength->value().getValue(); } +bool TaskPocketParameters::getReversed(void) const +{ + return ui->checkBoxReversed->isChecked(); +} + int TaskPocketParameters::getMode(void) const { return ui->changeMode->currentIndex(); @@ -434,6 +443,7 @@ void TaskPocketParameters::apply() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), buf.toStdString().c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", name.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),getReversed()?1:0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!PocketView->getObject()->isValid()) throw Base::Exception(PocketView->getObject()->getStatusString()); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index ad5ef90dea6e..43e4a31263a5 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -52,6 +52,7 @@ class TaskPocketParameters : public Gui::TaskView::TaskBox, public Gui::Selectio TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent = 0); ~TaskPocketParameters(); + bool getReversed(void) const; QByteArray getFaceName(void) const; const bool updateView() const; void apply(); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui index 43a78e376311..5a1f41c07702 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui @@ -7,7 +7,7 @@ 0 0 241 - 192 + 188 From b8156566491c9619c3019daa1ec5595c0e630146 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 14 May 2013 11:07:14 +0430 Subject: [PATCH 108/664] Refactored code of SketchBased features to have common code in an abstract superclass --- src/Mod/PartDesign/App/FeaturePad.h | 1 - src/Mod/PartDesign/App/FeaturePocket.h | 1 - src/Mod/PartDesign/App/FeatureRevolution.cpp | 28 +- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 4 +- src/Mod/PartDesign/App/FeatureSketchBased.h | 4 +- src/Mod/PartDesign/Gui/CMakeLists.txt | 3 + .../PartDesign/Gui/TaskGrooveParameters.cpp | 32 +-- src/Mod/PartDesign/Gui/TaskGrooveParameters.h | 21 +- .../Gui/TaskGrooveParameters.h.orig | 117 ++++++++ src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 176 ++---------- src/Mod/PartDesign/Gui/TaskPadParameters.h | 22 +- .../PartDesign/Gui/TaskPadParameters.h.orig | 121 ++++++++ .../PartDesign/Gui/TaskPocketParameters.cpp | 179 ++---------- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 23 +- .../Gui/TaskPocketParameters.h.orig | 119 ++++++++ .../Gui/TaskRevolutionParameters.cpp | 76 +---- .../PartDesign/Gui/TaskRevolutionParameters.h | 29 +- .../Gui/TaskRevolutionParameters.h.orig | 111 ++++++++ .../Gui/TaskSketchBasedParameters.cpp | 266 ++++++++++++++++++ .../Gui/TaskSketchBasedParameters.h | 97 +++++++ 20 files changed, 948 insertions(+), 482 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskGrooveParameters.h.orig create mode 100644 src/Mod/PartDesign/Gui/TaskPadParameters.h.orig create mode 100644 src/Mod/PartDesign/Gui/TaskPocketParameters.h.orig create mode 100644 src/Mod/PartDesign/Gui/TaskRevolutionParameters.h.orig create mode 100644 src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h index a3a7cebdf31b..510bf20fe4b5 100644 --- a/src/Mod/PartDesign/App/FeaturePad.h +++ b/src/Mod/PartDesign/App/FeaturePad.h @@ -42,7 +42,6 @@ class PartDesignExport Pad : public Additive App::PropertyEnumeration Type; App::PropertyLength Length; App::PropertyLength Length2; - App::PropertyLinkSub UpToFace; /** @name methods override feature */ //@{ diff --git a/src/Mod/PartDesign/App/FeaturePocket.h b/src/Mod/PartDesign/App/FeaturePocket.h index 1b15957eede9..57b298e77e7c 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.h +++ b/src/Mod/PartDesign/App/FeaturePocket.h @@ -39,7 +39,6 @@ class PartDesignExport Pocket : public Subtractive App::PropertyEnumeration Type; App::PropertyLength Length; - App::PropertyLinkSub UpToFace; /** @name methods override feature */ //@{ diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 67b888685aa9..83b9f69f25a4 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -93,12 +93,18 @@ App::DocumentObjectExecReturn *Revolution::execute(void) return new App::DocumentObjectExecReturn(e.what()); } - TopoDS_Shape support; + // if the Base property has a valid shape, fuse the AddShape into it + TopoDS_Shape base; try { - support = getSupportShape(); + base = getBaseShape(); } catch (const Base::Exception&) { - // ignore, because support isn't mandatory - support = TopoDS_Shape(); + // fall back to support (for legacy features) + try { + base = getSupportShape(); + } catch (const Base::Exception&) { + // ignore, because support isn't mandatory + base = TopoDS_Shape(); + } } // update Axis from ReferenceAxis @@ -127,7 +133,7 @@ App::DocumentObjectExecReturn *Revolution::execute(void) TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); - support.Move(invObjLoc); + base.Move(invObjLoc); sketchshape.Move(invObjLoc); // Check distance between sketchshape and axis - to avoid failures and crashes @@ -141,17 +147,7 @@ App::DocumentObjectExecReturn *Revolution::execute(void) TopoDS_Shape result = RevolMaker.Shape(); result = refineShapeIfActive(result); // set the additive shape property for later usage in e.g. pattern - this->AddShape.setValue(result); - - // if the Base property has a valid shape, fuse the AddShape into it - TopoDS_Shape base; - try { - base = getBaseShape(); - base.Move(invObjLoc); - } catch (const Base::Exception&) { - // fall back to support (for legacy features) - base = support; - } + this->AddShape.setValue(result); if (!base.IsNull()) { // Let's call algorithm computing a fuse operation: diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 2114d447d339..fe3a4703219b 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -101,13 +101,15 @@ SketchBased::SketchBased() ADD_PROPERTY_TYPE(Sketch,(0),"SketchBased", App::Prop_None, "Reference to sketch"); ADD_PROPERTY_TYPE(Midplane,(0),"SketchBased", App::Prop_None, "Extrude symmetric to sketch face"); ADD_PROPERTY_TYPE(Reversed, (0),"SketchBased", App::Prop_None, "Reverse extrusion direction"); + ADD_PROPERTY_TYPE(UpToFace,(0),"SketchBased",(App::PropertyType)(App::Prop_None),"Face where feature will end"); } short SketchBased::mustExecute() const { if (Sketch.isTouched() || Midplane.isTouched() || - Reversed.isTouched()) + Reversed.isTouched() || + UpToFace.isTouched()) return 1; return PartDesign::Feature::mustExecute(); } diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 7bce5fb2a926..d56b97b0a194 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -50,7 +50,9 @@ class PartDesignExport SketchBased : public PartDesign::Feature /// Reverse extrusion direction App::PropertyBool Reversed; /// Make extrusion symmetric to sketch plane - App::PropertyBool Midplane; + App::PropertyBool Midplane; + /// Face to extrude up to + App::PropertyLinkSub UpToFace; short mustExecute() const; diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index e9f868e8d2c2..b0e60d69bb1e 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -29,6 +29,7 @@ set(PartDesignGui_LIBS set(PartDesignGui_MOC_HDRS FeaturePickDialog.h + TaskSketchBasedParameters.h TaskPadParameters.h TaskPocketParameters.h TaskChamferParameters.h @@ -121,6 +122,8 @@ SET(PartDesignGuiTaskDlgs_SRCS FeaturePickDialog.h ReferenceSelection.cpp ReferenceSelection.h + TaskSketchBasedParameters.cpp + TaskSketchBasedParameters.h TaskPadParameters.ui TaskPadParameters.cpp TaskPadParameters.h diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index 38f9eabe212b..d7e2f1ddb268 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -50,7 +50,7 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskGrooveParameters */ TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Groove"),tr("Groove parameters"),true, parent),GrooveView(GrooveView) + : TaskSketchBasedParameters(GrooveView, parent, "PartDesign_Groove",tr("Groove parameters")) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -77,7 +77,7 @@ TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidge ui->checkBoxMidplane->blockSignals(true); ui->checkBoxReversed->blockSignals(true); - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); double l = pcGroove->Angle.getValue(); bool mirrored = pcGroove->Midplane.getValue(); bool reversed = pcGroove->Reversed.getValue(); @@ -126,7 +126,7 @@ TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidge void TaskGrooveParameters::onAngleChanged(double len) { - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Angle.setValue(len); if (updateView()) pcGroove->getDocument()->recomputeFeature(pcGroove); @@ -134,7 +134,7 @@ void TaskGrooveParameters::onAngleChanged(double len) void TaskGrooveParameters::onAxisChanged(int num) { - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); if (pcSketch) { App::DocumentObject *oldRefAxis = pcGroove->ReferenceAxis.getValue(); @@ -172,7 +172,7 @@ void TaskGrooveParameters::onAxisChanged(int num) void TaskGrooveParameters::onMidplane(bool on) { - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Midplane.setValue(on); if (updateView()) pcGroove->getDocument()->recomputeFeature(pcGroove); @@ -180,20 +180,12 @@ void TaskGrooveParameters::onMidplane(bool on) void TaskGrooveParameters::onReversed(bool on) { - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Reversed.setValue(on); if (updateView()) pcGroove->getDocument()->recomputeFeature(pcGroove); } -void TaskGrooveParameters::onUpdateView(bool on) -{ - if (on) { - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); - pcGroove->getDocument()->recomputeFeature(pcGroove); - } -} - double TaskGrooveParameters::getAngle(void) const { return ui->grooveAngle->value().getValue(); @@ -202,7 +194,7 @@ double TaskGrooveParameters::getAngle(void) const QString TaskGrooveParameters::getReferenceAxis(void) const { // get the support and Sketch - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); QString buf; @@ -254,7 +246,7 @@ void TaskGrooveParameters::changeEvent(QEvent *e) void TaskGrooveParameters::apply() { - App::DocumentObject* groove = GrooveView->getObject(); + App::DocumentObject* groove = vp->getObject(); std::string name = groove->getNameInDocument(); // retrieve sketch and its support object @@ -290,10 +282,10 @@ void TaskGrooveParameters::apply() //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TaskDlgGrooveParameters::TaskDlgGrooveParameters(ViewProviderGroove *GrooveView) - : TaskDialog(),GrooveView(GrooveView) + : TaskDlgSketchBasedParameters(GrooveView) { - assert(GrooveView); - parameter = new TaskGrooveParameters(GrooveView); + assert(vp); + parameter = new TaskGrooveParameters(static_cast(vp)); Content.push_back(parameter); } @@ -329,7 +321,7 @@ bool TaskDlgGrooveParameters::accept() bool TaskDlgGrooveParameters::reject() { // get the support and Sketch - PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = 0; if (pcGroove->Sketch.getValue()) { pcSketch = static_cast(pcGroove->Sketch.getValue()); diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h index dbc5f9d4e05a..d98aaddd3356 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h @@ -29,6 +29,7 @@ #include #include "ViewProviderGroove.h" +#include "TaskSketchBasedParameters.h" class Ui_TaskGrooveParameters; @@ -44,7 +45,7 @@ namespace PartDesignGui { -class TaskGrooveParameters : public Gui::TaskView::TaskBox +class TaskGrooveParameters : public TaskSketchBasedParameters { Q_OBJECT @@ -59,9 +60,9 @@ private Q_SLOTS: void onAxisChanged(int); void onMidplane(bool); void onReversed(bool); - void onUpdateView(bool); protected: + void onSelectionChanged(const Gui::SelectionChanges& msg) {} void changeEvent(QEvent *e); QString getReferenceAxis(void) const; double getAngle(void) const; @@ -74,11 +75,10 @@ private Q_SLOTS: private: QWidget* proxy; Ui_TaskGrooveParameters* ui; - ViewProviderGroove *GrooveView; }; /// simulation dialog for the TaskView -class TaskDlgGrooveParameters : public Gui::TaskView::TaskDialog +class TaskDlgGrooveParameters : public TaskDlgSketchBasedParameters { Q_OBJECT @@ -87,28 +87,19 @@ class TaskDlgGrooveParameters : public Gui::TaskView::TaskDialog ~TaskDlgGrooveParameters(); ViewProviderGroove* getGrooveView() const - { return GrooveView; } - + { return static_cast(vp); } public: /// is called the TaskView when the dialog is opened virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role + /// is called by the framework if an button is clicked which has no accept or reject role^M virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); /// is called by the framework if the dialog is rejected (Cancel) virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } protected: - ViewProviderGroove *GrooveView; - TaskGrooveParameters *parameter; }; diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h.orig b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h.orig new file mode 100644 index 000000000000..edd38bf57626 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h.orig @@ -0,0 +1,117 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 GUI_TASKVIEW_TaskGrooveParameters_H +#define GUI_TASKVIEW_TaskGrooveParameters_H + +#include +#include +#include + +#include "ViewProviderGroove.h" +#include "TaskSketchBasedParameters.h" + +class Ui_TaskGrooveParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartDesignGui { + + + +class TaskGrooveParameters : public TaskSketchBasedParameters +{ + Q_OBJECT + +public: + TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent = 0); + ~TaskGrooveParameters(); + + void apply(); + +private Q_SLOTS: + void onAngleChanged(double); + void onAxisChanged(int); + void onMidplane(bool); + void onReversed(bool); + +protected: + void onSelectionChanged(const Gui::SelectionChanges& msg) {} + void changeEvent(QEvent *e); + QString getReferenceAxis(void) const; + double getAngle(void) const; + bool getMidplane(void) const; + bool getReversed(void) const; + const bool updateView() const; + +private: + +private: + QWidget* proxy; + Ui_TaskGrooveParameters* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgGrooveParameters : public TaskDlgSketchBasedParameters +{ + Q_OBJECT + +public: + TaskDlgGrooveParameters(ViewProviderGroove *GrooveView); + ~TaskDlgGrooveParameters(); + + ViewProviderGroove* getGrooveView() const + { return static_cast(vp); } + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role^M + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); +<<<<<<< 0973b40e8e489ddbf6455e9a2e80b0520f143b58 + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } +======= +>>>>>>> Refactored code of SketchBased features to have common code in an abstract superclass + +protected: + TaskGrooveParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 179b5ea00532..51ff1cfc9f8a 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -46,6 +46,7 @@ #include #include #include +#include "TaskSketchBasedParameters.h" #include "ReferenceSelection.h" #include "Workbench.h" @@ -55,7 +56,7 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskPadParameters */ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Pad"),tr("Pad parameters"),true, parent),PadView(PadView) + : TaskSketchBasedParameters(PadView, parent, "PartDesign_Pad",tr("Pad parameters")) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -96,7 +97,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg ui->lengthEdit2->setParamGrpPath(QByteArray("User parameter:BaseApp/History/PadLength2")); // Get the feature data - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); Base::Quantity l = pcPad->Length.getQuantityValue(); bool midplane = pcPad->Midplane.getValue(); bool reversed = pcPad->Reversed.getValue(); @@ -212,40 +213,22 @@ void TaskPadParameters::updateUI(int index) void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { - // Don't allow selection in other document - if (strcmp(msg.pDocName, PadView->getObject()->getDocument()->getName()) != 0) - return; - - if (!msg.pSubName || msg.pSubName[0] == '\0') - return; - std::string subName(msg.pSubName); - if (subName.substr(0,4) != "Face") - return; - int faceId = std::atoi(&subName[4]); - - // Don't allow selection outside support - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - Part::Feature* support = pcPad->getSupport(); - if (support == NULL) { - // There is no support, so we can't select from it... + QString refText = onAddSelection(msg); + if (refText.length() != 0) { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->setText(refText); + ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); + ui->lineFaceName->blockSignals(false); // Turn off reference selection mode onButtonFace(false); - return; + } else { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->setText(tr("No face selected")); + ui->lineFaceName->setProperty("FaceName", QByteArray()); + ui->lineFaceName->blockSignals(false); } - if (strcmp(msg.pObjectName, support->getNameInDocument()) != 0) - return; - - std::vector upToFaces(1,subName); - pcPad->UpToFace.setValue(support, upToFaces); - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->setText(tr("Face") + QString::number(faceId)); - ui->lineFaceName->setProperty("FaceName", QByteArray(subName.c_str())); - ui->lineFaceName->blockSignals(false); - // Turn off reference selection mode - onButtonFace(false); } + else if (msg.Type == Gui::SelectionChanges::ClrSelection) { ui->lineFaceName->blockSignals(true); ui->lineFaceName->setText(tr("")); @@ -256,7 +239,7 @@ void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg) void TaskPadParameters::onLengthChanged(double len) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Length.setValue(len); if (updateView()) pcPad->getDocument()->recomputeFeature(pcPad); @@ -264,7 +247,7 @@ void TaskPadParameters::onLengthChanged(double len) void TaskPadParameters::onMidplane(bool on) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Midplane.setValue(on); ui->checkBoxReversed->setEnabled(!on); if (updateView()) @@ -273,7 +256,7 @@ void TaskPadParameters::onMidplane(bool on) void TaskPadParameters::onReversed(bool on) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Reversed.setValue(on); if (updateView()) pcPad->getDocument()->recomputeFeature(pcPad); @@ -281,7 +264,7 @@ void TaskPadParameters::onReversed(bool on) void TaskPadParameters::onLength2Changed(double len) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Length2.setValue(len); if (updateView()) pcPad->getDocument()->recomputeFeature(pcPad); @@ -289,7 +272,7 @@ void TaskPadParameters::onLength2Changed(double len) void TaskPadParameters::onModeChanged(int index) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); switch (index) { case 0: @@ -312,30 +295,6 @@ void TaskPadParameters::onModeChanged(int index) void TaskPadParameters::onButtonFace(const bool pressed) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - Part::Feature* support = pcPad->getSupport(); - if (support == NULL) { - // There is no support, so we can't select from it... - return; - } - - if (pressed) { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setHide(PadView->getObject()->getNameInDocument()); - doc->setShow(support->getNameInDocument()); - } - Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate - (new ReferenceSelection(support, false, true, false)); - } else { - Gui::Selection().rmvSelectionGate(); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setShow(PadView->getObject()->getNameInDocument()); - doc->setHide(support->getNameInDocument()); - } - } // Update button if onButtonFace() is called explicitly ui->buttonFace->setChecked(pressed); @@ -343,39 +302,7 @@ void TaskPadParameters::onButtonFace(const bool pressed) void TaskPadParameters::onFaceName(const QString& text) { - // We must expect that "text" is the translation of "Face" followed by an ID. - QString name; - QTextStream str(&name); - str << "^" << tr("Face") << "(\\d+)$"; - QRegExp rx(name); - if (text.indexOf(rx) < 0) { - ui->lineFaceName->setProperty("FaceName", QByteArray()); - return; - } - - int faceId = rx.cap(1).toInt(); - std::stringstream ss; - ss << "Face" << faceId; - ui->lineFaceName->setProperty("FaceName", QByteArray(ss.str().c_str())); - - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - Part::Feature* support = pcPad->getSupport(); - if (support == NULL) { - // There is no support, so we can't select from it... - return; - } - std::vector upToFaces(1,ss.str()); - pcPad->UpToFace.setValue(support, upToFaces); - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); -} - -void TaskPadParameters::onUpdateView(bool on) -{ - if (on) { - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - pcPad->getDocument()->recomputeFeature(pcPad); - } + ui->lineFaceName->setProperty("FaceName", TaskSketchBasedParameters::onFaceName(text)); } double TaskPadParameters::getLength(void) const @@ -464,7 +391,7 @@ void TaskPadParameters::saveHistory(void) void TaskPadParameters::apply() { - std::string name = PadView->getObject()->getNameInDocument(); + std::string name = vp->getObject()->getNameInDocument(); const char * cname = name.c_str(); ui->lengthEdit->apply(); @@ -476,7 +403,7 @@ void TaskPadParameters::apply() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",cname,getMode()); std::string facename = getFaceName().data(); - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + PartDesign::Pad* pcPad = static_cast(vp->getObject()); Part::Feature* support = pcPad->getSupport(); if (support != NULL && !facename.empty()) { @@ -487,8 +414,8 @@ void TaskPadParameters::apply() } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - if (!PadView->getObject()->isValid()) - throw Base::Exception(PadView->getObject()->getStatusString()); + if (!vp->getObject()->isValid()) + throw Base::Exception(vp->getObject()->getStatusString()); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); Gui::Command::commitCommand(); } @@ -499,10 +426,10 @@ void TaskPadParameters::apply() //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TaskDlgPadParameters::TaskDlgPadParameters(ViewProviderPad *PadView,bool newObj) - : TaskDialog(),PadView(PadView) + : TaskDlgSketchBasedParameters(PadView) { assert(PadView); - parameter = new TaskPadParameters(PadView,newObj); + parameter = new TaskPadParameters(static_cast(PadView)); Content.push_back(parameter); } @@ -514,20 +441,6 @@ TaskDlgPadParameters::~TaskDlgPadParameters() //==== calls from the TaskView =============================================================== - -void TaskDlgPadParameters::open() -{ - // a transaction is already open at creation time of the pad - if (!Gui::Command::hasPendingCommand()) { - QString msg = QObject::tr("Edit pad"); - Gui::Command::openCommand((const char*)msg.toUtf8()); - } -} - -void TaskDlgPadParameters::clicked(int) -{ -} - bool TaskDlgPadParameters::accept() { @@ -546,40 +459,5 @@ bool TaskDlgPadParameters::accept() return true; } -bool TaskDlgPadParameters::reject() -{ - // get the support and Sketch - PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - Sketcher::SketchObject *pcSketch = 0; - if (pcPad->Sketch.getValue()) { - pcSketch = static_cast(pcPad->Sketch.getValue()); - } - - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the sketch is visible again - if (!Gui::Application::Instance->getViewProvider(pcPad)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - } - - // Body housekeeping - if (ActivePartObject != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - return true; -} - - #include "moc_TaskPadParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index e69295b3497a..0c28b737471c 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -28,6 +28,7 @@ #include #include +#include "TaskSketchBasedParameters.h" #include "ViewProviderPad.h" class Ui_TaskPadParameters; @@ -44,7 +45,7 @@ namespace PartDesignGui { -class TaskPadParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +class TaskPadParameters : public TaskSketchBasedParameters { Q_OBJECT @@ -64,7 +65,6 @@ private Q_SLOTS: void onModeChanged(int); void onButtonFace(const bool pressed = true); void onFaceName(const QString& text); - void onUpdateView(bool); protected: void changeEvent(QEvent *e); @@ -82,11 +82,10 @@ private Q_SLOTS: private: QWidget* proxy; Ui_TaskPadParameters* ui; - ViewProviderPad *PadView; }; /// simulation dialog for the TaskView -class TaskDlgPadParameters : public Gui::TaskView::TaskDialog +class TaskDlgPadParameters : public TaskDlgSketchBasedParameters { Q_OBJECT @@ -95,28 +94,15 @@ class TaskDlgPadParameters : public Gui::TaskView::TaskDialog ~TaskDlgPadParameters(); ViewProviderPad* getPadView() const - { return PadView; } + { return static_cast(vp); } public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } protected: - ViewProviderPad *PadView; - TaskPadParameters *parameter; }; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h.orig b/src/Mod/PartDesign/Gui/TaskPadParameters.h.orig new file mode 100644 index 000000000000..2d9caf0735d0 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h.orig @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 GUI_TASKVIEW_TaskPadParameters_H +#define GUI_TASKVIEW_TaskPadParameters_H + +#include +#include +#include + +#include "TaskSketchBasedParameters.h" +#include "ViewProviderPad.h" + +class Ui_TaskPadParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartDesignGui { + + + +class TaskPadParameters : public TaskSketchBasedParameters +{ + Q_OBJECT + +public: + TaskPadParameters(ViewProviderPad *PadView,bool newObj=false,QWidget *parent = 0); + ~TaskPadParameters(); + + const bool updateView() const; + void saveHistory(void); + void apply(); + +private Q_SLOTS: + void onLengthChanged(double); + void onMidplane(bool); + void onReversed(bool); + void onLength2Changed(double); + void onModeChanged(int); + void onButtonFace(const bool pressed = true); + void onFaceName(const QString& text); + +protected: + void changeEvent(QEvent *e); + +private: + int getMode(void) const; + double getLength(void) const; + double getLength2(void) const; + bool getReversed(void) const; + bool getMidplane(void) const; + QByteArray getFaceName(void) const; + void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(int index); + +private: + QWidget* proxy; + Ui_TaskPadParameters* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgPadParameters : public TaskDlgSketchBasedParameters +{ + Q_OBJECT + +public: + TaskDlgPadParameters(ViewProviderPad *PadView,bool newObj=false); + ~TaskDlgPadParameters(); + + ViewProviderPad* getPadView() const + { return static_cast(vp); } + + +public: + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) +<<<<<<< 0973b40e8e489ddbf6455e9a2e80b0520f143b58 + virtual bool reject(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } +======= +>>>>>>> Refactored code of SketchBased features to have common code in an abstract superclass + +protected: + TaskPadParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 20c1967d6282..6c126d077c55 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -47,6 +47,7 @@ #include #include #include +#include "TaskSketchBasedParameters.h" #include "ReferenceSelection.h" #include "Workbench.h" @@ -56,7 +57,7 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskPocketParameters */ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Pocket"),tr("Pocket parameters"),true, parent),PocketView(PocketView) + : TaskSketchBasedParameters(PocketView, parent, "PartDesign_Pocket",tr("Pocket parameters")) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -90,7 +91,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->changeMode->blockSignals(true); // Get the feature data - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); double l = pcPocket->Length.getValue(); bool midplane = pcPocket->Midplane.getValue(); bool reversed = pcPocket->Reversed.getValue(); @@ -192,39 +193,20 @@ void TaskPocketParameters::updateUI(int index) void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { - // Don't allow selection in other document - if (strcmp(msg.pDocName, PocketView->getObject()->getDocument()->getName()) != 0) - return; - - if (!msg.pSubName || msg.pSubName[0] == '\0') - return; - std::string subName(msg.pSubName); - if (subName.substr(0,4) != "Face") - return; - int faceId = std::atoi(&subName[4]); - - // Don't allow selection outside of support - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); - Part::Feature* support = pcPocket->getSupport(); - if (support == NULL) { - // There is no support, so we can't select from it... + QString refText = onAddSelection(msg); + if (refText.length() > 0) { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->setText(refText); + ui->lineFaceName->setProperty("FaceName", QByteArray(msg.pSubName)); + ui->lineFaceName->blockSignals(false); // Turn off reference selection mode onButtonFace(false); - return; + } else { + ui->lineFaceName->blockSignals(true); + ui->lineFaceName->setText(tr("No face selected")); + ui->lineFaceName->setProperty("FaceName", QByteArray()); + ui->lineFaceName->blockSignals(false); } - if (strcmp(msg.pObjectName, support->getNameInDocument()) != 0) - return; - - std::vector upToFaces(1,subName); - pcPocket->UpToFace.setValue(support, upToFaces); - if (updateView()) - pcPocket->getDocument()->recomputeFeature(pcPocket); - ui->lineFaceName->blockSignals(true); - ui->lineFaceName->setText(tr("Face") + QString::number(faceId)); - ui->lineFaceName->setProperty("FaceName", QByteArray(subName.c_str())); - ui->lineFaceName->blockSignals(false); - // Turn off reference selection mode - onButtonFace(false); } else if (msg.Type == Gui::SelectionChanges::ClrSelection) { ui->lineFaceName->blockSignals(true); @@ -236,7 +218,7 @@ void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg) void TaskPocketParameters::onLengthChanged(double len) { - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Length.setValue(len); if (updateView()) pcPocket->getDocument()->recomputeFeature(pcPocket); @@ -244,7 +226,7 @@ void TaskPocketParameters::onLengthChanged(double len) void TaskPocketParameters::onMidplaneChanged(bool on) { - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Midplane.setValue(on); ui->checkBoxReversed->setEnabled(!on); if (updateView()) @@ -253,7 +235,7 @@ void TaskPocketParameters::onMidplaneChanged(bool on) void TaskPocketParameters::onReversedChanged(bool on) { - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Reversed.setValue(on); if (updateView()) pcPocket->getDocument()->recomputeFeature(pcPocket); @@ -261,7 +243,7 @@ void TaskPocketParameters::onReversedChanged(bool on) void TaskPocketParameters::onModeChanged(int index) { - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); switch (index) { case 0: @@ -299,30 +281,7 @@ void TaskPocketParameters::onModeChanged(int index) } void TaskPocketParameters::onButtonFace(const bool pressed) { - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); - Part::Feature* support = pcPocket->getSupport(); - if (support == NULL) { - // There is no support, so we can't select from it... - return; - } - - if (pressed) { - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setHide(PocketView->getObject()->getNameInDocument()); - doc->setShow(support->getNameInDocument()); - } - Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate - (new ReferenceSelection(support, false, true, false)); - } else { - Gui::Selection().rmvSelectionGate(); - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - doc->setShow(PocketView->getObject()->getNameInDocument()); - doc->setHide(support->getNameInDocument()); - } - } + TaskSketchBasedParameters::onButtonFace(pressed); // Update button if onButtonFace() is called explicitly ui->buttonFace->setChecked(pressed); @@ -330,39 +289,7 @@ void TaskPocketParameters::onButtonFace(const bool pressed) { void TaskPocketParameters::onFaceName(const QString& text) { - // We must expect that "text" is the translation of "Face" followed by an ID. - QString name; - QTextStream str(&name); - str << "^" << tr("Face") << "(\\d+)$"; - QRegExp rx(name); - if (text.indexOf(rx) < 0) { - ui->lineFaceName->setProperty("FaceName", QByteArray()); - return; - } - - int faceId = rx.cap(1).toInt(); - std::stringstream ss; - ss << "Face" << faceId; - ui->lineFaceName->setProperty("FaceName", QByteArray(ss.str().c_str())); - - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); - Part::Feature* support = pcPocket->getSupport(); - if (support == NULL) { - // There is no support, so we can't select from it... - return; - } - std::vector upToFaces(1,ss.str()); - pcPocket->UpToFace.setValue(support, upToFaces); - if (updateView()) - pcPocket->getDocument()->recomputeFeature(pcPocket); -} - -void TaskPocketParameters::onUpdateView(bool on) -{ - if (on) { - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); - pcPocket->getDocument()->recomputeFeature(pcPocket); - } + ui->lineFaceName->setProperty("FaceName", TaskSketchBasedParameters::onFaceName(text)); } double TaskPocketParameters::getLength(void) const @@ -428,13 +355,13 @@ void TaskPocketParameters::changeEvent(QEvent *e) void TaskPocketParameters::apply() { - std::string name = PocketView->getObject()->getNameInDocument(); + std::string name = vp->getObject()->getNameInDocument(); //Gui::Command::openCommand("Pocket changed"); ui->pocketLength->apply(); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),getMode()); std::string facename = getFaceName().data(); - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); Part::Feature* support = pcPocket->getSupport(); if (support != NULL && !facename.empty()) { QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); @@ -443,10 +370,10 @@ void TaskPocketParameters::apply() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), buf.toStdString().c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", name.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),getReversed()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", name.c_str(), getReversed()?1:0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - if (!PocketView->getObject()->isValid()) - throw Base::Exception(PocketView->getObject()->getStatusString()); + if (!vp->getObject()->isValid()) + throw Base::Exception(vp->getObject()->getStatusString()); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); Gui::Command::commitCommand(); } @@ -457,10 +384,10 @@ void TaskPocketParameters::apply() //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TaskDlgPocketParameters::TaskDlgPocketParameters(ViewProviderPocket *PocketView) - : TaskDialog(),PocketView(PocketView) + : TaskDlgSketchBasedParameters(PocketView) { - assert(PocketView); - parameter = new TaskPocketParameters(PocketView); + assert(vp); + parameter = new TaskPocketParameters(static_cast(vp)); Content.push_back(parameter); } @@ -472,21 +399,6 @@ TaskDlgPocketParameters::~TaskDlgPocketParameters() //==== calls from the TaskView =============================================================== - -void TaskDlgPocketParameters::open() -{ - // a transaction is already open at creation time of the pocket - if (!Gui::Command::hasPendingCommand()) { - QString msg = tr("Edit pocket"); - Gui::Command::openCommand((const char*)msg.toUtf8()); - } -} - -void TaskDlgPocketParameters::clicked(int) -{ - -} - bool TaskDlgPocketParameters::accept() { try { @@ -500,40 +412,5 @@ bool TaskDlgPocketParameters::accept() return true; } -bool TaskDlgPocketParameters::reject() -{ - // get the support and Sketch - PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); - Sketcher::SketchObject *pcSketch = 0; - if (pcPocket->Sketch.getValue()) { - pcSketch = static_cast(pcPocket->Sketch.getValue()); - } - - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the sketch is visible again - if (!Gui::Application::Instance->getViewProvider(pcPocket)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - } - - // Body housekeeping - if (ActivePartObject != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - return true; -} - - #include "moc_TaskPocketParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index 43e4a31263a5..749129e66cd4 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -28,6 +28,7 @@ #include #include +#include "TaskSketchBasedParameters.h" #include "ViewProviderPocket.h" class Ui_TaskPocketParameters; @@ -44,7 +45,7 @@ namespace PartDesignGui { -class TaskPocketParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +class TaskPocketParameters : public TaskSketchBasedParameters { Q_OBJECT @@ -64,7 +65,6 @@ private Q_SLOTS: void onModeChanged(int); void onButtonFace(const bool pressed = true); void onFaceName(const QString& text); - void onUpdateView(bool); protected: void changeEvent(QEvent *e); @@ -79,12 +79,11 @@ private Q_SLOTS: private: QWidget* proxy; Ui_TaskPocketParameters* ui; - ViewProviderPocket *PocketView; double oldLength; }; /// simulation dialog for the TaskView -class TaskDlgPocketParameters : public Gui::TaskView::TaskDialog +class TaskDlgPocketParameters : public TaskDlgSketchBasedParameters { Q_OBJECT @@ -93,28 +92,14 @@ class TaskDlgPocketParameters : public Gui::TaskView::TaskDialog ~TaskDlgPocketParameters(); ViewProviderPocket* getPocketView() const - { return PocketView; } + { return static_cast(vp); } public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); - /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } protected: - ViewProviderPocket *PocketView; - TaskPocketParameters *parameter; }; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h.orig b/src/Mod/PartDesign/Gui/TaskPocketParameters.h.orig new file mode 100644 index 000000000000..6678b58f83fe --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h.orig @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 GUI_TASKVIEW_TaskPocketParameters_H +#define GUI_TASKVIEW_TaskPocketParameters_H + +#include +#include +#include + +#include "TaskSketchBasedParameters.h" +#include "ViewProviderPocket.h" + +class Ui_TaskPocketParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartDesignGui { + + + +class TaskPocketParameters : public TaskSketchBasedParameters +{ + Q_OBJECT + +public: + TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent = 0); + ~TaskPocketParameters(); + + bool getReversed(void) const; + QByteArray getFaceName(void) const; + const bool updateView() const; + void apply(); + +private Q_SLOTS: + void onLengthChanged(double); + void onMidplaneChanged(bool); + void onReversedChanged(bool); + void onModeChanged(int); + void onButtonFace(const bool pressed = true); + void onFaceName(const QString& text); + +protected: + void changeEvent(QEvent *e); + +private: + double getLength(void) const; + bool getMidplane(void) const; + int getMode(void) const; + void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(int index); + +private: + QWidget* proxy; + Ui_TaskPocketParameters* ui; + double oldLength; +}; + +/// simulation dialog for the TaskView +class TaskDlgPocketParameters : public TaskDlgSketchBasedParameters +{ + Q_OBJECT + +public: + TaskDlgPocketParameters(ViewProviderPocket *PocketView); + ~TaskDlgPocketParameters(); + + ViewProviderPocket* getPocketView() const + { return static_cast(vp); } + + +public: + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); +<<<<<<< 0973b40e8e489ddbf6455e9a2e80b0520f143b58 + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } +======= +>>>>>>> Refactored code of SketchBased features to have common code in an abstract superclass + +protected: + TaskPocketParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 838a1c0375ba..268c5cb8a51a 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -51,7 +51,7 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskRevolutionParameters */ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *RevolutionView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Revolution"),tr("Revolution parameters"),true, parent),RevolutionView(RevolutionView) + : TaskSketchBasedParameters(RevolutionView, parent, "PartDesign_Revolution",tr("Revolution parameters")) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -78,7 +78,7 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol ui->checkBoxMidplane->blockSignals(true); ui->checkBoxReversed->blockSignals(true); - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); double l = pcRevolution->Angle.getValue(); bool mirrored = pcRevolution->Midplane.getValue(); bool reversed = pcRevolution->Reversed.getValue(); @@ -127,7 +127,7 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol void TaskRevolutionParameters::onAngleChanged(double len) { - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); pcRevolution->Angle.setValue(len); if (updateView()) pcRevolution->getDocument()->recomputeFeature(pcRevolution); @@ -135,7 +135,7 @@ void TaskRevolutionParameters::onAngleChanged(double len) void TaskRevolutionParameters::onAxisChanged(int num) { - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); if (pcSketch) { App::DocumentObject *oldRefAxis = pcRevolution->ReferenceAxis.getValue(); @@ -173,7 +173,7 @@ void TaskRevolutionParameters::onAxisChanged(int num) void TaskRevolutionParameters::onMidplane(bool on) { - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); pcRevolution->Midplane.setValue(on); if (updateView()) pcRevolution->getDocument()->recomputeFeature(pcRevolution); @@ -181,20 +181,12 @@ void TaskRevolutionParameters::onMidplane(bool on) void TaskRevolutionParameters::onReversed(bool on) { - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); pcRevolution->Reversed.setValue(on); if (updateView()) pcRevolution->getDocument()->recomputeFeature(pcRevolution); } -void TaskRevolutionParameters::onUpdateView(bool on) -{ - if (on) { - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); - pcRevolution->getDocument()->recomputeFeature(pcRevolution); - } -} - double TaskRevolutionParameters::getAngle(void) const { return ui->revolveAngle->value().getValue(); @@ -203,7 +195,7 @@ double TaskRevolutionParameters::getAngle(void) const QString TaskRevolutionParameters::getReferenceAxis(void) const { // get the support and Sketch - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); QString buf; @@ -255,7 +247,7 @@ void TaskRevolutionParameters::changeEvent(QEvent *e) void TaskRevolutionParameters::apply() { - App::DocumentObject* revolve = RevolutionView->getObject(); + App::DocumentObject* revolve = vp->getObject(); std::string name = revolve->getNameInDocument(); // retrieve sketch and its support object @@ -291,7 +283,7 @@ void TaskRevolutionParameters::apply() //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ TaskDlgRevolutionParameters::TaskDlgRevolutionParameters(ViewProviderRevolution *RevolutionView) - : TaskDialog(),RevolutionView(RevolutionView) + : TaskDlgSketchBasedParameters(RevolutionView) { assert(RevolutionView); parameter = new TaskRevolutionParameters(RevolutionView); @@ -306,61 +298,11 @@ TaskDlgRevolutionParameters::~TaskDlgRevolutionParameters() //==== calls from the TaskView =============================================================== - -void TaskDlgRevolutionParameters::open() -{ - // a transaction is already open at creation time of the revolve - if (!Gui::Command::hasPendingCommand()) { - QString msg = QObject::tr("Edit revolve"); - Gui::Command::openCommand((const char*)msg.toUtf8()); - } -} - -void TaskDlgRevolutionParameters::clicked(int) -{ - -} - bool TaskDlgRevolutionParameters::accept() { parameter->apply(); return true; } -bool TaskDlgRevolutionParameters::reject() -{ - // get the support and Sketch - PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); - Sketcher::SketchObject *pcSketch = 0; - if (pcRevolution->Sketch.getValue()) { - pcSketch = static_cast(pcRevolution->Sketch.getValue()); - } - - // role back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // if abort command deleted the object the support is visible again - if (!Gui::Application::Instance->getViewProvider(pcRevolution)) { - if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) - Gui::Application::Instance->getViewProvider(pcSketch)->show(); - } - - // Body housekeeping - if (ActivePartObject != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - return true; -} - - #include "moc_TaskRevolutionParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index 764246cf8b7d..1f224447f004 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -28,6 +28,7 @@ #include #include +#include "TaskSketchBasedParameters.h" #include "ViewProviderRevolution.h" class Ui_TaskRevolutionParameters; @@ -44,7 +45,7 @@ namespace PartDesignGui { -class TaskRevolutionParameters : public Gui::TaskView::TaskBox +class TaskRevolutionParameters : public TaskSketchBasedParameters { Q_OBJECT @@ -59,9 +60,9 @@ private Q_SLOTS: void onAxisChanged(int); void onMidplane(bool); void onReversed(bool); - void onUpdateView(bool); protected: + void onSelectionChanged(const Gui::SelectionChanges& msg) {} void changeEvent(QEvent *e); const bool updateView() const; QString getReferenceAxis(void) const; @@ -69,16 +70,13 @@ private Q_SLOTS: bool getMidplane(void) const; bool getReversed(void) const; -private: - private: QWidget* proxy; Ui_TaskRevolutionParameters* ui; - ViewProviderRevolution *RevolutionView; }; /// simulation dialog for the TaskView -class TaskDlgRevolutionParameters : public Gui::TaskView::TaskDialog +class TaskDlgRevolutionParameters : public TaskDlgSketchBasedParameters { Q_OBJECT @@ -87,28 +85,13 @@ class TaskDlgRevolutionParameters : public Gui::TaskView::TaskDialog ~TaskDlgRevolutionParameters(); ViewProviderRevolution* getRevolutionView() const - { return RevolutionView; } - + { return static_cast(vp); } -public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); +public: /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); - /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } protected: - ViewProviderRevolution *RevolutionView; - TaskRevolutionParameters *parameter; }; diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h.orig b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h.orig new file mode 100644 index 000000000000..1d219598d8db --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h.orig @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 GUI_TASKVIEW_TaskRevolutionParameters_H +#define GUI_TASKVIEW_TaskRevolutionParameters_H + +#include +#include +#include + +#include "TaskSketchBasedParameters.h" +#include "ViewProviderRevolution.h" + +class Ui_TaskRevolutionParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartDesignGui { + + + +class TaskRevolutionParameters : public TaskSketchBasedParameters +{ + Q_OBJECT + +public: + TaskRevolutionParameters(ViewProviderRevolution *RevolutionView,QWidget *parent = 0); + ~TaskRevolutionParameters(); + + void apply(); + +private Q_SLOTS: + void onAngleChanged(double); + void onAxisChanged(int); + void onMidplane(bool); + void onReversed(bool); + +protected: + void onSelectionChanged(const Gui::SelectionChanges& msg) {} + void changeEvent(QEvent *e); + const bool updateView() const; + QString getReferenceAxis(void) const; + double getAngle(void) const; + bool getMidplane(void) const; + bool getReversed(void) const; + +private: + QWidget* proxy; + Ui_TaskRevolutionParameters* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgRevolutionParameters : public TaskDlgSketchBasedParameters +{ + Q_OBJECT + +public: + TaskDlgRevolutionParameters(ViewProviderRevolution *RevolutionView); + ~TaskDlgRevolutionParameters(); + + ViewProviderRevolution* getRevolutionView() const + { return static_cast(vp); } + +public: + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); +<<<<<<< 0973b40e8e489ddbf6455e9a2e80b0520f143b58 + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } +======= +>>>>>>> Refactored code of SketchBased features to have common code in an abstract superclass + +protected: + TaskRevolutionParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp new file mode 100644 index 000000000000..10fb21399794 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -0,0 +1,266 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +#endif + +#include "TaskSketchBasedParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ReferenceSelection.h" +#include "Workbench.h" + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskSketchBasedParameters */ + +TaskSketchBasedParameters::TaskSketchBasedParameters(ViewProvider *vp, QWidget *parent, + const std::string& pixmapname, const QString& parname) + : TaskBox(Gui::BitmapFactory().pixmap(pixmapname.c_str()),parname,true, parent), + vp(vp) +{ + +} +/* +App::DocumentObject* TaskSketchBasedParameters::getBaseFeature() +{ + PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + App::DocumentObject* baseFeature = pcSketchBased->BaseFeature.getValue(); + if (baseFeature == NULL) { + if (ActivePartObject != NULL) { + baseFeature = ActivePartObject->getPrevSolidFeature(pcSketchBased, false); + } + if (baseFeature == NULL) { + // For legacy features + baseFeature = pcSketchBased->getSupport(); + } + } + + return baseFeature; +}*/ + +const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChanges& msg) +{ + // Note: The validity checking has already been done in ReferenceSelection.cpp + PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + App::DocumentObject* selObj = pcSketchBased->getDocument()->getObject(msg.pObjectName); + if (selObj == pcSketchBased) + return QString::fromAscii(""); + std::string subname = msg.pSubName; + QString refStr; + + // Remove subname for planes and datum features + if (selObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + selObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + subname = ""; + refStr = QString::fromAscii(selObj->getNameInDocument()); + } else { + int faceId = std::atoi(&subname[4]); + refStr = QString::fromAscii(selObj->getNameInDocument()) + QObject::tr(":Face") + QString::number(faceId); + } + + std::vector upToFaces(1,subname); + pcSketchBased->UpToFace.setValue(selObj, upToFaces); + if (updateView()) + pcSketchBased->getDocument()->recomputeFeature(pcSketchBased); + + return refStr; +} + +void TaskSketchBasedParameters::onButtonFace(const bool pressed) { + // Note: Even if there is no solid, App::Plane and Part::Datum can still be selected + App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(NULL, false); + PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + + if (pressed) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc && solid) { + doc->setHide(pcSketchBased->getNameInDocument()); + doc->setShow(solid->getNameInDocument()); + } + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate + (new ReferenceSelection(solid, false, true, false)); + } else { + Gui::Selection().rmvSelectionGate(); + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc && solid) { + doc->setShow(pcSketchBased->getNameInDocument()); + doc->setHide(solid->getNameInDocument()); + } + } +} + +const QByteArray TaskSketchBasedParameters::onFaceName(const QString& text) +{ + if (text.length() == 0) + return QByteArray(); + + QStringList parts = text.split(QChar::fromAscii(':')); + if (parts.length() < 2) + parts.push_back(QString::fromAscii("")); + // Check whether this is the name of an App::Plane or Part::Datum feature + App::DocumentObject* obj = vp->getObject()->getDocument()->getObject(parts[0].toAscii()); + if (obj == NULL) + return QByteArray(); + + if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + // everything is OK (we assume a Part can only have exactly 3 App::Plane objects located at the base of the feature tree) + return QByteArray(); + } else if (obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + if (!PartDesignGui::ActivePartObject->hasFeature(obj)) + return QByteArray(); + return QByteArray(); + } else { + // We must expect that "text" is the translation of "Face" followed by an ID. + QString name; + QTextStream str(&name); + str << "^" << tr("Face") << "(\\d+)$"; + QRegExp rx(name); + if (text.indexOf(rx) < 0) { + return QByteArray(); + } + + int faceId = rx.cap(1).toInt(); + std::stringstream ss; + ss << "Face" << faceId; + + std::vector upToFaces(1,ss.str()); + PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + pcSketchBased->UpToFace.setValue(obj, upToFaces); + if (updateView()) + pcSketchBased->getDocument()->recomputeFeature(pcSketchBased); + + return QByteArray(ss.str().c_str()); + } +} + +QString TaskSketchBasedParameters::getFaceReference(const QString& obj, const QString& sub) const +{ + QString o = obj.left(obj.indexOf(QString::fromAscii(":"))); + + if (o == tr("No face selected")) + return QString::fromAscii(""); + else + return QString::fromAscii("(App.activeDocument().") + o + + QString::fromAscii(", [\"") + sub + QString::fromAscii("\"])"); +} + +void TaskSketchBasedParameters::onUpdateView(bool on) +{ + if (on) { + PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + pcSketchBased->getDocument()->recomputeFeature(pcSketchBased); + } +} + +TaskSketchBasedParameters::~TaskSketchBasedParameters() +{ +} + + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgSketchBasedParameters::TaskDlgSketchBasedParameters(ViewProvider *vp) + : TaskDialog(),vp(vp) +{ +} + +TaskDlgSketchBasedParameters::~TaskDlgSketchBasedParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgSketchBasedParameters::open() +{ + +} + +void TaskDlgSketchBasedParameters::clicked(int) +{ + +} + +bool TaskDlgSketchBasedParameters::reject() +{ + // get the support and Sketch + PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + Sketcher::SketchObject *pcSketch; + if (pcSketchBased->Sketch.getValue()) { + pcSketch = static_cast(pcSketchBased->Sketch.getValue()); + } + + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the sketch is visible again + if (!Gui::Application::Instance->getViewProvider(pcSketchBased)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); + } + + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + return true; +} + + +#include "moc_TaskSketchBasedParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h new file mode 100644 index 000000000000..757b81825652 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 GUI_TASKVIEW_TaskSketchBasedParameters_H +#define GUI_TASKVIEW_TaskSketchBasedParameters_H + +#include +#include +#include +#include "ViewProvider.h" + +namespace App { +class Property; +} + +namespace PartDesignGui { + + +/// Convenience class to collect common methods for all SketchBased features +class TaskSketchBasedParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskSketchBasedParameters(ViewProvider* vp, QWidget *parent, + const std::string& pixmapname, const QString& parname); + ~TaskSketchBasedParameters(); + + //App::DocumentObject* getBaseFeature(); + +protected: + void onSelectionChanged(const Gui::SelectionChanges& msg)=0; + const QString onAddSelection(const Gui::SelectionChanges& msg); + void onButtonFace(const bool pressed = true); + const QByteArray onFaceName(const QString& text); + QString getFaceReference(const QString& obj, const QString& sub) const; + virtual const bool updateView() const=0; + +protected Q_SLOTS: + void onUpdateView(bool on); + +protected: + ViewProvider *vp; +}; + +class TaskDlgSketchBasedParameters : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgSketchBasedParameters(ViewProvider *vp); + ~TaskDlgSketchBasedParameters(); + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept()=0; + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProvider *vp; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TaskSketchBasedParameters_H From f954a514303ead89ff1cd0dbcb5aada242804e65 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 14 May 2013 15:44:24 +0430 Subject: [PATCH 109/664] Pad/Pocket: Allow extrude up to a datum plane --- src/Mod/Part/App/DatumFeature.cpp | 6 ++ src/Mod/Part/App/DatumFeature.h | 4 +- src/Mod/PartDesign/App/Feature.h | 8 +- src/Mod/PartDesign/App/FeatureGroove.cpp | 20 ++--- src/Mod/PartDesign/App/FeaturePad.cpp | 58 ++++++------- src/Mod/PartDesign/App/FeaturePocket.cpp | 56 +++++-------- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 83 +++++++++++++------ src/Mod/PartDesign/App/FeatureSketchBased.h | 9 +- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 2 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 35 ++++---- .../PartDesign/Gui/TaskPocketParameters.cpp | 33 ++++---- src/Mod/Sketcher/App/SketchObject.cpp | 2 +- 12 files changed, 162 insertions(+), 154 deletions(-) diff --git a/src/Mod/Part/App/DatumFeature.cpp b/src/Mod/Part/App/DatumFeature.cpp index 407288be0403..05ec5bf480ea 100644 --- a/src/Mod/Part/App/DatumFeature.cpp +++ b/src/Mod/Part/App/DatumFeature.cpp @@ -100,3 +100,9 @@ void Datum::onDocumentRestored() Part::Feature::onDocumentRestored(); } +TopoDS_Shape Datum::getShape() const +{ + Part::TopoShape sh = Shape.getShape(); + sh.setPlacement(Placement.getValue()); + return sh._Shape; +} diff --git a/src/Mod/Part/App/DatumFeature.h b/src/Mod/Part/App/DatumFeature.h index c10126138ab0..d2796b6edac3 100644 --- a/src/Mod/Part/App/DatumFeature.h +++ b/src/Mod/Part/App/DatumFeature.h @@ -57,8 +57,8 @@ class PartExport Datum : public Part::Feature virtual const std::set getHint() = 0; - /// Return a shape representing the datum feature - //virtual const TopoDS_Shape getShape() const = 0; + /// Return a shape including Placement representing the datum feature + TopoDS_Shape getShape() const; protected: void onChanged (const App::Property* prop); diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 050a73cea90c..ab5309c1d30c 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -52,6 +52,9 @@ class PartDesignExport Feature : public Part::Feature short mustExecute() const; + /// Check whether the given feature is a datum feature + static bool isDatum(const App::DocumentObject* feature); + protected: /// Returns the BaseFeature property's shape (if any) const TopoDS_Shape& getBaseShape() const; @@ -62,10 +65,7 @@ class PartDesignExport Feature : public Part::Feature static TopoDS_Shape getSolid(const TopoDS_Shape&); /// Grab any point from the given face - static const gp_Pnt getPointFromFace(const TopoDS_Face& f); - - /// Check whether the given feature is a datum feature - static bool isDatum(const App::DocumentObject* feature); + static const gp_Pnt getPointFromFace(const TopoDS_Face& f); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index a126fcbd881c..ede3a980edcf 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -93,24 +93,17 @@ App::DocumentObjectExecReturn *Groove::execute(void) return new App::DocumentObjectExecReturn(e.what()); } - // Get the sketch support - TopoDS_Shape support; - try { - support = getSupportShape(); - } catch (const Base::Exception&) { - // ignore, because support isn't mandatory any more - support = TopoDS_Shape(); - } - - // Get the base shape + // if the Base property has a valid shape, fuse the prism into it TopoDS_Shape base; try { base = getBaseShape(); } catch (const Base::Exception&) { - // fall back to support (for legacy features) - base = support; - if (base.IsNull()) + try { + // fall back to support (for legacy features) + base = getSupportShape(); + } catch (const Base::Exception&) { return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the groove!"); + } } updateAxis(); @@ -138,7 +131,6 @@ App::DocumentObjectExecReturn *Groove::execute(void) TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); - support.Move(invObjLoc); base.Move(invObjLoc); sketchshape.Move(invObjLoc); diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index ebc414eb96e7..9859c9726db7 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -96,17 +96,23 @@ App::DocumentObjectExecReturn *Pad::execute(void) return new App::DocumentObjectExecReturn(e.what()); } - TopoDS_Shape support; + // if the Base property has a valid shape, fuse the prism into it + TopoDS_Shape base; try { - support = getSupportShape(); + base = getBaseShape(); } catch (const Base::Exception&) { - // ignore, because support isn't mandatory - support = TopoDS_Shape(); + try { + // fall back to support (for legacy features) + base = getSupportShape(); + } catch (const Base::Exception&) { + // ignore, because support isn't mandatory + base = TopoDS_Shape(); + } } /* // Find Body feature which owns this Pad and get the shape of the feature preceding this one for fusing - // This method was rejected in favour of the Base property because it makes the feature atomic (independent of the + // This method was rejected in favour of the BaseFeature property because that makes the feature atomic (independent of the // Body object). See // https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=19&t=3831 // https://sourceforge.net/apps/phpbb/free-cad/viewtopic.php?f=19&t=3855 @@ -138,7 +144,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { - support.Move(invObjLoc); + base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); dir.Transform(invObjLoc.Transformation()); @@ -151,42 +157,36 @@ App::DocumentObjectExecReturn *Pad::execute(void) TopoDS_Shape prism; std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { + // Note: This will throw an exception if the sketch is located on a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); if (Reversed.getValue()) dir.Reverse(); - // Find a valid face to extrude up to + // Find a valid face or datum plane to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } - getUpToFace(upToFace, support, supportface, sketchshape, method, dir); + getUpToFace(upToFace, base, supportface, sketchshape, method, dir); // A support object is always required and we need to use BRepFeat_MakePrism // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid // because the feature does not add any material. This only happens with the "2" option, though // Note: It might be possible to pass a shell or a compound containing multiple faces // as the Until parameter of Perform() - // Note: Multiple independent wires are not supported, that's why we have to iterate over them. - TopoDS_Compound comp; - BRep_Builder builder; - builder.MakeCompound(comp); - + // Note: Multiple independent wires are not supported, we should check for that and + // warn the user // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results - for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { - BRepFeat_MakePrism PrismMaker; - PrismMaker.Init(support, xp.Current(), supportface, dir, 2, 1); - PrismMaker.Perform(upToFace); - - if (!PrismMaker.IsDone()) - return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); - builder.Add(comp, PrismMaker.Shape()); - } + BRepFeat_MakePrism PrismMaker; + PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); + PrismMaker.Perform(upToFace); - prism = comp; + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); + prism = PrismMaker.Shape(); } else { generatePrism(prism, sketchshape, method, dir, L, L2, Midplane.getValue(), Reversed.getValue()); @@ -197,17 +197,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) // set the additive shape property for later usage in e.g. pattern prism = refineShapeIfActive(prism); - this->AddShape.setValue(prism); - - // if the Base property has a valid shape, fuse the prism into it - TopoDS_Shape base; - try { - base = getBaseShape(); - base.Move(invObjLoc); - } catch (const Base::Exception&) { - // fall back to support (for legacy features) - base = support; - } + this->AddShape.setValue(prism); if (!base.IsNull()) { // Let's call algorithm computing a fuse operation: diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 17374f5e88b4..e57e7aa442b4 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -96,24 +96,17 @@ App::DocumentObjectExecReturn *Pocket::execute(void) return new App::DocumentObjectExecReturn(e.what()); } - // Get the sketch support - TopoDS_Shape support; - try { - support = getSupportShape(); - } catch (const Base::Exception&) { - // ignore, because support isn't mandatory any more - support = TopoDS_Shape(); - } - - // Get the base shape + // if the Base property has a valid shape, fuse the prism into it TopoDS_Shape base; try { base = getBaseShape(); } catch (const Base::Exception&) { - // fall back to support (for legacy features) - base = support; - if (base.IsNull()) + try { + // fall back to support (for legacy features) + base = getSupportShape(); + } catch (const Base::Exception&) { return new App::DocumentObjectExecReturn("No sketch support and no base shape: Please tell me where to remove the material of the pocket!"); + } } // get the Sketch plane @@ -129,7 +122,6 @@ App::DocumentObjectExecReturn *Pocket::execute(void) TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { - support.Move(invObjLoc); base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); @@ -142,45 +134,37 @@ App::DocumentObjectExecReturn *Pocket::execute(void) std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToFace") { + // Note: This will throw an exception if the sketch is located on a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); if (Reversed.getValue()) dir.Reverse(); - // Find a valid face to extrude up to + // Find a valid face or datum plane to extrude up to TopoDS_Face upToFace; if (method == "UpToFace") { getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } - getUpToFace(upToFace, support, supportface, sketchshape, method, dir); - - // #0001655: When 'supportshape' consists of several faces BRepFeat_MakePrism uses only the first face. - // Thus, we have to iterate over the faces and use the algorithm for each of them. - TopoDS_Shape prism = support; - for (TopExp_Explorer xp(sketchshape, TopAbs_FACE); xp.More(); xp.Next()) { - // Special treatment because often the created stand-alone prism is invalid (empty) because - // BRepFeat_MakePrism(..., 2, 1) is buggy - // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results - BRepFeat_MakePrism PrismMaker; - PrismMaker.Init(prism, xp.Current(), supportface, dir, 0, 1); - PrismMaker.Perform(upToFace); - - if (!PrismMaker.IsDone()) - return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); - prism = PrismMaker.Shape(); - } + getUpToFace(upToFace, base, supportface, sketchshape, method, dir); - prism = refineShapeIfActive(prism); + // Special treatment because often the created stand-alone prism is invalid (empty) because + // BRepFeat_MakePrism(..., 2, 1) is buggy + BRepFeat_MakePrism PrismMaker; + PrismMaker.Init(base, sketchshape, supportface, dir, 0, 1); + PrismMaker.Perform(upToFace); + + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); + TopoDS_Shape prism = PrismMaker.Shape(); // And the really expensive way to get the SubShape... - BRepAlgoAPI_Cut mkCut(support, prism); + BRepAlgoAPI_Cut mkCut(base, prism); if (!mkCut.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not get SubShape!"); // FIXME: In some cases this affects the Shape property: It is set to the same shape as the SubShape!!!! - TopoDS_Shape result = refineShapeIfActive(mkCut.Shape()); - this->SubShape.setValue(result); + this->SubShape.setValue(mkCut.Shape()); this->Shape.setValue(prism); } else { TopoDS_Shape prism; diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index fe3a4703219b..ca217b1ae3a2 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -65,11 +65,13 @@ #include #include +#include #include #include #include #include #include "FeatureSketchBased.h" +#include "DatumPlane.h" using namespace PartDesign; @@ -180,9 +182,13 @@ std::vector SketchBased::getSketchWires() const { // this method, it becomes null! const TopoDS_Face SketchBased::getSupportFace() const { const App::PropertyLinkSub& Support = static_cast(Sketch.getValue())->Support; + App::DocumentObject* ref = Support.getValue(); + if (ref->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + ref->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + throw Base::Exception("Sketch must be located on a face of a solid for this feature to work"); Part::Feature *part = static_cast(Support.getValue()); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Sketch has no support shape"); + throw Base::Exception("No support in sketch"); const std::vector &sub = Support.getSubValues(); assert(sub.size()==1); @@ -449,6 +455,25 @@ void SketchBased::getUpToFaceFromLinkSub(TopoDS_Face& upToFace, if (ref == NULL) throw Base::Exception("SketchBased: Up to face: No face selected"); + + if (ref->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* plane = static_cast(ref); + Base::Rotation rot = plane->Placement.getValue().getRotation(); + Base::Vector3d normal(0,0,1); + rot.multVec(normal, normal); + BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z))); + if (!builder.IsDone()) + throw Base::Exception("SketchBased: Up to face: Could not create shape from base plane"); + upToFace = TopoDS::Face(builder.Shape()); + return; + } + + if (ref->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + Part::Datum* datum = static_cast(ref); + upToFace = TopoDS::Face(datum->getShape()); + return; + } + if (!ref->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::Exception("SketchBased: Up to face: Must be face of a feature"); Part::TopoShape baseShape = static_cast(ref)->Shape.getShape(); @@ -472,7 +497,7 @@ void SketchBased::getUpToFace(TopoDS_Face& upToFace, if ((method == "UpToLast") || (method == "UpToFirst")) { // Check for valid support object if (support.IsNull()) - throw Base::Exception("SketchBased: Up to face: No support in Sketch!"); + throw Base::Exception("SketchBased: Up to face: No support in Sketch and no base feature!"); std::vector cfaces = Part::findAllFacesCutBy(support, sketchshape, dir); if (cfaces.empty()) @@ -489,33 +514,37 @@ void SketchBased::getUpToFace(TopoDS_Face& upToFace, upToFace = (method == "UpToLast" ? it_far->face : it_near->face); } - // Remove the limits of the upToFace so that the extrusion works even if sketchshape is larger - // than the upToFace - bool remove_limits = false; - TopExp_Explorer Ex; - for (Ex.Init(sketchshape,TopAbs_FACE); Ex.More(); Ex.Next()) { - // Get outermost wire of sketch face - TopoDS_Face sketchface = TopoDS::Face(Ex.Current()); - TopoDS_Wire outerWire = ShapeAnalysis::OuterWire(sketchface); - if (!checkWireInsideFace(outerWire, upToFace, dir)) { - remove_limits = true; - break; + // Check whether the face has limits or not. Unlimited faces have no wire + // Note: Datum planes are always unlimited + TopExp_Explorer Ex(upToFace,TopAbs_WIRE); + if (Ex.More()) { + // Remove the limits of the upToFace so that the extrusion works even if sketchshape is larger + // than the upToFace + bool remove_limits = false; + for (Ex.Init(sketchshape,TopAbs_FACE); Ex.More(); Ex.Next()) { + // Get outermost wire of sketch face + TopoDS_Face sketchface = TopoDS::Face(Ex.Current()); + TopoDS_Wire outerWire = ShapeAnalysis::OuterWire(sketchface); + if (!checkWireInsideFace(outerWire, upToFace, dir)) { + remove_limits = true; + break; + } } - } - if (remove_limits) { - // Note: Using an unlimited face every time gives unnecessary failures for concave faces - TopLoc_Location loc = upToFace.Location(); - BRepAdaptor_Surface adapt(upToFace, Standard_False); - BRepBuilderAPI_MakeFace mkFace(adapt.Surface().Surface() -#if OCC_VERSION_HEX >= 0x060502 - , Precision::Confusion() -#endif - ); - if (!mkFace.IsDone()) - throw Base::Exception("SketchBased: Up To Face: Failed to create unlimited face"); - upToFace = TopoDS::Face(mkFace.Shape()); - upToFace.Location(loc); + if (remove_limits) { + // Note: Using an unlimited face every time gives unnecessary failures for concave faces + TopLoc_Location loc = upToFace.Location(); + BRepAdaptor_Surface adapt(upToFace, Standard_False); + BRepBuilderAPI_MakeFace mkFace(adapt.Surface().Surface() + #if OCC_VERSION_HEX >= 0x060502 + , Precision::Confusion() + #endif + ); + if (!mkFace.IsDone()) + throw Base::Exception("SketchBased: Up To Face: Failed to create unlimited face"); + upToFace = TopoDS::Face(mkFace.Shape()); + upToFace.Location(loc); + } } // Check that the upToFace does not intersect the sketch face and diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index d56b97b0a194..2a86eaa8d199 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -46,9 +46,9 @@ class PartDesignExport SketchBased : public PartDesign::Feature // Common properties for all sketch based features /// Sketch used to create this feature - App::PropertyLink Sketch; + App::PropertyLink Sketch; /// Reverse extrusion direction - App::PropertyBool Reversed; + App::PropertyBool Reversed; /// Make extrusion symmetric to sketch plane App::PropertyBool Midplane; /// Face to extrude up to @@ -71,8 +71,6 @@ class PartDesignExport SketchBased : public PartDesign::Feature std::vector getSketchWires() const; /// Returns the face of the sketch support (if any) const TopoDS_Face getSupportFace() const; - /// Returns the sketch support feature or NULL - Part::Feature* getSupport() const; /// Returns the sketch support shape (if any) const TopoDS_Shape& getSupportShape() const; /// Check whether the sketch support is a datum plane @@ -127,6 +125,9 @@ class PartDesignExport SketchBased : public PartDesign::Feature private: class Wire_Compare; + + /// Returns the sketch support feature or NULL + Part::Feature* getSupport() const; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 60b25bf12c6a..3b6450afced3 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -52,7 +52,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c return true; if (pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { - // Allow selecting Part::Datum features + // Allow selecting Part::Datum features from the active Body if (!ActivePartObject->hasFeature(pObj)) return false; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 51ff1cfc9f8a..48b80a001cca 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -103,6 +103,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg bool reversed = pcPad->Reversed.getValue(); Base::Quantity l2 = pcPad->Length2.getQuantityValue(); int index = pcPad->Type.getValue(); // must extract value here, clear() kills it! + App::DocumentObject* obj = pcPad->UpToFace.getValue(); std::vector subStrings = pcPad->UpToFace.getSubValues(); std::string upToFace; int faceId = -1; @@ -128,12 +129,13 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg // According to bug #0000521 the reversed option // shouldn't be de-activated if the pad has a support face ui->checkBoxReversed->setChecked(reversed); -#if QT_VERSION >= 0x040700 - ui->lineFaceName->setPlaceholderText(tr("No face selected")); -#endif - ui->lineFaceName->setText(faceId >= 0 ? - tr("Face") + QString::number(faceId) : - QString()); + if (PartDesign::Feature::isDatum(obj)) + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); + else if (faceId >= 0) + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + + QString::number(faceId)); + else + ui->lineFaceName->setText(tr("No face selected")); ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str())); ui->changeMode->clear(); ui->changeMode->insertItem(0, tr("Dimension")); @@ -195,7 +197,7 @@ void TaskPadParameters::updateUI(int index) ui->lineFaceName->setEnabled(true); QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection); // Go into reference selection mode if no face has been selected yet - if (ui->lineFaceName->text().isEmpty()) + if (ui->lineFaceName->text().isEmpty() || (ui->lineFaceName->text() == tr("No face selected"))) onButtonFace(true); } else { // two dimensions ui->lengthEdit->setEnabled(true); @@ -332,7 +334,10 @@ int TaskPadParameters::getMode(void) const QByteArray TaskPadParameters::getFaceName(void) const { - return ui->lineFaceName->property("FaceName").toByteArray(); + if ((getMode() >= 1) || (getMode() <= 3)) + return getFaceReference(ui->lineFaceName->text(), ui->lineFaceName->property("FaceName").toString()).toLatin1(); + else + return ""; } const bool TaskPadParameters::updateView() const @@ -363,7 +368,8 @@ void TaskPadParameters::changeEvent(QEvent *e) ui->changeMode->addItem(tr("Two dimensions")); ui->changeMode->setCurrentIndex(index); - QByteArray upToFace = this->getFaceName(); + QStringList parts = ui->lineFaceName->text().split(QChar::fromAscii(':')); + QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); int faceId = -1; bool ok = false; if (upToFace.indexOf("Face") == 0) { @@ -373,7 +379,7 @@ void TaskPadParameters::changeEvent(QEvent *e) ui->lineFaceName->setPlaceholderText(tr("No face selected")); #endif ui->lineFaceName->setText(ok ? - tr("Face") + QString::number(faceId) : + parts[0] + tr(":Face") + QString::number(faceId) : QString()); ui->lengthEdit->blockSignals(false); ui->lengthEdit2->blockSignals(false); @@ -403,14 +409,9 @@ void TaskPadParameters::apply() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",cname,getMode()); std::string facename = getFaceName().data(); - PartDesign::Pad* pcPad = static_cast(vp->getObject()); - Part::Feature* support = pcPad->getSupport(); - if (support != NULL && !facename.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromUtf8(support->getNameInDocument())); - buf = buf.arg(QString::fromStdString(facename)); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", cname, buf.toStdString().c_str()); + if (!facename.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), facename.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 6c126d077c55..a117fc6e5b35 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -96,6 +96,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge bool midplane = pcPocket->Midplane.getValue(); bool reversed = pcPocket->Reversed.getValue(); int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it! + App::DocumentObject* obj = pcPocket->UpToFace.getValue(); std::vector subStrings = pcPocket->UpToFace.getSubValues(); std::string upToFace; int faceId = -1; @@ -111,9 +112,13 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->pocketLength->setValue(l); ui->checkBoxMidplane->setChecked(midplane); ui->checkBoxReversed->setChecked(reversed); - ui->lineFaceName->setText(faceId >= 0 ? - tr("Face") + QString::number(faceId) : - tr("No face selected")); + if (PartDesign::Feature::isDatum(obj)) + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); + else if (faceId >= 0) + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + + QString::number(faceId)); + else + ui->lineFaceName->setText(tr("No face selected")); ui->lineFaceName->setProperty("FaceName", QByteArray(upToFace.c_str())); ui->changeMode->clear(); ui->changeMode->insertItem(0, tr("Dimension")); @@ -185,7 +190,7 @@ void TaskPocketParameters::updateUI(int index) ui->lineFaceName->setEnabled(true); QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection); // Go into reference selection mode if no face has been selected yet - if (ui->lineFaceName->text().isEmpty()) + if (ui->lineFaceName->text().isEmpty() || (ui->lineFaceName->text() == tr("No face selected"))) onButtonFace(true); } } @@ -309,7 +314,10 @@ int TaskPocketParameters::getMode(void) const QByteArray TaskPocketParameters::getFaceName(void) const { - return ui->lineFaceName->property("FaceName").toByteArray(); + if ((getMode() >= 1) || (getMode() <= 3)) + return getFaceReference(ui->lineFaceName->text(), ui->lineFaceName->property("FaceName").toString()).toLatin1(); + else + return ""; } const bool TaskPocketParameters::updateView() const @@ -338,14 +346,15 @@ void TaskPocketParameters::changeEvent(QEvent *e) ui->changeMode->addItem(tr("Up to face")); ui->changeMode->setCurrentIndex(index); - QByteArray upToFace = this->getFaceName(); + QStringList parts = ui->lineFaceName->text().split(QChar::fromAscii(':')); + QByteArray upToFace = ui->lineFaceName->property("FaceName").toByteArray(); int faceId = -1; bool ok = false; if (upToFace.indexOf("Face") == 0) { faceId = upToFace.remove(0,4).toInt(&ok); } ui->lineFaceName->setText(ok ? - tr("Face") + QString::number(faceId) : + parts[0] + tr(":Face") + QString::number(faceId) : tr("No face selected")); ui->pocketLength->blockSignals(false); ui->lineFaceName->blockSignals(false); @@ -361,13 +370,9 @@ void TaskPocketParameters::apply() ui->pocketLength->apply(); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),getMode()); std::string facename = getFaceName().data(); - PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); - Part::Feature* support = pcPocket->getSupport(); - if (support != NULL && !facename.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromUtf8(support->getNameInDocument())); - buf = buf.arg(QString::fromStdString(facename)); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), buf.toStdString().c_str()); + + if (!facename.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), facename.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", name.c_str(), getReversed()?1:0); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 318d2e044ecf..1a0ca7cfed47 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3085,7 +3085,7 @@ void SketchObject::rebuildExternalGeometry(void) if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { const Part::Datum* datum = static_cast(Obj); - refSubShape = datum->Shape.getValue(); + refSubShape = datum->getShape(); } else if (Obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { try { const Part::Feature *refObj=static_cast(Obj); From cda9b57b6cee6ccf0535b84ce9ef06e7b8b12d08 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 14 May 2013 15:45:02 +0430 Subject: [PATCH 110/664] miscellaneous fixes --- src/Mod/PartDesign/Gui/Command.cpp | 3 ++- src/Mod/PartDesign/Gui/ViewProvider.cpp | 5 ++++- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index fe0aa261a6d1..e3b0fb541817 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -186,7 +186,8 @@ void CmdPartDesignMoveTip::activated(int iMsg) } App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); + if (!oldTip->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); if (prevSolidFeature != NULL) doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index a0b9de8a885e..83d92ef1a6af 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -58,7 +58,10 @@ bool ViewProvider::doubleClicked(void) // Drop into insert mode so that the user doesn't see all the geometry that comes later in the tree // Also, this way the user won't be tempted to use future geometry as external references for the sketch oldTip = ActivePartObject->Tip.getValue(); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + if (oldTip != this->pcObject) + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + else + oldTip = NULL; } else { oldTip = NULL; } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index cbefe3883844..af2e8d2f1194 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -265,7 +265,10 @@ bool ViewProviderDatum::doubleClicked(void) // Drop into insert mode so that the user doesn't see all the geometry that comes later in the tree // Also, this way the user won't be tempted to use future geometry as external references for the sketch oldTip = ActivePartObject->Tip.getValue(); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + if (oldTip != this->pcObject) + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + else + oldTip = NULL; } else { oldTip = NULL; } From 1f42d4e3a3cfc28adc000241c174a0ad0be4dd1c Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 14 May 2013 16:02:43 +0430 Subject: [PATCH 111/664] bugfix for extrude to datum plane --- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 4 ++-- src/Mod/PartDesign/Gui/TaskPocketParameters.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 48b80a001cca..61fcfb838f77 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -107,7 +107,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg std::vector subStrings = pcPad->UpToFace.getSubValues(); std::string upToFace; int faceId = -1; - if (!subStrings.empty()) { + if ((obj != NULL) && !subStrings.empty()) { upToFace = subStrings.front(); if (upToFace.substr(0,4) == "Face") faceId = std::atoi(&upToFace[4]); @@ -129,7 +129,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg // According to bug #0000521 the reversed option // shouldn't be de-activated if the pad has a support face ui->checkBoxReversed->setChecked(reversed); - if (PartDesign::Feature::isDatum(obj)) + if ((obj != NULL) && PartDesign::Feature::isDatum(obj)) ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); else if (faceId >= 0) ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index a117fc6e5b35..8622d1be64df 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -100,7 +100,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge std::vector subStrings = pcPocket->UpToFace.getSubValues(); std::string upToFace; int faceId = -1; - if (!subStrings.empty()) { + if ((obj != NULL) && !subStrings.empty()) { upToFace = subStrings.front(); if (upToFace.substr(0,4) == "Face") faceId = std::atoi(&upToFace[4]); @@ -112,7 +112,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->pocketLength->setValue(l); ui->checkBoxMidplane->setChecked(midplane); ui->checkBoxReversed->setChecked(reversed); - if (PartDesign::Feature::isDatum(obj)) + if ((obj != NULL) && PartDesign::Feature::isDatum(obj)) ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); else if (faceId >= 0) ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + From 4645fdcd372966cca5d4e0c4c4c8d89d65394aaa Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 15 May 2013 19:13:21 +0430 Subject: [PATCH 112/664] Miscellaneous fixes --- src/Mod/PartDesign/App/Feature.cpp | 18 ++++++++++++++ src/Mod/PartDesign/App/Feature.h | 2 ++ src/Mod/PartDesign/App/FeatureSketchBased.cpp | 13 ++-------- src/Mod/PartDesign/App/FeatureTransformed.cpp | 24 +++++++++++++------ src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 9 +++---- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 2 +- .../PartDesign/Gui/TaskPocketParameters.cpp | 2 +- .../Gui/TaskSketchBasedParameters.cpp | 3 +-- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 20 +++++++++++++--- 9 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 40014cfae443..fe5c0ce07e75 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -29,6 +29,8 @@ # include # include # include +# include +# include #endif @@ -114,4 +116,20 @@ bool Feature::isDatum(const App::DocumentObject* feature) feature->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()); } +TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) +{ + const App::Plane* plane = static_cast(obj); + if (plane == NULL) + throw Base::Exception("Feature: Null object"); + + Base::Rotation rot = plane->Placement.getValue().getRotation(); + Base::Vector3d normal(0,0,1); + rot.multVec(normal, normal); + BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z))); + if (!builder.IsDone()) + throw Base::Exception("Feature: Could not create shape from base plane"); + + return builder.Shape(); +} + } diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index ab5309c1d30c..daa024c45be0 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -66,6 +66,8 @@ class PartDesignExport Feature : public Part::Feature /// Grab any point from the given face static const gp_Pnt getPointFromFace(const TopoDS_Face& f); + /// Make a shape from a base plane (convenience method) + static TopoDS_Shape makeShapeFromPlane(const App::DocumentObject* obj); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index ca217b1ae3a2..e3689dc92b29 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -457,18 +457,9 @@ void SketchBased::getUpToFaceFromLinkSub(TopoDS_Face& upToFace, throw Base::Exception("SketchBased: Up to face: No face selected"); if (ref->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { - App::Plane* plane = static_cast(ref); - Base::Rotation rot = plane->Placement.getValue().getRotation(); - Base::Vector3d normal(0,0,1); - rot.multVec(normal, normal); - BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z))); - if (!builder.IsDone()) - throw Base::Exception("SketchBased: Up to face: Could not create shape from base plane"); - upToFace = TopoDS::Face(builder.Shape()); + upToFace = TopoDS::Face(makeShapeFromPlane(ref)); return; - } - - if (ref->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + } else if (ref->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { Part::Datum* datum = static_cast(ref); upToFace = TopoDS::Face(datum->getShape()); return; diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index 679ebaa11494..2ac20f93bc5b 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -251,15 +251,25 @@ App::DocumentObjectExecReturn *Transformed::execute(void) return new App::DocumentObjectExecReturn("Transformation failed", (*o)); // Check for intersection with support - if (!Part::checkIntersection(support, mkTrf.Shape(), false, true)) { + try { + if (!Part::checkIntersection(support, mkTrf.Shape(), false, true)) { #ifdef FC_DEBUG // do not write this in release mode because a message appears already in the task view - Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); + Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); #endif - nointersect_trsfms.insert(t); - } else { - v_transformations.push_back(t); - v_transformedShapes.push_back(mkTrf.Shape()); - // Note: Transformations that do not intersect the support are ignored in the overlap tests + nointersect_trsfms.insert(t); + } else { + v_transformations.push_back(t); + v_transformedShapes.push_back(mkTrf.Shape()); + // Note: Transformations that do not intersect the support are ignored in the overlap tests + } + } catch (Standard_Failure) { + // Note: Ignoring this failure is probably pointless because if the intersection check fails, the later + // fuse operation of the transformation result will also fail + Handle_Standard_Failure e = Standard_Failure::Caught(); + std::string msg("Transformation: Intersection check failed"); + if (e->GetMessageString() != NULL) + msg += std::string(": '") + e->GetMessageString() + "'"; + return new App::DocumentObjectExecReturn(msg.c_str()); } } diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 3b6450afced3..eb33af112a88 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -47,6 +47,10 @@ using namespace Gui; bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName) { + // Don't allow selection in other document + if ((support != NULL) && (pDoc != support->getDocument())) + return false; + if (plane && (pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()))) // Note: It is assumed that a Part has exactly 3 App::Plane objects at the root of the feature tree return true; @@ -68,10 +72,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c // Handle selection of geometry elements if (support == NULL) - return false; - // Don't allow selection in other document - if (pDoc != support->getDocument()) - return false; + return false; if (!sSubName || sSubName[0] == '\0') return false; if (pObj != support) diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 61fcfb838f77..2164d7ba41e2 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -334,7 +334,7 @@ int TaskPadParameters::getMode(void) const QByteArray TaskPadParameters::getFaceName(void) const { - if ((getMode() >= 1) || (getMode() <= 3)) + if ((getMode() >= 1) && (getMode() <= 3)) return getFaceReference(ui->lineFaceName->text(), ui->lineFaceName->property("FaceName").toString()).toLatin1(); else return ""; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 8622d1be64df..1eac9291f779 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -314,7 +314,7 @@ int TaskPocketParameters::getMode(void) const QByteArray TaskPocketParameters::getFaceName(void) const { - if ((getMode() >= 1) || (getMode() <= 3)) + if ((getMode() >= 1) && (getMode() <= 3)) return getFaceReference(ui->lineFaceName->text(), ui->lineFaceName->property("FaceName").toString()).toLatin1(); else return ""; diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 10fb21399794..dcf9ddc85cb3 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -91,8 +91,7 @@ const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChan QString refStr; // Remove subname for planes and datum features - if (selObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || - selObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { + if (PartDesign::Feature::isDatum(selObj)) { subname = ""; refStr = QString::fromAscii(selObj->getNameInDocument()); } else { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index af2e8d2f1194..398bcc03299c 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -32,6 +32,8 @@ # include # include # include +# include +# include # include # include # include @@ -90,15 +92,27 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) else if (o->getTypeId() == PartDesign::Point::getClassTypeId()) datumType = QObject::tr("Point"); - SoSeparator* sep = new SoSeparator(); - SoPickStyle* ps = new SoPickStyle(); - ps->style = SoPickStyle::SHAPE; SoShapeHints* hints = new SoShapeHints(); hints->shapeType.setValue(SoShapeHints::UNKNOWN_SHAPE_TYPE); hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); + SoMaterialBinding* bind = new SoMaterialBinding(); + SoTransparencyType* ttype = new SoTransparencyType(); + ttype->value.setValue(SoGLRenderAction::BLEND); + SoDrawStyle* fstyle = new SoDrawStyle(); + fstyle->style = SoDrawStyle::FILLED; + SoNormalBinding* normb = new SoNormalBinding(); + normb->value = SoNormalBinding::PER_VERTEX_INDEXED; SoBaseColor* color = new SoBaseColor(); color->rgb.setValue(0.9, 0.9, 0.3); + SoSeparator* sep = new SoSeparator(); + SoPickStyle* ps = new SoPickStyle(); + ps->style = SoPickStyle::SHAPE; + sep->addChild(hints); + sep->addChild(bind); + sep->addChild(ttype); + sep->addChild(fstyle); + sep->addChild(normb); sep->addChild(color); sep->addChild(ps); sep->addChild(pShapeSep); From 880587a62729711896291deaae6969bb89ada530 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 15 May 2013 20:37:14 +0430 Subject: [PATCH 113/664] Allow datum lines and planes for Transformed features' references --- .../PartDesign/App/FeatureLinearPattern.cpp | 28 +- src/Mod/PartDesign/App/FeatureMirrored.cpp | 33 +- .../PartDesign/App/FeaturePolarPattern.cpp | 17 +- .../Gui/TaskLinearPatternParameters.cpp | 142 ++--- .../Gui/TaskLinearPatternParameters.cpp.orig | 511 ++++++++++++++++++ .../Gui/TaskLinearPatternParameters.h | 2 +- .../Gui/TaskLinearPatternParameters.ui | 17 +- .../PartDesign/Gui/TaskMirroredParameters.cpp | 165 +++--- .../Gui/TaskMirroredParameters.cpp.orig | 412 ++++++++++++++ .../PartDesign/Gui/TaskMirroredParameters.h | 2 +- .../PartDesign/Gui/TaskMirroredParameters.ui | 17 +- .../Gui/TaskPolarPatternParameters.cpp | 86 ++- .../Gui/TaskPolarPatternParameters.cpp.orig | 424 +++++++++++++++ .../Gui/TaskPolarPatternParameters.h | 3 +- .../Gui/TaskTransformedParameters.cpp | 42 +- .../Gui/TaskTransformedParameters.h | 11 +- 16 files changed, 1709 insertions(+), 203 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig diff --git a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp index 9841c4ccc0ec..f17846be440c 100644 --- a/src/Mod/PartDesign/App/FeatureLinearPattern.cpp +++ b/src/Mod/PartDesign/App/FeatureLinearPattern.cpp @@ -34,6 +34,9 @@ #include "FeatureLinearPattern.h" +#include "DatumPlane.h" +#include "DatumLine.h" +#include #include #include #include @@ -79,10 +82,9 @@ const std::list LinearPattern::getTransformations(const std::vectorgetTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Direction reference must be edge or face of a feature"); + std::vector subStrings = Direction.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) + if (subStrings.empty()) throw Base::Exception("No direction reference specified"); gp_Dir dir; @@ -102,7 +104,23 @@ const std::list LinearPattern::getTransformations(const std::vectorPlacement.getValue(); dir = gp_Dir(axis.getDirection().x, axis.getDirection().y, axis.getDirection().z); - } else { + } else if (refObject->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* plane = static_cast(refObject); + Base::Vector3d d = plane->getNormal(); + dir = gp_Dir(d.x, d.y, d.z); + } else if (refObject->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* line = static_cast(refObject); + Base::Vector3d d = line->getDirection(); + dir = gp_Dir(d.x, d.y, d.z); + } else if (refObject->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* plane = static_cast(refObject); + Base::Rotation rot = plane->Placement.getValue().getRotation(); + Base::Vector3d d(0,0,1); + rot.multVec(d, d); + dir = gp_Dir(d.x, d.y, d.z); + } else if (refObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + if (subStrings[0].empty()) + throw Base::Exception("No direction reference specified"); Part::Feature* refFeature = static_cast(refObject); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); @@ -128,6 +146,8 @@ const std::list LinearPattern::getTransformations(const std::vectorgetLocation().Inverted(); dir.Transform(invObjLoc.Transformation()); diff --git a/src/Mod/PartDesign/App/FeatureMirrored.cpp b/src/Mod/PartDesign/App/FeatureMirrored.cpp index 0206134bf7a2..a599a4eccbc2 100644 --- a/src/Mod/PartDesign/App/FeatureMirrored.cpp +++ b/src/Mod/PartDesign/App/FeatureMirrored.cpp @@ -31,8 +31,10 @@ #endif +#include #include #include "FeatureMirrored.h" +#include "DatumPlane.h" #include #include @@ -60,10 +62,8 @@ const std::list Mirrored::getTransformations(const std::vectorgetTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Mirror plane reference must be face of a feature"); std::vector subStrings = MirrorPlane.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) + if (subStrings.empty()) throw Base::Exception("No mirror plane reference specified"); gp_Pnt axbase; @@ -86,13 +86,29 @@ const std::list Mirrored::getTransformations(const std::vectorPlacement.getValue(); - axbase = gp_Pnt(axis.getBase().x, axis.getBase().y, axis.getBase().z); + axbase = gp_Pnt(axis.getBase().x, axis.getBase().y, axis.getBase().z); axdir = gp_Dir(axis.getDirection().x, axis.getDirection().y, axis.getDirection().z); - } else { + } else if (refObject->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* plane = static_cast(refObject); + Base::Vector3d base = plane->getBasePoint(); + axbase = gp_Pnt(base.x, base.y, base.z); + Base::Vector3d dir = plane->getNormal(); + axdir = gp_Dir(dir.x, dir.y, dir.z); + } else if (refObject->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane* plane = static_cast(refObject); + Base::Vector3d base = plane->Placement.getValue().getPosition(); + axbase = gp_Pnt(base.x, base.y, base.z); + Base::Rotation rot = plane->Placement.getValue().getRotation(); + Base::Vector3d dir(0,0,1); + rot.multVec(dir, dir); + axdir = gp_Dir(dir.x, dir.y, dir.z); + } else if (refObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + if (subStrings[0].empty()) + throw Base::Exception("No direction reference specified"); Part::TopoShape baseShape = static_cast(refObject)->Shape.getShape(); // TODO: Check for multiple mirror planes? - - TopoDS_Face face = TopoDS::Face(baseShape.getSubShape(subStrings[0].c_str())); + TopoDS_Shape shape = baseShape.getSubShape(subStrings[0].c_str()); + TopoDS_Face face = TopoDS::Face(shape); if (face.IsNull()) throw Base::Exception("Failed to extract mirror plane"); BRepAdaptor_Surface adapt(face); @@ -101,7 +117,10 @@ const std::list Mirrored::getTransformations(const std::vectorgetLocation().Inverted(); axbase.Transform(invObjLoc.Transformation()); axdir.Transform(invObjLoc.Transformation()); diff --git a/src/Mod/PartDesign/App/FeaturePolarPattern.cpp b/src/Mod/PartDesign/App/FeaturePolarPattern.cpp index e0906a29b0a8..653718d6a81d 100644 --- a/src/Mod/PartDesign/App/FeaturePolarPattern.cpp +++ b/src/Mod/PartDesign/App/FeaturePolarPattern.cpp @@ -32,6 +32,7 @@ #include "FeaturePolarPattern.h" +#include "DatumLine.h" #include #include #include @@ -82,10 +83,8 @@ const std::list PolarPattern::getTransformations(const std::vectorgetTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Axis reference must be edge of a feature"); std::vector subStrings = Axis.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) + if (subStrings.empty()) throw Base::Exception("No axis reference specified"); gp_Pnt axbase; @@ -107,7 +106,15 @@ const std::list PolarPattern::getTransformations(const std::vectorPlacement.getValue(); axbase = gp_Pnt(axis.getBase().x, axis.getBase().y, axis.getBase().z); axdir = gp_Dir(axis.getDirection().x, axis.getDirection().y, axis.getDirection().z); - } else { + } else if (refObject->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* line = static_cast(refObject); + Base::Vector3d base = line->getBasePoint(); + axbase = gp_Pnt(base.x, base.y, base.z); + Base::Vector3d dir = line->getDirection(); + axdir = gp_Dir(dir.x, dir.y, dir.z); + } else if (refObject->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + if (subStrings[0].empty()) + throw Base::Exception("No axis reference specified"); Part::Feature* refFeature = static_cast(refObject); Part::TopoShape refShape = refFeature->Shape.getShape(); TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); @@ -125,6 +132,8 @@ const std::list PolarPattern::getTransformations(const std::vectorgetLocation().Inverted(); axbase.Transform(invObjLoc.Transformation()); diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 621a10cf4bfd..c84f865597ae 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -31,6 +31,7 @@ #include "ui_TaskLinearPatternParameters.h" #include "TaskLinearPatternParameters.h" #include "TaskMultiTransformParameters.h" +#include "Workbench.h" #include #include #include @@ -43,6 +44,8 @@ #include #include #include +#include +#include #include using namespace PartDesignGui; @@ -155,15 +158,16 @@ void TaskLinearPatternParameters::updateUI() double length = pcLinearPattern->Length.getValue(); unsigned occurrences = pcLinearPattern->Occurrences.getValue(); + // Add user-defined sketch axes to the reference selection combo box App::DocumentObject* sketch = getSketchObject(); - int maxcount=2; + int maxcount=5; if (sketch) maxcount += static_cast(sketch)->getAxisCount(); - for (int i=ui->comboDirection->count()-1; i >= 2; i--) + for (int i=ui->comboDirection->count()-1; i >= 5; i--) ui->comboDirection->removeItem(i); for (int i=ui->comboDirection->count(); i < maxcount; i++) - ui->comboDirection->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); + ui->comboDirection->addItem(QString::fromLatin1("Sketch axis %1").arg(i-5)); bool undefined = false; if (directionFeature != NULL && !directions.empty()) { @@ -171,14 +175,20 @@ void TaskLinearPatternParameters::updateUI() ui->comboDirection->setCurrentIndex(0); else if (directions.front() == "V_Axis") ui->comboDirection->setCurrentIndex(1); + else if (strcmp(directionFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[0]) == 0) + ui->comboDirection->setCurrentIndex(2); + else if (strcmp(directionFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[1]) == 0) + ui->comboDirection->setCurrentIndex(3); + else if (strcmp(directionFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[2]) == 0) + ui->comboDirection->setCurrentIndex(4); else if (directions.front().size() > 4 && directions.front().substr(0,4) == "Axis") { - int pos = 2 + std::atoi(directions.front().substr(4,4000).c_str()); + int pos = 5 + std::atoi(directions.front().substr(4,4000).c_str()); if (pos <= maxcount) ui->comboDirection->setCurrentIndex(pos); else undefined = true; - } else if (directionFeature != NULL && !directions.empty()) { - ui->comboDirection->addItem(QString::fromLatin1(directions.front().c_str())); + } else { + ui->comboDirection->addItem(getRefStr(directionFeature, directions)); ui->comboDirection->setCurrentIndex(maxcount); } } else { @@ -186,7 +196,7 @@ void TaskLinearPatternParameters::updateUI() } if (referenceSelectionMode) { - ui->comboDirection->addItem(tr("Select an edge or a face")); + ui->comboDirection->addItem(tr("Select an edge/face or datum line/plane")); ui->comboDirection->setCurrentIndex(ui->comboDirection->count() - 1); } else if (undefined) { ui->comboDirection->addItem(tr("Undefined")); @@ -220,34 +230,33 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) return; - std::string subName(msg.pSubName); if (originalSelected(msg)) { ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode && - ((subName.size() > 4 && subName.substr(0,4) == "Edge") || - (subName.size() > 4 && subName.substr(0,4) == "Face"))) { - - if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) - return; - + } else if (referenceSelectionMode) { + // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { + std::vector directions; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, directions); PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); - std::vector directions(1,subName); - pcLinearPattern->Direction.setValue(getSupportObject(), directions); + pcLinearPattern->Direction.setValue(selObj, directions); recomputeFeature(); updateUI(); } else { App::DocumentObject* sketch = getSketchObject(); - int maxcount=2; + int maxcount=5; if (sketch) maxcount += static_cast(sketch)->getAxisCount(); for (int i=ui->comboDirection->count()-1; i >= maxcount; i--) ui->comboDirection->removeItem(i); - ui->comboDirection->addItem(QString::fromLatin1(subName.c_str())); + std::vector directions; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, directions); + ui->comboDirection->addItem(getRefStr(selObj, directions)); ui->comboDirection->setCurrentIndex(maxcount); ui->comboDirection->addItem(tr("Select reference...")); } @@ -291,7 +300,7 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); App::DocumentObject* pcSketch = getSketchObject(); - int maxcount=2; + int maxcount=5; if (pcSketch) maxcount += static_cast(pcSketch)->getAxisCount(); @@ -303,8 +312,23 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,"V_Axis")); exitSelectionMode(); } - else if (num >= 2 && num < maxcount) { - QString buf = QString::fromUtf8("Axis%1").arg(num-2); + else if (num == 2) { + pcLinearPattern->Direction.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 3) { + pcLinearPattern->Direction.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 4) { + pcLinearPattern->Direction.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); std::string str = buf.toStdString(); pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,str)); } @@ -328,18 +352,11 @@ void TaskLinearPatternParameters::onUpdateView(bool on) if (on) { // Do the same like in TaskDlgLinearPatternParameters::accept() but without doCommand PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + std::vector directions; + App::DocumentObject* obj; - std::string direction = getDirection(); - if (!direction.empty()) { - std::vector directions(1,direction); - if (direction == "H_Axis" || direction == "V_Axis" || - (direction.size() > 4 && direction.substr(0,4) == "Axis")) - pcLinearPattern->Direction.setValue(getSketchObject(), directions); - else - pcLinearPattern->Direction.setValue(getSupportObject(), directions); - } else - pcLinearPattern->Direction.setValue(NULL); - + getDirection(obj, directions); + pcLinearPattern->Direction.setValue(obj,directions); pcLinearPattern->Reversed.setValue(getReverse()); pcLinearPattern->Length.setValue(getLength()); pcLinearPattern->Occurrences.setValue(getOccurrences()); @@ -348,25 +365,36 @@ void TaskLinearPatternParameters::onUpdateView(bool on) } } -const std::string TaskLinearPatternParameters::getDirection(void) const +void TaskLinearPatternParameters::getDirection(App::DocumentObject*& obj, std::vector& sub) const { - App::DocumentObject* pcSketch = getSketchObject(); - int maxcount=2; - if (pcSketch) - maxcount += static_cast(pcSketch)->getAxisCount(); + obj = getSketchObject(); + sub = std::vector(1,""); + int maxcount=5; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); int num = ui->comboDirection->currentIndex(); if (num == 0) - return "H_Axis"; + sub[0] = "H_Axis"; else if (num == 1) - return "V_Axis"; - else if (num >= 2 && num < maxcount) { - QString buf = QString::fromUtf8("Axis%1").arg(num-2); - return buf.toStdString(); - } else if (num == maxcount && - ui->comboDirection->count() == maxcount + 2) - return ui->comboDirection->currentText().toStdString(); - return std::string(""); + sub[0] = "V_Axis"; + else if (num == 2) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]); + else if (num == 3) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]); + else if (num == 4) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]); + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->comboDirection->count() == maxcount + 2) { + QStringList parts = ui->comboDirection->currentText().split(QChar::fromAscii(':')); + obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } } const bool TaskLinearPatternParameters::getReverse(void) const @@ -403,22 +431,13 @@ void TaskLinearPatternParameters::changeEvent(QEvent *e) void TaskLinearPatternParameters::apply() { std::string name = TransformedView->getObject()->getNameInDocument(); - std::string direction = getDirection(); + std::vector directions; + App::DocumentObject* obj; + getDirection(obj, directions); + std::string direction = getPythonStr(obj, directions); if (!direction.empty()) { - App::DocumentObject* sketch = 0; - if (direction == "H_Axis" || direction == "V_Axis" || - (direction.size() > 4 && direction.substr(0,4) == "Axis")) - sketch = getSketchObject(); - else - sketch = getSupportObject(); - - if (sketch) { - QString buf = QString::fromLatin1("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromLatin1(sketch->getNameInDocument())); - buf = buf.arg(QString::fromLatin1(direction.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), buf.toStdString().c_str()); - } + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), direction.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),getReverse()); @@ -451,7 +470,6 @@ TaskDlgLinearPatternParameters::TaskDlgLinearPatternParameters(ViewProviderLinea bool TaskDlgLinearPatternParameters::accept() { try { - //Gui::Command::openCommand("LinearPattern changed"); // Handle Originals if (!TaskDlgTransformedParameters::accept()) return false; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig new file mode 100644 index 000000000000..0a982a4a8b40 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig @@ -0,0 +1,511 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +# include +#endif + +#include "ui_TaskLinearPatternParameters.h" +#include "TaskLinearPatternParameters.h" +#include "TaskMultiTransformParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskLinearPatternParameters */ + +TaskLinearPatternParameters::TaskLinearPatternParameters(ViewProviderTransformed *TransformedView,QWidget *parent) + : TaskTransformedParameters(TransformedView, parent) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskLinearPatternParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + this->groupLayout()->addWidget(proxy); + + ui->buttonOK->hide(); + ui->checkBoxUpdateView->setEnabled(true); + + referenceSelectionMode = false; + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +TaskLinearPatternParameters::TaskLinearPatternParameters(TaskMultiTransformParameters *parentTask, QLayout *layout) + : TaskTransformedParameters(parentTask) +{ + proxy = new QWidget(parentTask); + ui = new Ui_TaskLinearPatternParameters(); + ui->setupUi(proxy); + connect(ui->buttonOK, SIGNAL(pressed()), + parentTask, SLOT(onSubTaskButtonOK())); + QMetaObject::connectSlotsByName(this); + + layout->addWidget(proxy); + + ui->buttonOK->setEnabled(true); + ui->labelOriginal->hide(); + ui->lineOriginal->hide(); + ui->checkBoxUpdateView->hide(); + + referenceSelectionMode = false; + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +void TaskLinearPatternParameters::setupUI() +{ + updateViewTimer = new QTimer(this); + updateViewTimer->setSingleShot(true); + updateViewTimer->setInterval(getUpdateViewTimeout()); + + connect(updateViewTimer, SIGNAL(timeout()), + this, SLOT(onUpdateViewTimer())); + connect(ui->comboDirection, SIGNAL(activated(int)), + this, SLOT(onDirectionChanged(int))); + connect(ui->checkReverse, SIGNAL(toggled(bool)), + this, SLOT(onCheckReverse(bool))); + connect(ui->spinLength, SIGNAL(valueChanged(double)), + this, SLOT(onLength(double))); + connect(ui->spinOccurrences, SIGNAL(valueChanged(uint)), + this, SLOT(onOccurrences(uint))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + // Get the feature data + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + std::vector originals = pcLinearPattern->Originals.getValues(); + + // Fill data into dialog elements + ui->lineOriginal->setEnabled(false); + for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) + { + if ((*i) != NULL) { // find the first valid original + ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); + break; + } + } + // --------------------- + + ui->spinLength->bind(pcLinearPattern->Length); + ui->spinOccurrences->setMaximum(INT_MAX); + ui->spinOccurrences->bind(pcLinearPattern->Occurrences); + + ui->comboDirection->setEnabled(true); + ui->checkReverse->setEnabled(true); + ui->spinLength->blockSignals(true); + ui->spinLength->setEnabled(true); + ui->spinLength->setUnit(Base::Unit::Length); + ui->spinLength->blockSignals(false); + ui->spinOccurrences->setEnabled(true); + updateUI(); +} + +void TaskLinearPatternParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + + App::DocumentObject* directionFeature = pcLinearPattern->Direction.getValue(); + std::vector directions = pcLinearPattern->Direction.getSubValues(); + bool reverse = pcLinearPattern->Reversed.getValue(); + double length = pcLinearPattern->Length.getValue(); + unsigned occurrences = pcLinearPattern->Occurrences.getValue(); + + // Add user-defined sketch axes to the reference selection combo box + App::DocumentObject* sketch = getSketchObject(); + int maxcount=5; + if (sketch) + maxcount += static_cast(sketch)->getAxisCount(); + + for (int i=ui->comboDirection->count()-1; i >= 5; i--) + ui->comboDirection->removeItem(i); + for (int i=ui->comboDirection->count(); i < maxcount; i++) +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->comboDirection->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); +======= + ui->comboDirection->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); +>>>>>>> Allow datum lines and planes for Transformed features' references + + bool undefined = false; + if (directionFeature != NULL && !directions.empty()) { + if (directions.front() == "H_Axis") + ui->comboDirection->setCurrentIndex(0); + else if (directions.front() == "V_Axis") + ui->comboDirection->setCurrentIndex(1); + else if (strcmp(directionFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[0]) == 0) + ui->comboDirection->setCurrentIndex(2); + else if (strcmp(directionFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[1]) == 0) + ui->comboDirection->setCurrentIndex(3); + else if (strcmp(directionFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[2]) == 0) + ui->comboDirection->setCurrentIndex(4); + else if (directions.front().size() > 4 && directions.front().substr(0,4) == "Axis") { + int pos = 5 + std::atoi(directions.front().substr(4,4000).c_str()); + if (pos <= maxcount) + ui->comboDirection->setCurrentIndex(pos); + else + undefined = true; +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + } else if (directionFeature != NULL && !directions.empty()) { + ui->comboDirection->addItem(QString::fromLatin1(directions.front().c_str())); +======= + } else { + ui->comboDirection->addItem(getRefStr(directionFeature, directions)); +>>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboDirection->setCurrentIndex(maxcount); + } + } else { + undefined = true; + } + + if (referenceSelectionMode) { + ui->comboDirection->addItem(tr("Select an edge/face or datum line/plane")); + ui->comboDirection->setCurrentIndex(ui->comboDirection->count() - 1); + } else if (undefined) { + ui->comboDirection->addItem(tr("Undefined")); + ui->comboDirection->setCurrentIndex(ui->comboDirection->count() - 1); + } else + ui->comboDirection->addItem(tr("Select reference...")); + + // Note: These three lines would trigger onLength(), on Occurrences() and another updateUI() if we + // didn't check for blockUpdate + ui->checkReverse->setChecked(reverse); + ui->spinLength->setValue(length); + ui->spinOccurrences->setValue(occurrences); + + blockUpdate = false; +} + +void TaskLinearPatternParameters::onUpdateViewTimer() +{ + recomputeFeature(); +} + +void TaskLinearPatternParameters::kickUpdateViewTimer() const +{ + updateViewTimer->start(); +} + +void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + + if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) + return; + + if (originalSelected(msg)) { +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); + } else if (referenceSelectionMode && + ((subName.size() > 4 && subName.substr(0,4) == "Edge") || + (subName.size() > 4 && subName.substr(0,4) == "Face"))) { + + if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) + return; + +======= + ui->lineOriginal->setText(QString::fromAscii(msg.pObjectName)); + } else if (referenceSelectionMode) { + // Note: ReferenceSelection has already checked the selection for validity +>>>>>>> Allow datum lines and planes for Transformed features' references + exitSelectionMode(); + if (!blockUpdate) { + std::vector directions; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, directions); + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + pcLinearPattern->Direction.setValue(selObj, directions); + + recomputeFeature(); + updateUI(); + } + else { + App::DocumentObject* sketch = getSketchObject(); + int maxcount=5; + if (sketch) + maxcount += static_cast(sketch)->getAxisCount(); + for (int i=ui->comboDirection->count()-1; i >= maxcount; i--) + ui->comboDirection->removeItem(i); + +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->comboDirection->addItem(QString::fromLatin1(subName.c_str())); +======= + std::vector directions; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, directions); + ui->comboDirection->addItem(getRefStr(selObj, directions)); +>>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboDirection->setCurrentIndex(maxcount); + ui->comboDirection->addItem(tr("Select reference...")); + } + } + } +} + +void TaskLinearPatternParameters::onCheckReverse(const bool on) { + if (blockUpdate) + return; + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + pcLinearPattern->Reversed.setValue(on); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + +void TaskLinearPatternParameters::onLength(const double l) { + if (blockUpdate) + return; + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + pcLinearPattern->Length.setValue(l); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + +void TaskLinearPatternParameters::onOccurrences(const uint n) { + if (blockUpdate) + return; + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + pcLinearPattern->Occurrences.setValue(n); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + +void TaskLinearPatternParameters::onDirectionChanged(int num) { + if (blockUpdate) + return; + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + + App::DocumentObject* pcSketch = getSketchObject(); + int maxcount=5; + if (pcSketch) + maxcount += static_cast(pcSketch)->getAxisCount(); + + if (num == 0) { + pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,"H_Axis")); + exitSelectionMode(); + } + else if (num == 1) { + pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,"V_Axis")); + exitSelectionMode(); + } + else if (num == 2) { + pcLinearPattern->Direction.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 3) { + pcLinearPattern->Direction.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 4) { + pcLinearPattern->Direction.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); + std::string str = buf.toStdString(); + pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,str)); + } + else if (num == ui->comboDirection->count() - 1) { + // enter reference selection mode + hideObject(); + showOriginals(); + referenceSelectionMode = true; + Gui::Selection().clearSelection(); + addReferenceSelectionGate(true, true); + } + else if (num == maxcount) + exitSelectionMode(); + + kickUpdateViewTimer(); +} + +void TaskLinearPatternParameters::onUpdateView(bool on) +{ + blockUpdate = !on; + if (on) { + // Do the same like in TaskDlgLinearPatternParameters::accept() but without doCommand + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + std::vector directions; + App::DocumentObject* obj; + + getDirection(obj, directions); + pcLinearPattern->Direction.setValue(obj,directions); + pcLinearPattern->Reversed.setValue(getReverse()); + pcLinearPattern->Length.setValue(getLength()); + pcLinearPattern->Occurrences.setValue(getOccurrences()); + + recomputeFeature(); + } +} + +void TaskLinearPatternParameters::getDirection(App::DocumentObject*& obj, std::vector& sub) const +{ + obj = getSketchObject(); + sub = std::vector(1,""); + int maxcount=5; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + + int num = ui->comboDirection->currentIndex(); + if (num == 0) + sub[0] = "H_Axis"; + else if (num == 1) + sub[0] = "V_Axis"; + else if (num == 2) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]); + else if (num == 3) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]); + else if (num == 4) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]); + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->comboDirection->count() == maxcount + 2) { + QStringList parts = ui->comboDirection->currentText().split(QChar::fromAscii(':')); + obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } +} + +const bool TaskLinearPatternParameters::getReverse(void) const +{ + return ui->checkReverse->isChecked(); +} + +const double TaskLinearPatternParameters::getLength(void) const +{ + return ui->spinLength->value().getValue(); +} + +const unsigned TaskLinearPatternParameters::getOccurrences(void) const +{ + return ui->spinOccurrences->value(); +} + + +TaskLinearPatternParameters::~TaskLinearPatternParameters() +{ + delete ui; + if (proxy) + delete proxy; +} + +void TaskLinearPatternParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +void TaskLinearPatternParameters::apply() +{ + std::string name = TransformedView->getObject()->getNameInDocument(); + + std::vector directions; + App::DocumentObject* obj; + getDirection(obj, directions); + std::string direction = getPythonStr(obj, directions); + if (!direction.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = %s", name.c_str(), direction.c_str()); + } else + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Direction = None", name.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),getReverse()); + + ui->spinLength->apply(); + ui->spinOccurrences->apply(); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!TransformedView->getObject()->isValid()) + throw Base::Exception(TransformedView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgLinearPatternParameters::TaskDlgLinearPatternParameters(ViewProviderLinearPattern *LinearPatternView) + : TaskDlgTransformedParameters(LinearPatternView) +{ + parameter = new TaskLinearPatternParameters(LinearPatternView); + + Content.push_back(parameter); +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgLinearPatternParameters::accept() +{ + try { + // Handle Originals + if (!TaskDlgTransformedParameters::accept()) + return false; + + parameter->apply(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return true; +} + +#include "moc_TaskLinearPatternParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h index 2f557357d879..5bf80e256ccb 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h @@ -70,7 +70,7 @@ private Q_SLOTS: protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); - const std::string getDirection(void) const; + void getDirection(App::DocumentObject*& obj, std::vector& sub) const; const bool getReverse(void) const; const double getLength(void) const; const unsigned getOccurrences(void) const; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui index b1ad7ce8e1ee..dff273eb8952 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui @@ -6,7 +6,7 @@ 0 0 - 260 + 266 402 @@ -49,6 +49,21 @@ Vertical sketch axis + + + Base plane XY + + + + + Base plane XZ + + + + + Base plane YZ + + Select reference... diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index eae21f844d4f..a1da163966fe 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -30,6 +30,7 @@ #include "ui_TaskMirroredParameters.h" #include "TaskMirroredParameters.h" #include "TaskMultiTransformParameters.h" +#include "Workbench.h" #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #include @@ -56,7 +58,7 @@ TaskMirroredParameters::TaskMirroredParameters(ViewProviderTransformed *Transfor ui = new Ui_TaskMirroredParameters(); ui->setupUi(proxy); QMetaObject::connectSlotsByName(this); - + this->groupLayout()->addWidget(proxy); ui->buttonOK->hide(); @@ -119,24 +121,25 @@ void TaskMirroredParameters::setupUI() void TaskMirroredParameters::updateUI() { - if (blockUpdate) + if (blockUpdate) return; blockUpdate = true; - + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); - + App::DocumentObject* mirrorPlaneFeature = pcMirrored->MirrorPlane.getValue(); std::vector mirrorPlanes = pcMirrored->MirrorPlane.getSubValues(); - + + // Add user-defined sketch axes to the reference selection combo box App::DocumentObject* sketch = getSketchObject(); - int maxcount=2; + int maxcount=5; if (sketch) maxcount += static_cast(sketch)->getAxisCount(); - for (int i=ui->comboPlane->count()-1; i >= 2; i--) + for (int i=ui->comboPlane->count()-1; i >= 5; i--) ui->comboPlane->removeItem(i); for (int i=ui->comboPlane->count(); i < maxcount; i++) - ui->comboPlane->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); + ui->comboPlane->addItem(QString::fromLatin1("Sketch axis %1").arg(i-5)); bool undefined = false; if (mirrorPlaneFeature != NULL && !mirrorPlanes.empty()) { @@ -144,22 +147,28 @@ void TaskMirroredParameters::updateUI() ui->comboPlane->setCurrentIndex(0); else if (mirrorPlanes.front() == "V_Axis") ui->comboPlane->setCurrentIndex(1); + else if (strcmp(mirrorPlaneFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[0]) == 0) + ui->comboPlane->setCurrentIndex(2); + else if (strcmp(mirrorPlaneFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[1]) == 0) + ui->comboPlane->setCurrentIndex(3); + else if (strcmp(mirrorPlaneFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[2]) == 0) + ui->comboPlane->setCurrentIndex(4); else if (mirrorPlanes.front().size() > 4 && mirrorPlanes.front().substr(0,4) == "Axis") { - int pos = 2 + std::atoi(mirrorPlanes.front().substr(4,4000).c_str()); + int pos = 5 + std::atoi(mirrorPlanes.front().substr(4,4000).c_str()); if (pos <= maxcount) ui->comboPlane->setCurrentIndex(pos); else undefined = true; - } else if (mirrorPlaneFeature != NULL && !mirrorPlanes.empty()) { - ui->comboPlane->addItem(QString::fromLatin1(mirrorPlanes.front().c_str())); - ui->comboPlane->setCurrentIndex(maxcount); + } else { + ui->comboPlane->addItem(getRefStr(mirrorPlaneFeature, mirrorPlanes)); + ui->comboPlane->setCurrentIndex(maxcount); } } else { undefined = true; } - + if (referenceSelectionMode) { - ui->comboPlane->addItem(tr("Select a face")); + ui->comboPlane->addItem(tr("Select a face or datum plane")); ui->comboPlane->setCurrentIndex(ui->comboPlane->count() - 1); } else if (undefined) { ui->comboPlane->addItem(tr("Undefined")); @@ -177,33 +186,33 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) return; - std::string subName(msg.pSubName); if (originalSelected(msg)) { ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode && - (subName.size() > 4 && subName.substr(0,4) == "Face")) { - - if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) - return; - + } else if (referenceSelectionMode) { + // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { + std::vector mirrorPlanes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, mirrorPlanes); PartDesign::Mirrored* pcMirrored = static_cast(getObject()); - std::vector mirrorPlanes(1,subName); - pcMirrored->MirrorPlane.setValue(getSupportObject(), mirrorPlanes); + pcMirrored->MirrorPlane.setValue(selObj, mirrorPlanes); recomputeFeature(); updateUI(); } else { App::DocumentObject* sketch = getSketchObject(); - int maxcount=2; + int maxcount=5; if (sketch) maxcount += static_cast(sketch)->getAxisCount(); for (int i=ui->comboPlane->count()-1; i >= maxcount; i--) ui->comboPlane->removeItem(i); - ui->comboPlane->addItem(QString::fromLatin1(subName.c_str())); + std::vector mirrorPlanes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, mirrorPlanes); + ui->comboPlane->addItem(getRefStr(selObj, mirrorPlanes)); ui->comboPlane->setCurrentIndex(maxcount); ui->comboPlane->addItem(tr("Select reference...")); } @@ -212,12 +221,12 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg } void TaskMirroredParameters::onPlaneChanged(int num) { - if (blockUpdate) + if (blockUpdate) return; PartDesign::Mirrored* pcMirrored = static_cast(getObject()); - + App::DocumentObject* pcSketch = getSketchObject(); - int maxcount=2; + int maxcount=5; if (pcSketch) maxcount += static_cast(pcSketch)->getAxisCount(); @@ -229,8 +238,23 @@ void TaskMirroredParameters::onPlaneChanged(int num) { pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,"V_Axis")); exitSelectionMode(); } - else if (num >= 2 && num < maxcount) { - QString buf = QString::fromUtf8("Axis%1").arg(num-2); + else if (num == 2) { + pcMirrored->MirrorPlane.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 3) { + pcMirrored->MirrorPlane.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 4) { + pcMirrored->MirrorPlane.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); std::string str = buf.toStdString(); pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,str)); } @@ -244,7 +268,7 @@ void TaskMirroredParameters::onPlaneChanged(int num) { } else if (num == maxcount) exitSelectionMode(); - + recomputeFeature(); } @@ -254,41 +278,46 @@ void TaskMirroredParameters::onUpdateView(bool on) if (on) { // Do the same like in TaskDlgMirroredParameters::accept() but without doCommand PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + std::vector mirrorPlanes; + App::DocumentObject* obj; - std::string mirrorPlane = getMirrorPlane(); - if (!mirrorPlane.empty()) { - std::vector planes(1,mirrorPlane); - if (mirrorPlane == "H_Axis" || mirrorPlane == "V_Axis" || - (mirrorPlane.size() > 4 && mirrorPlane.substr(0,4) == "Axis")) - pcMirrored->MirrorPlane.setValue(getSketchObject(),planes); - else - pcMirrored->MirrorPlane.setValue(getSupportObject(),planes); - } else - pcMirrored->MirrorPlane.setValue(NULL); + getMirrorPlane(obj, mirrorPlanes); + pcMirrored->MirrorPlane.setValue(obj,mirrorPlanes); recomputeFeature(); } } -const std::string TaskMirroredParameters::getMirrorPlane(void) const +void TaskMirroredParameters::getMirrorPlane(App::DocumentObject*& obj, std::vector& sub) const { - App::DocumentObject* pcSketch = getSketchObject(); - int maxcount=2; - if (pcSketch) - maxcount += static_cast(pcSketch)->getAxisCount(); - + obj = getSketchObject(); + sub = std::vector(1,""); + int maxcount=5; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + int num = ui->comboPlane->currentIndex(); if (num == 0) - return "H_Axis"; + sub[0] = "H_Axis"; else if (num == 1) - return "V_Axis"; - else if (num >= 2 && num < maxcount) { - QString buf = QString::fromUtf8("Axis%1").arg(num-2); - return buf.toStdString(); - } else if (num == maxcount && - ui->comboPlane->count() == maxcount + 2) - return ui->comboPlane->currentText().toStdString(); - return std::string(""); + sub[0] = "V_Axis"; + else if (num == 2) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]); + else if (num == 3) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]); + else if (num == 4) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]); + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->comboPlane->count() == maxcount + 2) { + QStringList parts = ui->comboPlane->currentText().split(QChar::fromAscii(':')); + obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } } void TaskMirroredParameters::apply() @@ -329,29 +358,19 @@ bool TaskDlgMirroredParameters::accept() std::string name = TransformedView->getObject()->getNameInDocument(); try { - //Gui::Command::openCommand("Mirrored changed"); - // Handle Originals + // Handle Originals if (!TaskDlgTransformedParameters::accept()) return false; TaskMirroredParameters* mirrorParameter = static_cast(parameter); - std::string mirrorPlane = mirrorParameter->getMirrorPlane(); + std::vector mirrorPlanes; + App::DocumentObject* obj; + mirrorParameter->getMirrorPlane(obj, mirrorPlanes); + std::string mirrorPlane = mirrorParameter->getPythonStr(obj, mirrorPlanes); if (!mirrorPlane.empty()) { - App::DocumentObject* sketch = 0; - if (mirrorPlane == "H_Axis" || mirrorPlane == "V_Axis" || - (mirrorPlane.size() > 4 && mirrorPlane.substr(0,4) == "Axis")) - sketch = mirrorParameter->getSketchObject(); - else - sketch = mirrorParameter->getSupportObject(); - - if (sketch) { - QString buf = QString::fromLatin1("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromLatin1(sketch->getNameInDocument())); - buf = buf.arg(QString::fromLatin1(mirrorPlane.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = %s", name.c_str(), buf.toStdString().c_str()); - } + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = %s", name.c_str(), mirrorPlane.c_str()); } else - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = None", name.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!TransformedView->getObject()->isValid()) throw Base::Exception(TransformedView->getObject()->getStatusString()); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig new file mode 100644 index 000000000000..c3ae4235c1ba --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig @@ -0,0 +1,412 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +#endif + +#include "ui_TaskMirroredParameters.h" +#include "TaskMirroredParameters.h" +#include "TaskMultiTransformParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskMirroredParameters */ + +TaskMirroredParameters::TaskMirroredParameters(ViewProviderTransformed *TransformedView, QWidget *parent) + : TaskTransformedParameters(TransformedView, parent) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskMirroredParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + this->groupLayout()->addWidget(proxy); + + ui->buttonOK->hide(); + ui->checkBoxUpdateView->setEnabled(true); + + referenceSelectionMode = false; + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +TaskMirroredParameters::TaskMirroredParameters(TaskMultiTransformParameters *parentTask, QLayout *layout) + : TaskTransformedParameters(parentTask) +{ + proxy = new QWidget(parentTask); + ui = new Ui_TaskMirroredParameters(); + ui->setupUi(proxy); + connect(ui->buttonOK, SIGNAL(pressed()), + parentTask, SLOT(onSubTaskButtonOK())); + QMetaObject::connectSlotsByName(this); + + layout->addWidget(proxy); + + ui->buttonOK->setEnabled(true); + ui->labelOriginal->hide(); + ui->lineOriginal->hide(); + ui->checkBoxUpdateView->hide(); + + referenceSelectionMode = false; + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +void TaskMirroredParameters::setupUI() +{ + connect(ui->comboPlane, SIGNAL(activated(int)), + this, SLOT(onPlaneChanged(int))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + // Get the feature data + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + std::vector originals = pcMirrored->Originals.getValues(); + + // Fill data into dialog elements + ui->lineOriginal->setEnabled(false); + for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) + { + if ((*i) != NULL) { // find the first valid original + ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); + break; + } + } + // --------------------- + + ui->comboPlane->setEnabled(true); + updateUI(); +} + +void TaskMirroredParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + + App::DocumentObject* mirrorPlaneFeature = pcMirrored->MirrorPlane.getValue(); + std::vector mirrorPlanes = pcMirrored->MirrorPlane.getSubValues(); + + // Add user-defined sketch axes to the reference selection combo box + App::DocumentObject* sketch = getSketchObject(); + int maxcount=5; + if (sketch) + maxcount += static_cast(sketch)->getAxisCount(); + + for (int i=ui->comboPlane->count()-1; i >= 5; i--) + ui->comboPlane->removeItem(i); + for (int i=ui->comboPlane->count(); i < maxcount; i++) +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->comboPlane->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); +======= + ui->comboPlane->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); +>>>>>>> Allow datum lines and planes for Transformed features' references + + bool undefined = false; + if (mirrorPlaneFeature != NULL && !mirrorPlanes.empty()) { + if (mirrorPlanes.front() == "H_Axis") + ui->comboPlane->setCurrentIndex(0); + else if (mirrorPlanes.front() == "V_Axis") + ui->comboPlane->setCurrentIndex(1); + else if (strcmp(mirrorPlaneFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[0]) == 0) + ui->comboPlane->setCurrentIndex(2); + else if (strcmp(mirrorPlaneFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[1]) == 0) + ui->comboPlane->setCurrentIndex(3); + else if (strcmp(mirrorPlaneFeature->getNameInDocument(), PartDesignGui::BaseplaneNames[2]) == 0) + ui->comboPlane->setCurrentIndex(4); + else if (mirrorPlanes.front().size() > 4 && mirrorPlanes.front().substr(0,4) == "Axis") { + int pos = 5 + std::atoi(mirrorPlanes.front().substr(4,4000).c_str()); + if (pos <= maxcount) + ui->comboPlane->setCurrentIndex(pos); + else + undefined = true; +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + } else if (mirrorPlaneFeature != NULL && !mirrorPlanes.empty()) { + ui->comboPlane->addItem(QString::fromLatin1(mirrorPlanes.front().c_str())); + ui->comboPlane->setCurrentIndex(maxcount); +======= + } else { + ui->comboPlane->addItem(getRefStr(mirrorPlaneFeature, mirrorPlanes)); + ui->comboPlane->setCurrentIndex(maxcount); +>>>>>>> Allow datum lines and planes for Transformed features' references + } + } else { + undefined = true; + } + + if (referenceSelectionMode) { + ui->comboPlane->addItem(tr("Select a face or datum plane")); + ui->comboPlane->setCurrentIndex(ui->comboPlane->count() - 1); + } else if (undefined) { + ui->comboPlane->addItem(tr("Undefined")); + ui->comboPlane->setCurrentIndex(ui->comboPlane->count() - 1); + } else + ui->comboPlane->addItem(tr("Select reference...")); + + blockUpdate = false; +} + +void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + + if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) + return; + + if (originalSelected(msg)) { +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); + } else if (referenceSelectionMode && + (subName.size() > 4 && subName.substr(0,4) == "Face")) { + + if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) + return; + +======= + ui->lineOriginal->setText(QString::fromAscii(msg.pObjectName)); + } else if (referenceSelectionMode) { + // Note: ReferenceSelection has already checked the selection for validity +>>>>>>> Allow datum lines and planes for Transformed features' references + exitSelectionMode(); + if (!blockUpdate) { + std::vector mirrorPlanes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, mirrorPlanes); + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + pcMirrored->MirrorPlane.setValue(selObj, mirrorPlanes); + + recomputeFeature(); + updateUI(); + } + else { + App::DocumentObject* sketch = getSketchObject(); + int maxcount=5; + if (sketch) + maxcount += static_cast(sketch)->getAxisCount(); + for (int i=ui->comboPlane->count()-1; i >= maxcount; i--) + ui->comboPlane->removeItem(i); + +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->comboPlane->addItem(QString::fromLatin1(subName.c_str())); +======= + std::vector mirrorPlanes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, mirrorPlanes); + ui->comboPlane->addItem(getRefStr(selObj, mirrorPlanes)); +>>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboPlane->setCurrentIndex(maxcount); + ui->comboPlane->addItem(tr("Select reference...")); + } + } + } +} + +void TaskMirroredParameters::onPlaneChanged(int num) { + if (blockUpdate) + return; + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + + App::DocumentObject* pcSketch = getSketchObject(); + int maxcount=5; + if (pcSketch) + maxcount += static_cast(pcSketch)->getAxisCount(); + + if (num == 0) { + pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,"H_Axis")); + exitSelectionMode(); + } + else if (num == 1) { + pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,"V_Axis")); + exitSelectionMode(); + } + else if (num == 2) { + pcMirrored->MirrorPlane.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 3) { + pcMirrored->MirrorPlane.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num == 4) { + pcMirrored->MirrorPlane.setValue(getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]), + std::vector(1,"")); + exitSelectionMode(); + } + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); + std::string str = buf.toStdString(); + pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,str)); + } + else if (num == ui->comboPlane->count() - 1) { + // enter reference selection mode + hideObject(); + showOriginals(); + referenceSelectionMode = true; + Gui::Selection().clearSelection(); + addReferenceSelectionGate(false, true); + } + else if (num == maxcount) + exitSelectionMode(); + + recomputeFeature(); +} + +void TaskMirroredParameters::onUpdateView(bool on) +{ + blockUpdate = !on; + if (on) { + // Do the same like in TaskDlgMirroredParameters::accept() but without doCommand + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + std::vector mirrorPlanes; + App::DocumentObject* obj; + + getMirrorPlane(obj, mirrorPlanes); + pcMirrored->MirrorPlane.setValue(obj,mirrorPlanes); + + recomputeFeature(); + } +} + +void TaskMirroredParameters::getMirrorPlane(App::DocumentObject*& obj, std::vector& sub) const +{ + obj = getSketchObject(); + sub = std::vector(1,""); + int maxcount=5; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + + int num = ui->comboPlane->currentIndex(); + if (num == 0) + sub[0] = "H_Axis"; + else if (num == 1) + sub[0] = "V_Axis"; + else if (num == 2) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[0]); + else if (num == 3) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[1]); + else if (num == 4) + obj = getObject()->getDocument()->getObject(PartDesignGui::BaseplaneNames[2]); + else if (num >= 5 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-5); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->comboPlane->count() == maxcount + 2) { + QStringList parts = ui->comboPlane->currentText().split(QChar::fromAscii(':')); + obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } +} + +void TaskMirroredParameters::apply() +{ +} + +TaskMirroredParameters::~TaskMirroredParameters() +{ + delete ui; + if (proxy) + delete proxy; +} + +void TaskMirroredParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgMirroredParameters::TaskDlgMirroredParameters(ViewProviderMirrored *MirroredView) + : TaskDlgTransformedParameters(MirroredView) +{ + parameter = new TaskMirroredParameters(MirroredView); + + Content.push_back(parameter); +} +//==== calls from the TaskView =============================================================== + +bool TaskDlgMirroredParameters::accept() +{ + std::string name = TransformedView->getObject()->getNameInDocument(); + + try { + // Handle Originals + if (!TaskDlgTransformedParameters::accept()) + return false; + + TaskMirroredParameters* mirrorParameter = static_cast(parameter); + std::vector mirrorPlanes; + App::DocumentObject* obj; + mirrorParameter->getMirrorPlane(obj, mirrorPlanes); + std::string mirrorPlane = mirrorParameter->getPythonStr(obj, mirrorPlanes); + if (!mirrorPlane.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = %s", name.c_str(), mirrorPlane.c_str()); + } else + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = None", name.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!TransformedView->getObject()->isValid()) + throw Base::Exception(TransformedView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return true; +} + +#include "moc_TaskMirroredParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.h b/src/Mod/PartDesign/Gui/TaskMirroredParameters.h index 3312662fa390..fa56829ed971 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.h +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.h @@ -57,7 +57,7 @@ class TaskMirroredParameters : public TaskTransformedParameters virtual ~TaskMirroredParameters(); - const std::string getMirrorPlane(void) const; + void getMirrorPlane(App::DocumentObject*& obj, std::vector& sub) const; virtual void apply(); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui b/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui index f0f2e8d7d789..461ca5e07f8d 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui @@ -6,7 +6,7 @@ 0 0 - 218 + 242 290 @@ -49,6 +49,21 @@ Vertical sketch axis + + + Base plane XY + + + + + Base plane XZ + + + + + Base plane YZ + + Select reference... diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index 8e556d814543..967fb4567afe 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -31,6 +31,7 @@ #include "ui_TaskPolarPatternParameters.h" #include "TaskPolarPatternParameters.h" #include "TaskMultiTransformParameters.h" +#include "Workbench.h" #include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include using namespace PartDesignGui; using namespace Gui; @@ -158,8 +160,8 @@ void TaskPolarPatternParameters::updateUI() if (axisFeature != NULL && !axes.empty()) { if (axes.front() == "N_Axis") ui->comboAxis->setCurrentIndex(0); - else if (axisFeature != NULL && !axes.empty()) { - ui->comboAxis->addItem(QString::fromLatin1(axes.front().c_str())); + else { + ui->comboAxis->addItem(getRefStr(axisFeature, axes)); ui->comboAxis->setCurrentIndex(1); } } else { @@ -167,7 +169,7 @@ void TaskPolarPatternParameters::updateUI() } if (referenceSelectionMode) { - ui->comboAxis->addItem(tr("Select an edge")); + ui->comboAxis->addItem(tr("Select an edge or datum line")); ui->comboAxis->setCurrentIndex(ui->comboAxis->count() - 1); } else ui->comboAxis->addItem(tr("Select reference...")); @@ -198,20 +200,17 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) return; - std::string subName(msg.pSubName); if (originalSelected(msg)) { ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode && - (subName.size() > 4 && subName.substr(0,4) == "Edge")) { - - if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) - return; - + } else if (referenceSelectionMode) { + // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { + std::vector axes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, axes); PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); - std::vector axes(1,subName); - pcPolarPattern->Axis.setValue(getSupportObject(), axes); + pcPolarPattern->Axis.setValue(selObj, axes); recomputeFeature(); updateUI(); @@ -220,7 +219,10 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& for (int i=ui->comboAxis->count()-1; i >= 1; i--) ui->comboAxis->removeItem(i); - ui->comboAxis->addItem(QString::fromLatin1(subName.c_str())); + std::vector axes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, axes); + ui->comboAxis->addItem(getRefStr(selObj, axes)); ui->comboAxis->setCurrentIndex(1); ui->comboAxis->addItem(tr("Select reference...")); } @@ -287,17 +289,11 @@ void TaskPolarPatternParameters::onUpdateView(bool on) if (on) { // Do the same like in TaskDlgPolarPatternParameters::accept() but without doCommand PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + std::vector axes; + App::DocumentObject* obj; - std::string axis = getAxis(); - if (!axis.empty()) { - std::vector axes(1,axis); - if (axis == "N_Axis") - pcPolarPattern->Axis.setValue(getSketchObject(), axes); - else - pcPolarPattern->Axis.setValue(getSupportObject(), axes); - } else - pcPolarPattern->Axis.setValue(NULL); - + getAxis(obj, axes); + pcPolarPattern->Axis.setValue(obj,axes); pcPolarPattern->Reversed.setValue(getReverse()); pcPolarPattern->Angle.setValue(getAngle()); pcPolarPattern->Occurrences.setValue(getOccurrences()); @@ -306,13 +302,21 @@ void TaskPolarPatternParameters::onUpdateView(bool on) } } -const std::string TaskPolarPatternParameters::getAxis(void) const -{ - if (ui->comboAxis->currentIndex() == 0) - return "N_Axis"; - else if (ui->comboAxis->count() > 2 && ui->comboAxis->currentIndex() == 1) - return ui->comboAxis->currentText().toStdString(); - return std::string(""); +void TaskPolarPatternParameters::getAxis(App::DocumentObject*& obj, std::vector& sub) const +{ + obj = getSketchObject(); + sub = std::vector(1,""); + + if (ui->comboAxis->currentIndex() == 0) { + sub[0] = "N_Axis"; + } else if (ui->comboAxis->count() > 2 && ui->comboAxis->currentIndex() == 1) { + QStringList parts = ui->comboAxis->currentText().split(QChar::fromAscii(':')); + obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } } const bool TaskPolarPatternParameters::getReverse(void) const @@ -349,21 +353,12 @@ void TaskPolarPatternParameters::changeEvent(QEvent *e) void TaskPolarPatternParameters::apply() { std::string name = TransformedView->getObject()->getNameInDocument(); - std::string axis = getAxis(); - - if (!axis.empty()) { - App::DocumentObject* sketch = 0; - if (axis == "N_Axis") - sketch = getSketchObject(); - else - sketch = getSupportObject(); - - if (sketch) { - QString buf = QString::fromLatin1("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromLatin1(sketch->getNameInDocument())); - buf = buf.arg(QString::fromLatin1(axis.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Axis = %s", name.c_str(), buf.toStdString().c_str()); - } + std::vector axes; + App::DocumentObject* obj; + getAxis(obj, axes); + std::string axis = getPythonStr(obj, axes); + if (!axis.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Axis = %s", name.c_str(), axis.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Axis = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),getReverse()); @@ -393,7 +388,6 @@ TaskDlgPolarPatternParameters::TaskDlgPolarPatternParameters(ViewProviderPolarPa bool TaskDlgPolarPatternParameters::accept() { try { - //Gui::Command::openCommand("PolarPattern changed"); // Handle Originals if (!TaskDlgTransformedParameters::accept()) return false; diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig new file mode 100644 index 000000000000..085ed2d81c4c --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig @@ -0,0 +1,424 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +# include +#endif + +#include "ui_TaskPolarPatternParameters.h" +#include "TaskPolarPatternParameters.h" +#include "TaskMultiTransformParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskPolarPatternParameters */ + +TaskPolarPatternParameters::TaskPolarPatternParameters(ViewProviderTransformed *TransformedView,QWidget *parent) + : TaskTransformedParameters(TransformedView, parent) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskPolarPatternParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + this->groupLayout()->addWidget(proxy); + + ui->buttonOK->hide(); + ui->checkBoxUpdateView->setEnabled(true); + + referenceSelectionMode = false; + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +TaskPolarPatternParameters::TaskPolarPatternParameters(TaskMultiTransformParameters *parentTask, QLayout *layout) + : TaskTransformedParameters(parentTask) +{ + proxy = new QWidget(parentTask); + ui = new Ui_TaskPolarPatternParameters(); + ui->setupUi(proxy); + connect(ui->buttonOK, SIGNAL(pressed()), + parentTask, SLOT(onSubTaskButtonOK())); + QMetaObject::connectSlotsByName(this); + + layout->addWidget(proxy); + + ui->buttonOK->setEnabled(true); + ui->labelOriginal->hide(); + ui->lineOriginal->hide(); + ui->checkBoxUpdateView->hide(); + + referenceSelectionMode = false; + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +void TaskPolarPatternParameters::setupUI() +{ + updateViewTimer = new QTimer(this); + updateViewTimer->setSingleShot(true); + updateViewTimer->setInterval(getUpdateViewTimeout()); + + connect(updateViewTimer, SIGNAL(timeout()), + this, SLOT(onUpdateViewTimer())); + connect(ui->comboAxis, SIGNAL(activated(int)), + this, SLOT(onAxisChanged(int))); + connect(ui->checkReverse, SIGNAL(toggled(bool)), + this, SLOT(onCheckReverse(bool))); + connect(ui->polarAngle, SIGNAL(valueChanged(double)), + this, SLOT(onAngle(double))); + connect(ui->spinOccurrences, SIGNAL(valueChanged(uint)), + this, SLOT(onOccurrences(uint))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + // Get the feature data + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + std::vector originals = pcPolarPattern->Originals.getValues(); + + // Fill data into dialog elements + ui->lineOriginal->setEnabled(false); + for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) + { + if ((*i) != NULL) { // find the first valid original + ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); + break; + } + } + // --------------------- + + ui->polarAngle->bind(pcPolarPattern->Angle); + ui->spinOccurrences->setMaximum(INT_MAX); + ui->spinOccurrences->bind(pcPolarPattern->Occurrences); + + ui->comboAxis->setEnabled(true); + ui->checkReverse->setEnabled(true); + ui->polarAngle->setEnabled(true); + ui->spinOccurrences->setEnabled(true); + updateUI(); +} + +void TaskPolarPatternParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + + App::DocumentObject* axisFeature = pcPolarPattern->Axis.getValue(); + std::vector axes = pcPolarPattern->Axis.getSubValues(); + bool reverse = pcPolarPattern->Reversed.getValue(); + double angle = pcPolarPattern->Angle.getValue(); + unsigned occurrences = pcPolarPattern->Occurrences.getValue(); + + for (int i=ui->comboAxis->count()-1; i >= 1; i--) + ui->comboAxis->removeItem(i); + + if (axisFeature != NULL && !axes.empty()) { + if (axes.front() == "N_Axis") + ui->comboAxis->setCurrentIndex(0); +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + else if (axisFeature != NULL && !axes.empty()) { + ui->comboAxis->addItem(QString::fromLatin1(axes.front().c_str())); +======= + else { + ui->comboAxis->addItem(getRefStr(axisFeature, axes)); +>>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboAxis->setCurrentIndex(1); + } + } else { + // Error message? + } + + if (referenceSelectionMode) { + ui->comboAxis->addItem(tr("Select an edge or datum line")); + ui->comboAxis->setCurrentIndex(ui->comboAxis->count() - 1); + } else + ui->comboAxis->addItem(tr("Select reference...")); + + // Note: These three lines would trigger onLength(), on Occurrences() and another updateUI() if we + // didn't check for blockUpdate + ui->checkReverse->setChecked(reverse); + ui->polarAngle->setValue(angle); + ui->spinOccurrences->setValue(occurrences); + + blockUpdate = false; +} + +void TaskPolarPatternParameters::onUpdateViewTimer() +{ + recomputeFeature(); +} + +void TaskPolarPatternParameters::kickUpdateViewTimer() const +{ + updateViewTimer->start(); +} + +void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + + if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) + return; + + if (originalSelected(msg)) { +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); + } else if (referenceSelectionMode && + (subName.size() > 4 && subName.substr(0,4) == "Edge")) { + + if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) + return; + +======= + ui->lineOriginal->setText(QString::fromAscii(msg.pObjectName)); + } else if (referenceSelectionMode) { + // Note: ReferenceSelection has already checked the selection for validity +>>>>>>> Allow datum lines and planes for Transformed features' references + exitSelectionMode(); + if (!blockUpdate) { + std::vector axes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, axes); + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + pcPolarPattern->Axis.setValue(selObj, axes); + + recomputeFeature(); + updateUI(); + } + else { + for (int i=ui->comboAxis->count()-1; i >= 1; i--) + ui->comboAxis->removeItem(i); + +<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 + ui->comboAxis->addItem(QString::fromLatin1(subName.c_str())); +======= + std::vector axes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, axes); + ui->comboAxis->addItem(getRefStr(selObj, axes)); +>>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboAxis->setCurrentIndex(1); + ui->comboAxis->addItem(tr("Select reference...")); + } + } + } +} + +void TaskPolarPatternParameters::onCheckReverse(const bool on) { + if (blockUpdate) + return; + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + pcPolarPattern->Reversed.setValue(on); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + +void TaskPolarPatternParameters::onAngle(const double a) { + if (blockUpdate) + return; + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + pcPolarPattern->Angle.setValue(a); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + +void TaskPolarPatternParameters::onOccurrences(const uint n) { + if (blockUpdate) + return; + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + pcPolarPattern->Occurrences.setValue(n); + + exitSelectionMode(); + kickUpdateViewTimer(); +} + +void TaskPolarPatternParameters::onAxisChanged(int num) { + if (blockUpdate) + return; + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + + if (num == 0) { + pcPolarPattern->Axis.setValue(getSketchObject(), std::vector(1,"N_Axis")); + exitSelectionMode(); + } + else if (num == ui->comboAxis->count() - 1) { + // enter reference selection mode + hideObject(); + showOriginals(); + referenceSelectionMode = true; + Gui::Selection().clearSelection(); + addReferenceSelectionGate(true, false); + } + else if (num == 1) + exitSelectionMode(); + + kickUpdateViewTimer(); +} + +void TaskPolarPatternParameters::onUpdateView(bool on) +{ + blockUpdate = !on; + if (on) { + // Do the same like in TaskDlgPolarPatternParameters::accept() but without doCommand + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + std::vector axes; + App::DocumentObject* obj; + + getAxis(obj, axes); + pcPolarPattern->Axis.setValue(obj,axes); + pcPolarPattern->Reversed.setValue(getReverse()); + pcPolarPattern->Angle.setValue(getAngle()); + pcPolarPattern->Occurrences.setValue(getOccurrences()); + + recomputeFeature(); + } +} + +void TaskPolarPatternParameters::getAxis(App::DocumentObject*& obj, std::vector& sub) const +{ + obj = getSketchObject(); + sub = std::vector(1,""); + + if (ui->comboAxis->currentIndex() == 0) { + sub[0] = "N_Axis"; + } else if (ui->comboAxis->count() > 2 && ui->comboAxis->currentIndex() == 1) { + QStringList parts = ui->comboAxis->currentText().split(QChar::fromAscii(':')); + obj = getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } +} + +const bool TaskPolarPatternParameters::getReverse(void) const +{ + return ui->checkReverse->isChecked(); +} + +const double TaskPolarPatternParameters::getAngle(void) const +{ + return ui->polarAngle->value().getValue(); +} + +const unsigned TaskPolarPatternParameters::getOccurrences(void) const +{ + return ui->spinOccurrences->value(); +} + + +TaskPolarPatternParameters::~TaskPolarPatternParameters() +{ + delete ui; + if (proxy) + delete proxy; +} + +void TaskPolarPatternParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +void TaskPolarPatternParameters::apply() +{ + std::string name = TransformedView->getObject()->getNameInDocument(); + std::vector axes; + App::DocumentObject* obj; + getAxis(obj, axes); + std::string axis = getPythonStr(obj, axes); + if (!axis.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Axis = %s", name.c_str(), axis.c_str()); + } else + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Axis = None", name.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),getReverse()); + ui->polarAngle->apply(); + ui->spinOccurrences->apply(); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!TransformedView->getObject()->isValid()) + throw Base::Exception(TransformedView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgPolarPatternParameters::TaskDlgPolarPatternParameters(ViewProviderPolarPattern *PolarPatternView) + : TaskDlgTransformedParameters(PolarPatternView) +{ + parameter = new TaskPolarPatternParameters(PolarPatternView); + + Content.push_back(parameter); +} +//==== calls from the TaskView =============================================================== + +bool TaskDlgPolarPatternParameters::accept() +{ + try { + // Handle Originals + if (!TaskDlgTransformedParameters::accept()) + return false; + + parameter->apply(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return true; +} + +#include "moc_TaskPolarPatternParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h index 442a3dcafe3f..531105cbb211 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h @@ -69,8 +69,9 @@ private Q_SLOTS: protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + void getAxis(App::DocumentObject*& obj, std::vector& sub) const; const std::string getStdAxis(void) const; - const std::string getAxis(void) const; + //const std::string getAxis(void) const; const bool getReverse(void) const; const double getAngle(void) const; const unsigned getOccurrences(void) const; diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 6615ee05738e..ce5f7f5a818b 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -98,7 +98,7 @@ const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChang { if (msg.Type == Gui::SelectionChanges::AddSelection && originalSelectionMode) { - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) + if ((msg.pDocName, getObject()->getDocument()->getName()) != 0) return false; PartDesign::Transformed* pcTransformed = getObject(); @@ -228,6 +228,46 @@ void TaskTransformedParameters::addReferenceSelectionGate(bool edge, bool face) Gui::Selection().addSelectionGate(new ReferenceSelection(getSupportObject(), edge, face, true)); } +void TaskTransformedParameters::getReferencedSelection(const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub) +{ + PartDesign::Transformed* pcTransformed = static_cast(getObject()); + selObj = pcTransformed->getDocument()->getObject(msg.pObjectName); + if (selObj == pcTransformed) + return; + std::string subname = msg.pSubName; + + // Remove subname for planes and datum features + if (PartDesign::Feature::isDatum(selObj)) { + subname = ""; + } + + selSub = std::vector(1,subname); +} + +const QString TaskTransformedParameters::getRefStr(const App::DocumentObject* obj, const std::vector& sub) +{ + if (obj == NULL) + return QString::fromAscii(""); + + if (PartDesign::Feature::isDatum(obj)) + return QString::fromAscii(obj->getNameInDocument()); + else + return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + + QString::fromAscii(sub.front().c_str()); +} + +const std::string TaskTransformedParameters::getPythonStr(const App::DocumentObject* obj, const std::vector& sub) +{ + if (obj == NULL) + return ""; + + if (PartDesign::Feature::isDatum(obj)) + return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])"; + else + return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])"; +} + //************************************************************************** //************************************************************************** diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index c49766548447..30209268ad91 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -64,6 +64,9 @@ class TaskTransformedParameters : public Gui::TaskView::TaskBox, public Gui::Sel /// Get the sketch object of the first original either of the object associated with this feature or with the parent feature (MultiTransform mode) App::DocumentObject* getSketchObject() const; + /// Return reference as string for python (format (, [""]) ) + const std::string getPythonStr(const App::DocumentObject* selObj, const std::vector& selSub); + void exitSelectionMode(); virtual void apply() = 0; @@ -87,6 +90,12 @@ protected Q_SLOTS: void showOriginals(); void addReferenceSelectionGate(bool edge, bool face); + /// Extract reference from Selection (convenience method) + void getReferencedSelection(const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub); + /// Return reference as string for UI elements (format : + const QString getRefStr(const App::DocumentObject* selObj, const std::vector& selSub); + bool isViewUpdated() const; int getUpdateViewTimeout() const; @@ -106,7 +115,7 @@ protected Q_SLOTS: /// Flag indicating whether this object is a container for MultiTransform bool insideMultiTransform; /// Lock updateUI(), applying changes to the underlying feature and calling recomputeFeature() - bool blockUpdate; + bool blockUpdate; }; /// simulation dialog for the TaskView From ffc09ec50c2ef63067831eda0c8898495eb99aa7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 16 May 2013 14:46:33 +0430 Subject: [PATCH 114/664] Duplicate Selection: Add duplicated features to active Body --- src/Mod/PartDesign/App/Body.cpp | 7 +++ src/Mod/PartDesign/Gui/Command.cpp | 79 ++++++++++++++++++++++++++++ src/Mod/PartDesign/Gui/Workbench.cpp | 23 ++++++++ src/Mod/PartDesign/Gui/Workbench.h | 2 + 4 files changed, 111 insertions(+) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index de1014f9b8ff..c95718381068 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -196,6 +196,13 @@ const bool Body::isAllowed(const App::DocumentObject* f) void Body::addFeature(App::DocumentObject *feature) { + /* + // Remove this test if Workbench::slotNewObject() has been tested sufficiently in respect to Undo() and + // the addFeature() calls have been removed in Command.cpp + if (hasFeature(feature)) + return; + */ + // Set the BaseFeature property if (feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { App::DocumentObject* prevSolidFeature = getPrevSolidFeature(NULL, true); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index e3b0fb541817..d15448cb1d5f 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -210,6 +210,78 @@ bool CmdPartDesignMoveTip::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_DuplicateSelection +//=========================================================================== + +DEF_STD_CMD_A(CmdPartDesignDuplicateSelection); + +CmdPartDesignDuplicateSelection::CmdPartDesignDuplicateSelection() + :Command("PartDesign_DuplicateSelection") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Duplicate selected object"); + sToolTipText = QT_TR_NOOP("Duplicates the selected object and adds it to the active body"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = ""; +} + +void CmdPartDesignDuplicateSelection::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + App::DocumentObject* selFeature = features.front(); + + if (!pcActiveBody->hasFeature(selFeature)) { + // NOTE: We assume all selected features will be in the same document + // Switch to other body + pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); + if (pcActiveBody != NULL) + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", + pcActiveBody->getNameInDocument()); + else + return; + } + + std::vector beforeFeatures = PartDesignGui::ActiveAppDoc->getObjects(); + + openCommand("Duplicate a PartDesign object"); + doCommand(Doc,"FreeCADGui.runCommand('Std_DuplicateSelection')"); + + // Find the features that were added + std::vector afterFeatures = PartDesignGui::ActiveAppDoc->getObjects(); + std::vector newFeatures; + std::set_difference(afterFeatures.begin(), afterFeatures.end(), beforeFeatures.begin(), beforeFeatures.end(), + std::back_inserter(newFeatures)); + + for (std::vector::const_iterator f = newFeatures.begin(); f != newFeatures.end(); f++) { + if (PartDesign::Body::isAllowed(*f)) { + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); + } + } + + // Adjust visibility of features + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); +} + +bool CmdPartDesignDuplicateSelection::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // PartDesign_Datum //=========================================================================== @@ -1524,17 +1596,24 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignBody()); rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); + + rcCmdMgr.addCommand(new CmdPartDesignDuplicateSelection()); + rcCmdMgr.addCommand(new CmdPartDesignPlane()); rcCmdMgr.addCommand(new CmdPartDesignLine()); rcCmdMgr.addCommand(new CmdPartDesignPoint()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); rcCmdMgr.addCommand(new CmdPartDesignGroove()); + rcCmdMgr.addCommand(new CmdPartDesignFillet()); rcCmdMgr.addCommand(new CmdPartDesignDraft()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); + rcCmdMgr.addCommand(new CmdPartDesignMirrored()); rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index d0daf7219f8f..b850295939e1 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -256,6 +256,21 @@ void Workbench::slotDeleteDocument(const App::Document&) ActiveAppDoc = 0; ActiveVp = 0; } +/* + This does not work for Std_DuplicateSelection: + Tree.cpp gives: "Cannot reparent unknown object", probably because the signalNewObject is emitted + before the duplication of the object has been completely finished + +void Workbench::slotNewObject(const App::DocumentObject& obj) +{ + if ((obj.getDocument() == ActiveAppDoc) && (ActivePartObject != NULL)) { + // Add the new object to the active Body + // Note: Will this break Undo? But how else can we catch Edit->Duplicate selection? + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + ActivePartObject->getNameInDocument(), obj.getNameInDocument()); + } +} +*/ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) const { @@ -437,6 +452,8 @@ void Workbench::activated() App::GetApplication().signalNewDocument.connect(boost::bind(&Workbench::slotNewDocument, this, _1)); App::GetApplication().signalFinishRestoreDocument.connect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); App::GetApplication().signalDeleteDocument.connect(boost::bind(&Workbench::slotDeleteDocument, this, _1)); + // Watch out for objects being added to the active document, so that we can add them to the body + //App::GetApplication().signalNewObject.connect(boost::bind(&Workbench::slotNewObject, this, _1)); } void Workbench::deactivated() @@ -446,6 +463,7 @@ void Workbench::deactivated() App::GetApplication().signalNewDocument.disconnect(boost::bind(&Workbench::slotNewDocument, this, _1)); App::GetApplication().signalFinishRestoreDocument.disconnect(boost::bind(&Workbench::slotFinishRestoreDocument, this, _1)); App::GetApplication().signalDeleteDocument.disconnect(boost::bind(&Workbench::slotDeleteDocument, this, _1)); + //App::GetApplication().signalNewObject.disconnect(boost::bind(&Workbench::slotNewObject, this, _1)); removeTaskWatcher(); // reset the active Body @@ -513,6 +531,11 @@ Gui::MenuItem* Workbench::setupMenuBar() const *part << "Separator" << "PartDesign_WizardShaft"; } + // Replace the "Duplicate selection" menu item with a replacement that is compatible with Body + item = root->findItem("&Edit"); + Gui::MenuItem* dup = item->findItem("Std_DuplicateSelection"); + dup->setCommand("PartDesign_DuplicateSelection"); + return root; } diff --git a/src/Mod/PartDesign/Gui/Workbench.h b/src/Mod/PartDesign/Gui/Workbench.h index 3c1af1f862f7..bfaf790113c8 100644 --- a/src/Mod/PartDesign/Gui/Workbench.h +++ b/src/Mod/PartDesign/Gui/Workbench.h @@ -86,6 +86,8 @@ class PartDesignGuiExport Workbench : public Gui::StdWorkbench void slotNewDocument(const App::Document&); /// Update the ActivePartObject etc. when a document is closed void slotDeleteDocument(const App::Document&); + // Add new objects to the body, if appropriate + //void slotNewObject(const App::DocumentObject& obj); }; } // namespace PartDesignGui From d8462d135b02406dfadf9804f589c76c688cd3f6 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 16 May 2013 14:46:49 +0430 Subject: [PATCH 115/664] Miscellaneous fixes --- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 27 ++++++++++--------- src/Mod/PartDesign/App/FeatureSketchBased.h | 4 --- src/Mod/PartDesign/Gui/Command.cpp | 2 ++ 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index e3689dc92b29..c4ecd6bb9758 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -120,11 +120,16 @@ void SketchBased::positionBySketch(void) { Part::Part2DObject *sketch = static_cast(Sketch.getValue()); if (sketch && sketch->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - Part::Feature *part = static_cast(sketch->Support.getValue()); - if (part && part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + App::DocumentObject* support = sketch->Support.getValue(); + if (support->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature *part = static_cast(support); this->Placement.setValue(part->Placement.getValue()); - else + } else if (support->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + App::Plane *plane = static_cast(support); + this->Placement.setValue(plane->Placement.getValue()); + } else { this->Placement.setValue(sketch->Placement.getValue()); + } } } @@ -212,20 +217,15 @@ const TopoDS_Face SketchBased::getSupportFace() const { return face; } -Part::Feature* SketchBased::getSupport() const { - // get the support of the Sketch if any +const TopoDS_Shape& SketchBased::getSupportShape() const { if (!Sketch.getValue()) - return 0; + throw Base::Exception("No Sketch!"); + App::DocumentObject* SupportLink = static_cast(Sketch.getValue())->Support.getValue(); Part::Feature* SupportObject = NULL; if (SupportLink && SupportLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) SupportObject = static_cast(SupportLink); - return SupportObject; -} - -const TopoDS_Shape& SketchBased::getSupportShape() const { - Part::Feature* SupportObject = getSupport(); if (SupportObject == NULL) throw Base::Exception("No support in Sketch!"); @@ -954,9 +954,12 @@ bool SketchBased::isParallelPlane(const TopoDS_Shape& s1, const TopoDS_Shape& s2 bool SketchBased::isSupportDatum() const { - Part::Feature* SupportObject = getSupport(); + if (!Sketch.getValue()) + return 0; + App::DocumentObject* SupportObject = static_cast(Sketch.getValue())->Support.getValue(); if (SupportObject == NULL) throw Base::Exception("No support in Sketch!"); + return isDatum(SupportObject); } diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 2a86eaa8d199..b28f18cc2be4 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -122,12 +122,8 @@ class PartDesignExport SketchBased : public PartDesign::Feature /// Check whether the line crosses the face (line and face must be on the same plane) static const bool checkLineCrossesFace(const gp_Lin& line, const TopoDS_Face& face); - -private: class Wire_Compare; - /// Returns the sketch support feature or NULL - Part::Feature* getSupport() const; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index d15448cb1d5f..bc8d339eaf71 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -183,6 +183,8 @@ void CmdPartDesignMoveTip::activated(int iMsg) if (pcActiveBody != NULL) Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", pcActiveBody->getNameInDocument()); + else + return; } App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); From 934c68faa50b0ad1a4800eb5132778361a3dbc10 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 16 May 2013 18:09:11 +0430 Subject: [PATCH 116/664] Draft: Accept datum lines and planes as references --- src/Mod/PartDesign/App/Feature.cpp | 9 +- src/Mod/PartDesign/App/Feature.h | 2 + src/Mod/PartDesign/App/FeatureDraft.cpp | 126 ++++++++++-------- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 29 ++++ src/Mod/PartDesign/Gui/ReferenceSelection.h | 6 + .../PartDesign/Gui/TaskDraftParameters.cpp | 88 +++++++----- src/Mod/PartDesign/Gui/TaskDraftParameters.h | 7 +- .../Gui/TaskTransformedParameters.cpp | 24 ---- .../Gui/TaskTransformedParameters.h | 7 +- 9 files changed, 175 insertions(+), 123 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index fe5c0ce07e75..2b56be6fb682 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -116,7 +116,7 @@ bool Feature::isDatum(const App::DocumentObject* feature) feature->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()); } -TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) +gp_Pln Feature::makePlnFromPlane(const App::DocumentObject* obj) { const App::Plane* plane = static_cast(obj); if (plane == NULL) @@ -125,7 +125,12 @@ TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) Base::Rotation rot = plane->Placement.getValue().getRotation(); Base::Vector3d normal(0,0,1); rot.multVec(normal, normal); - BRepBuilderAPI_MakeFace builder(gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z))); + return gp_Pln(gp_Pnt(0,0,0), gp_Dir(normal.x,normal.y,normal.z)); +} + +TopoDS_Shape Feature::makeShapeFromPlane(const App::DocumentObject* obj) +{ + BRepBuilderAPI_MakeFace builder(makePlnFromPlane(obj)); if (!builder.IsDone()) throw Base::Exception("Feature: Could not create shape from base plane"); diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index daa024c45be0..adba54e437f3 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -28,6 +28,7 @@ #include class gp_Pnt; +class gp_Pln; /// Base class of all additive features in PartDesign @@ -67,6 +68,7 @@ class PartDesignExport Feature : public Part::Feature /// Grab any point from the given face static const gp_Pnt getPointFromFace(const TopoDS_Face& f); /// Make a shape from a base plane (convenience method) + static gp_Pln makePlnFromPlane(const App::DocumentObject* obj); static TopoDS_Shape makeShapeFromPlane(const App::DocumentObject* obj); }; diff --git a/src/Mod/PartDesign/App/FeatureDraft.cpp b/src/Mod/PartDesign/App/FeatureDraft.cpp index eda4e4bf2efa..f3e8a686f41b 100644 --- a/src/Mod/PartDesign/App/FeatureDraft.cpp +++ b/src/Mod/PartDesign/App/FeatureDraft.cpp @@ -47,10 +47,13 @@ # include #endif +#include #include #include #include "FeatureDraft.h" +#include "DatumLine.h" +#include "DatumPlane.h" #include @@ -110,29 +113,35 @@ App::DocumentObjectExecReturn *Draft::execute(void) // Pull direction gp_Dir pullDirection; - App::DocumentObject* refDirection = PullDirection.getValue(); + App::DocumentObject* refDirection = PullDirection.getValue(); if (refDirection != NULL) { - if (!refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Pull direction reference must be an edge of a feature"); - std::vector subStrings = PullDirection.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) - throw Base::Exception("No pull direction reference specified"); - - Part::Feature* refFeature = static_cast(refDirection); - Part::TopoShape refShape = refFeature->Shape.getShape(); - TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); - - if (ref.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge refEdge = TopoDS::Edge(ref); - if (refEdge.IsNull()) - throw Base::Exception("Failed to extract pull direction reference edge"); - BRepAdaptor_Curve adapt(refEdge); - if (adapt.GetType() != GeomAbs_Line) - throw Base::Exception("Pull direction reference edge must be linear"); - - pullDirection = adapt.Line().Direction(); + if (refDirection->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + PartDesign::Line* line = static_cast(refDirection); + Base::Vector3d d = line->getDirection(); + pullDirection = gp_Dir(d.x, d.y, d.z); + } else if (refDirection->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + std::vector subStrings = PullDirection.getSubValues(); + if (subStrings.empty() || subStrings[0].empty()) + throw Base::Exception("No pull direction reference specified"); + + Part::Feature* refFeature = static_cast(refDirection); + Part::TopoShape refShape = refFeature->Shape.getShape(); + TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); + + if (ref.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge refEdge = TopoDS::Edge(ref); + if (refEdge.IsNull()) + throw Base::Exception("Failed to extract pull direction reference edge"); + BRepAdaptor_Curve adapt(refEdge); + if (adapt.GetType() != GeomAbs_Line) + throw Base::Exception("Pull direction reference edge must be linear"); + + pullDirection = adapt.Line().Direction(); + } else { + throw Base::Exception("Pull direction reference must be an edge or a datum line"); + } } else { - throw Base::Exception("Pull direction reference must be an edge"); + throw Base::Exception("Pull direction reference must be an edge of a feature or a datum line"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); @@ -188,43 +197,52 @@ App::DocumentObjectExecReturn *Draft::execute(void) if (!found) throw Base::Exception("No neutral plane specified and none can be guessed"); } else { - if (!refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - throw Base::Exception("Neutral plane reference must be face of a feature"); - std::vector subStrings = NeutralPlane.getSubValues(); - if (subStrings.empty() || subStrings[0].empty()) - throw Base::Exception("No neutral plane reference specified"); - - Part::Feature* refFeature = static_cast(refPlane); - Part::TopoShape refShape = refFeature->Shape.getShape(); - TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); - - if (ref.ShapeType() == TopAbs_FACE) { - TopoDS_Face refFace = TopoDS::Face(ref); - if (refFace.IsNull()) - throw Base::Exception("Failed to extract neutral plane reference face"); - BRepAdaptor_Surface adapt(refFace); - if (adapt.GetType() != GeomAbs_Plane) - throw Base::Exception("Neutral plane reference face must be planar"); - - neutralPlane = adapt.Plane(); - } else if (ref.ShapeType() == TopAbs_EDGE) { - if (refDirection != NULL) { - // Create neutral plane through edge normal to pull direction - TopoDS_Edge refEdge = TopoDS::Edge(ref); - if (refEdge.IsNull()) - throw Base::Exception("Failed to extract neutral plane reference edge"); - BRepAdaptor_Curve c(refEdge); + if (refPlane->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* plane = static_cast(refPlane); + Base::Vector3d b = plane->getBasePoint(); + Base::Vector3d n = plane->getNormal(); + neutralPlane = gp_Pln(gp_Pnt(b.x, b.y, b.z), gp_Dir(n.x, n.y, n.z)); + } else if (refPlane->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + neutralPlane = Feature::makePlnFromPlane(refPlane); + } else if (refPlane->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + std::vector subStrings = NeutralPlane.getSubValues(); + if (subStrings.empty() || subStrings[0].empty()) + throw Base::Exception("No neutral plane reference specified"); + + Part::Feature* refFeature = static_cast(refPlane); + Part::TopoShape refShape = refFeature->Shape.getShape(); + TopoDS_Shape ref = refShape.getSubShape(subStrings[0].c_str()); + + if (ref.ShapeType() == TopAbs_FACE) { + TopoDS_Face refFace = TopoDS::Face(ref); + if (refFace.IsNull()) + throw Base::Exception("Failed to extract neutral plane reference face"); + BRepAdaptor_Surface adapt(refFace); + if (adapt.GetType() != GeomAbs_Plane) + throw Base::Exception("Neutral plane reference face must be planar"); + + neutralPlane = adapt.Plane(); + } else if (ref.ShapeType() == TopAbs_EDGE) { + if (refDirection != NULL) { + // Create neutral plane through edge normal to pull direction + TopoDS_Edge refEdge = TopoDS::Edge(ref); + if (refEdge.IsNull()) + throw Base::Exception("Failed to extract neutral plane reference edge"); + BRepAdaptor_Curve c(refEdge); if (c.GetType() != GeomAbs_Line) - throw Base::Exception("Neutral plane reference edge must be linear"); - double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection)); - if (std::fabs(a - M_PI_2) > Precision::Confusion()) - throw Base::Exception("Neutral plane reference edge must be normal to pull direction"); - neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection); + throw Base::Exception("Neutral plane reference edge must be linear"); + double a = c.Line().Angle(gp_Lin(c.Value(c.FirstParameter()), pullDirection)); + if (std::fabs(a - M_PI_2) > Precision::Confusion()) + throw Base::Exception("Neutral plane reference edge must be normal to pull direction"); + neutralPlane = gp_Pln(c.Value(c.FirstParameter()), pullDirection); + } else { + throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined"); + } } else { - throw Base::Exception("Neutral plane reference can only be an edge if pull direction is defined"); + throw Base::Exception("Neutral plane reference must be a face"); } } else { - throw Base::Exception("Neutral plane reference must be a face"); + throw Base::Exception("Neutral plane reference must be face of a feature or a datum plane"); } TopLoc_Location invObjLoc = this->getLocation().Inverted(); diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index eb33af112a88..ef943f7629d4 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -111,3 +112,31 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } return false; } + +namespace PartDesignGui +{ + +const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub) +{ + if (obj == NULL) + return QString::fromAscii(""); + + if (PartDesign::Feature::isDatum(obj)) + return QString::fromAscii(obj->getNameInDocument()); + else + return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + + QString::fromAscii(sub.front().c_str()); +} + +const std::string getPythonStr(const App::DocumentObject* obj, const std::vector& sub) +{ + if (obj == NULL) + return ""; + + if (PartDesign::Feature::isDatum(obj)) + return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])"; + else + return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])"; +} + +} diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index efdf6242290f..0055d65fad20 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -47,6 +47,12 @@ class ReferenceSelection : public Gui::SelectionFilterGate bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName); }; +// Convenience methods +/// Return reference as string for UI elements (format : +const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub); +/// Return reference as string for python (format (, [""]) ) +const std::string getPythonStr(const App::DocumentObject* obj, const std::vector& sub); + } //namespace PartDesignGui #endif // GUI_ReferenceSelection_H diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index de55ef33221a..c220b4683a98 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -101,13 +101,30 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p connect(action, SIGNAL(triggered()), this, SLOT(onFaceDeleted())); ui->listWidgetFaces->setContextMenuPolicy(Qt::ActionsContextMenu); + App::DocumentObject* ref = pcDraft->NeutralPlane.getValue(); strings = pcDraft->NeutralPlane.getSubValues(); - std::string neutralPlane = (strings.empty() ? "" : strings[0]); - ui->linePlane->setText(QString::fromStdString(neutralPlane)); + ui->linePlane->setText(getRefStr(ref, strings)); + ref = pcDraft->PullDirection.getValue(); strings = pcDraft->PullDirection.getSubValues(); - std::string pullDirection = (strings.empty() ? "" : strings[0]); - ui->lineLine->setText(QString::fromStdString(pullDirection)); + ui->lineLine->setText(getRefStr(ref, strings)); +} + +void TaskDraftParameters::getReferencedSelection(const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub) +{ + PartDesign::DressUp* pcDressup = static_cast(DraftView->getObject()); + selObj = pcDressup->getDocument()->getObject(msg.pObjectName); + if (selObj == pcDressup) + return; + std::string subname = msg.pSubName; + + // Remove subname for planes and datum features + if (PartDesign::Feature::isDatum(selObj)) { + subname = ""; + } + + selSub = std::vector(1,subname); } void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -162,27 +179,22 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) ui->buttonFaceRemove->setChecked(false); exitSelectionMode(); } - } else if ((selectionMode == plane) && (subName.size() > 4) && - ((subName.substr(0,4) == "Face") || (subName.substr(0,4) == "Edge"))) { - - if (strcmp(msg.pObjectName, fname) != 0) - return; - - std::vector planes(1,subName); - pcDraft->NeutralPlane.setValue(base, planes); - ui->linePlane->setText(QString::fromStdString(subName)); + } else if ((selectionMode == plane)) { + std::vector planes; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, planes); + pcDraft->NeutralPlane.setValue(selObj, planes); + ui->linePlane->setText(getRefStr(selObj, planes)); pcDraft->getDocument()->recomputeFeature(pcDraft); ui->buttonPlane->setChecked(false); exitSelectionMode(); } else if ((selectionMode == line) && (subName.size() > 4 && subName.substr(0,4) == "Edge")) { - - if (strcmp(msg.pObjectName, fname) != 0) - return; - - std::vector edges(1,subName); - pcDraft->PullDirection.setValue(base, edges); - ui->lineLine->setText(QString::fromStdString(subName)); + std::vector edges; + App::DocumentObject* selObj; + getReferencedSelection(msg, selObj, edges); + pcDraft->PullDirection.setValue(selObj, edges); + ui->lineLine->setText(getRefStr(selObj, edges)); pcDraft->getDocument()->recomputeFeature(pcDraft); ui->buttonLine->setChecked(false); @@ -258,14 +270,22 @@ void TaskDraftParameters::onFaceDeleted(void) pcDraft->getDocument()->recomputeFeature(pcDraft); } -const std::string TaskDraftParameters::getPlane(void) const +void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector& sub) const { - return ui->linePlane->text().toStdString(); + sub = std::vector(1,""); + QStringList parts = ui->linePlane->text().split(QChar::fromAscii(':')); + obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); } -const std::string TaskDraftParameters::getLine(void) const +void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector& sub) const { - return ui->lineLine->text().toStdString(); + sub = std::vector(1,""); + QStringList parts = ui->lineLine->text().split(QChar::fromAscii(':')); + obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); } void TaskDraftParameters::hideObject() @@ -379,7 +399,11 @@ bool TaskDlgDraftParameters::accept() parameter->showObject(); // Force the user to select a neutral plane - if (parameter->getPlane().empty()) { + std::vector strings; + App::DocumentObject* obj; + parameter->getPlane(obj, strings); + std::string neutralPlane = getPythonStr(obj, strings); + if (neutralPlane.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"), QObject::tr("Please select a plane or an edge plus a pull direction")); return false; @@ -403,20 +427,14 @@ bool TaskDlgDraftParameters::accept() QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); return false; } - std::string neutralPlane = parameter->getPlane(); if (!neutralPlane.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromUtf8(parameter->getBase()->getNameInDocument())); - buf = buf.arg(QString::fromUtf8(neutralPlane.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), buf.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), neutralPlane.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = None", name.c_str()); - std::string pullDirection = parameter->getLine(); + parameter->getLine(obj, strings); + std::string pullDirection = getPythonStr(obj, strings); if (!pullDirection.empty()) { - QString buf = QString::fromUtf8("(App.ActiveDocument.%1,[\"%2\"])"); - buf = buf.arg(QString::fromUtf8(parameter->getBase()->getNameInDocument())); - buf = buf.arg(QString::fromUtf8(pullDirection.c_str())); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), buf.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), pullDirection.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.h b/src/Mod/PartDesign/Gui/TaskDraftParameters.h index 7a19fef51fce..3d93f389e96d 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.h @@ -54,8 +54,8 @@ class TaskDraftParameters : public Gui::TaskView::TaskBox, public Gui::Selection const double getAngle(void) const; const bool getReversed(void) const; const std::vector getFaces(void) const; - const std::string getPlane(void) const; - const std::string getLine(void) const; + void getPlane(App::DocumentObject*& obj, std::vector& sub) const; + void getLine(App::DocumentObject*& obj, std::vector& sub) const; App::DocumentObject *getBase(void) const; void hideObject(); @@ -84,6 +84,9 @@ private Q_SLOTS: enum selectionModes { none, faceAdd, faceRemove, plane, line }; selectionModes selectionMode; + + void getReferencedSelection(const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub); }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index ce5f7f5a818b..1c80e5ff1c3f 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -245,30 +245,6 @@ void TaskTransformedParameters::getReferencedSelection(const Gui::SelectionChang selSub = std::vector(1,subname); } -const QString TaskTransformedParameters::getRefStr(const App::DocumentObject* obj, const std::vector& sub) -{ - if (obj == NULL) - return QString::fromAscii(""); - - if (PartDesign::Feature::isDatum(obj)) - return QString::fromAscii(obj->getNameInDocument()); - else - return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + - QString::fromAscii(sub.front().c_str()); -} - -const std::string TaskTransformedParameters::getPythonStr(const App::DocumentObject* obj, const std::vector& sub) -{ - if (obj == NULL) - return ""; - - if (PartDesign::Feature::isDatum(obj)) - return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"\"])"; - else - return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])"; -} - - //************************************************************************** //************************************************************************** // TaskDialog diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index 30209268ad91..ebcb0d47d1c2 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -62,10 +62,7 @@ class TaskTransformedParameters : public Gui::TaskView::TaskBox, public Gui::Sel /// Get the support object either of the object associated with this feature or with the parent feature (MultiTransform mode) App::DocumentObject* getSupportObject() const; /// Get the sketch object of the first original either of the object associated with this feature or with the parent feature (MultiTransform mode) - App::DocumentObject* getSketchObject() const; - - /// Return reference as string for python (format (, [""]) ) - const std::string getPythonStr(const App::DocumentObject* selObj, const std::vector& selSub); + App::DocumentObject* getSketchObject() const; void exitSelectionMode(); @@ -93,8 +90,6 @@ protected Q_SLOTS: /// Extract reference from Selection (convenience method) void getReferencedSelection(const Gui::SelectionChanges& msg, App::DocumentObject*& selObj, std::vector& selSub); - /// Return reference as string for UI elements (format : - const QString getRefStr(const App::DocumentObject* selObj, const std::vector& selSub); bool isViewUpdated() const; int getUpdateViewTimeout() const; From c751eefc00b9bd091f68c27e8613cf09d14bc72a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 16 May 2013 18:09:42 +0430 Subject: [PATCH 117/664] Miscellaneous fixes --- src/Mod/PartDesign/Gui/Command.cpp | 8 +++++++- src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp | 1 + src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp | 3 ++- src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index bc8d339eaf71..2ec6fb6b3287 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -1049,6 +1049,12 @@ void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) Part::Feature *base = static_cast(selection[0].getObject()); + if (base != pcActiveBody->getPrevSolidFeature(NULL, true)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), + QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); + return; + } + const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -1244,7 +1250,7 @@ void CmdPartDesignDraft::activated(int iMsg) Part::Feature *base = static_cast(selection[0].getObject()); - if (base != pcActiveBody->Tip.getValue()) { + if (base != pcActiveBody->getPrevSolidFeature(NULL, true)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); return; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index c84f865597ae..6c1bcffaf1e7 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -32,6 +32,7 @@ #include "TaskLinearPatternParameters.h" #include "TaskMultiTransformParameters.h" #include "Workbench.h" +#include "ReferenceSelection.h" #include #include #include diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index a1da163966fe..1c761560f2dc 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -31,6 +31,7 @@ #include "TaskMirroredParameters.h" #include "TaskMultiTransformParameters.h" #include "Workbench.h" +#include "ReferenceSelection.h" #include #include #include @@ -366,7 +367,7 @@ bool TaskDlgMirroredParameters::accept() std::vector mirrorPlanes; App::DocumentObject* obj; mirrorParameter->getMirrorPlane(obj, mirrorPlanes); - std::string mirrorPlane = mirrorParameter->getPythonStr(obj, mirrorPlanes); + std::string mirrorPlane = getPythonStr(obj, mirrorPlanes); if (!mirrorPlane.empty()) { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = %s", name.c_str(), mirrorPlane.c_str()); } else diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index 967fb4567afe..eb3014a9a4e9 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -32,6 +32,7 @@ #include "TaskPolarPatternParameters.h" #include "TaskMultiTransformParameters.h" #include "Workbench.h" +#include "ReferenceSelection.h" #include #include #include From b18958b3d960737e126b38766cad70934cd4a40b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 17 May 2013 20:14:00 +0430 Subject: [PATCH 118/664] Miscellaneous fixes --- src/Mod/PartDesign/App/FeaturePad.cpp | 6 +++--- src/Mod/PartDesign/App/FeaturePocket.cpp | 6 +++--- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 2 ++ src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 2 +- src/Mod/PartDesign/Gui/TaskPocketParameters.cpp | 2 +- src/Mod/PartDesign/Gui/ViewProvider.cpp | 8 ++++---- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 9859c9726db7..c57ebd17441a 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -140,10 +140,10 @@ App::DocumentObjectExecReturn *Pad::execute(void) Base::Vector3d SketchVector(0,0,1); SketchOrientation.multVec(SketchVector,SketchVector); - this->positionBySketch(); - TopLoc_Location invObjLoc = this->getLocation().Inverted(); - try { + this->positionBySketch(); + TopLoc_Location invObjLoc = this->getLocation().Inverted(); + base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index e57e7aa442b4..000f4ac9dcf8 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -118,10 +118,10 @@ App::DocumentObjectExecReturn *Pocket::execute(void) // turn around for pockets SketchVector *= -1; - this->positionBySketch(); - TopLoc_Location invObjLoc = this->getLocation().Inverted(); - try { + this->positionBySketch(); + TopLoc_Location invObjLoc = this->getLocation().Inverted(); + base.Move(invObjLoc); gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index c4ecd6bb9758..57fb6b4d327e 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -121,6 +121,8 @@ void SketchBased::positionBySketch(void) Part::Part2DObject *sketch = static_cast(Sketch.getValue()); if (sketch && sketch->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { App::DocumentObject* support = sketch->Support.getValue(); + if (support == NULL) + throw Base::Exception("Sketch with NULL support"); if (support->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Part::Feature *part = static_cast(support); this->Placement.setValue(part->Placement.getValue()); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 2164d7ba41e2..2d5e503eb4b1 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -334,7 +334,7 @@ int TaskPadParameters::getMode(void) const QByteArray TaskPadParameters::getFaceName(void) const { - if ((getMode() >= 1) && (getMode() <= 3)) + if (getMode() == 3) return getFaceReference(ui->lineFaceName->text(), ui->lineFaceName->property("FaceName").toString()).toLatin1(); else return ""; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 1eac9291f779..77b243681830 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -314,7 +314,7 @@ int TaskPocketParameters::getMode(void) const QByteArray TaskPocketParameters::getFaceName(void) const { - if ((getMode() >= 1) && (getMode() <= 3)) + if (getMode() == 3) return getFaceReference(ui->lineFaceName->text(), ui->lineFaceName->property("FaceName").toString()).toLatin1(); else return ""; diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 83d92ef1a6af..6249768fbae7 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -50,10 +50,7 @@ ViewProvider::~ViewProvider() } bool ViewProvider::doubleClicked(void) -{ - std::string Msg("Edit "); - Msg += this->pcObject->Label.getValue(); - Gui::Command::openCommand(Msg.c_str()); +{ if (PartDesignGui::ActivePartObject != NULL) { // Drop into insert mode so that the user doesn't see all the geometry that comes later in the tree // Also, this way the user won't be tempted to use future geometry as external references for the sketch @@ -67,6 +64,9 @@ bool ViewProvider::doubleClicked(void) } try { + std::string Msg("Edit "); + Msg += this->pcObject->Label.getValue(); + Gui::Command::openCommand(Msg.c_str()); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().setEdit('%s',0)",this->pcObject->getNameInDocument()); } catch (const Base::Exception&) { From ed2657380c2437742aee92ef4f3d2478cba85b27 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 18 May 2013 08:47:20 +0430 Subject: [PATCH 119/664] Fix bug that produced 'cannot update representation' error message on adding a fillet --- src/Mod/PartDesign/App/Body.cpp | 5 +++++ src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index c95718381068..a31379f3a86c 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -333,6 +333,11 @@ Base::BoundBox3d Body::getBoundBox() Base::BoundBox3d result; Part::Feature* tipSolid = static_cast(getPrevSolidFeature()); + TopoDS_Shape sh = tipSolid->Shape.getValue(); + if (sh.IsNull()) + // This can happen when a new feature is added without having its Shape property set yet + tipSolid = static_cast(getPrevSolidFeature(NULL, false)); + if (tipSolid != NULL) { result = tipSolid->Shape.getShape().getBoundBox(); } else { diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index 6f855c37c1e2..d8fbec81fcba 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -90,6 +90,8 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) Base::BoundBox3d bbox = body->getBoundBox(); bbox = bbox.Transformed(plm.toMatrix()); double dlength = bbox.CalcDiagonalLength(); + if (dlength < Precision::Confusion()) + return; bbox.Enlarge(0.1 * dlength); // Calculate intersection of plane with bounding box edges From 638cfd26829be2a19f85e496cb29569f9afe3397 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 22 May 2013 20:47:31 +0430 Subject: [PATCH 120/664] Allow booleans of bodies in PartDesign --- src/Mod/PartDesign/App/AppPartDesign.cpp | 2 + src/Mod/PartDesign/App/CMakeLists.txt | 2 + src/Mod/PartDesign/App/FeatureBoolean.cpp | 133 +++++++ src/Mod/PartDesign/App/FeatureBoolean.h | 69 ++++ src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 2 + src/Mod/PartDesign/Gui/CMakeLists.txt | 7 + src/Mod/PartDesign/Gui/Command.cpp | 63 ++++ .../PartDesign/Gui/TaskBooleanParameters.cpp | 355 ++++++++++++++++++ .../PartDesign/Gui/TaskBooleanParameters.h | 118 ++++++ .../PartDesign/Gui/TaskBooleanParameters.ui | 72 ++++ .../PartDesign/Gui/ViewProviderBoolean.cpp | 124 ++++++ src/Mod/PartDesign/Gui/ViewProviderBoolean.h | 56 +++ src/Mod/PartDesign/Gui/Workbench.cpp | 19 +- 13 files changed, 1020 insertions(+), 2 deletions(-) create mode 100644 src/Mod/PartDesign/App/FeatureBoolean.cpp create mode 100644 src/Mod/PartDesign/App/FeatureBoolean.h create mode 100644 src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskBooleanParameters.h create mode 100644 src/Mod/PartDesign/Gui/TaskBooleanParameters.ui create mode 100644 src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderBoolean.h diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index 55e52e5ec656..c352fb03045f 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -52,6 +52,7 @@ #include "DatumPlane.h" #include "DatumLine.h" #include "DatumPoint.h" +#include "FeatureBoolean.h" namespace PartDesign { extern PyObject* initModule(); @@ -102,6 +103,7 @@ PyMODINIT_FUNC init_PartDesign() PartDesign::Plane ::init(); PartDesign::Line ::init(); PartDesign::Point ::init(); + PartDesign::Boolean ::init(); PartDesign::Point::initHints(); PartDesign::Line ::initHints(); diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 77d3cb68aa10..d7201d894dae 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -94,6 +94,8 @@ SET(FeaturesSketchBased_SRCS FeatureSubtractive.cpp FeatureHole.h FeatureHole.cpp + FeatureBoolean.h + FeatureBoolean.cpp ) SOURCE_GROUP("SketchBasedFeatures" FILES ${FeaturesSketchBased_SRCS}) diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp new file mode 100644 index 000000000000..73a5a633b82a --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp @@ -0,0 +1,133 @@ +/****************************************************************************** + * Copyright (c)2013 Jan Rheinlaender * + * * + * 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 +# include +# include +# include +#endif + +#include "Body.h" +#include "FeatureBoolean.h" + +#include +#include + +using namespace PartDesign; + +namespace PartDesign { + +PROPERTY_SOURCE(PartDesign::Boolean, PartDesign::Feature) + +const char* Boolean::TypeEnums[]= {"Fuse","Cut","Common","Section",NULL}; + +Boolean::Boolean() +{ + ADD_PROPERTY(Type,((long)0)); + Type.setEnums(TypeEnums); + ADD_PROPERTY(Bodies,(0)); + Bodies.setSize(0); +} + +short Boolean::mustExecute() const +{ + if (Bodies.isTouched()) + return 1; + return PartDesign::Feature::mustExecute(); +} + +App::DocumentObjectExecReturn *Boolean::execute(void) +{ + std::vector bodies = Bodies.getValues(); + if (bodies.empty()) + return App::DocumentObject::StdReturn; + + // Get the first body + if (bodies.front() == NULL) + return new App::DocumentObjectExecReturn("No body for boolean"); + PartDesign::Body* body = static_cast(bodies.front()); + const Part::TopoShape& bodyTopShape = body->Shape.getShape(); + if (bodyTopShape._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Cannot do boolean operation on invalid body shape"); + + // create an untransformed copy of the body shape + Part::TopoShape bodyShape(bodyTopShape); + bodyShape.setTransform(Base::Matrix4D()); + TopoDS_Shape result = bodyShape._Shape; + + // Position this feature by the first body + this->Placement.setValue(body->Placement.getValue()); + + // Get the operation type + std::string type = Type.getValueAsString(); + + std::vector::const_iterator b = bodies.begin(); + b++; + + for (; b != bodies.end(); b++) + { + // Extract the body shape + PartDesign::Body* body = static_cast(*b); + TopoDS_Shape shape = body->Shape.getValue(); + TopoDS_Shape boolOp; + + if (type == "Fuse") { + BRepAlgoAPI_Fuse mkFuse(result, shape); + if (!mkFuse.IsDone()) + return new App::DocumentObjectExecReturn("Fusion of bodies failed", *b); + // we have to get the solids (fuse sometimes creates compounds) + boolOp = this->getSolid(mkFuse.Shape()); + // lets check if the result is a solid + if (boolOp.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *b); + } else if (type == "Cut") { + BRepAlgoAPI_Cut mkCut(result, shape); + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Cut out of first body failed", *b); + boolOp = mkCut.Shape(); + } else if (type == "Common") { + BRepAlgoAPI_Common mkCommon(result, shape); + if (!mkCommon.IsDone()) + return new App::DocumentObjectExecReturn("Common operation with first body failed", *b); + boolOp = mkCommon.Shape(); + } else if (type == "Section") { + BRepAlgoAPI_Section mkSection(result, shape); + if (!mkSection.IsDone()) + return new App::DocumentObjectExecReturn("Section out of first body failed", *b); + // we have to get the solids + boolOp = this->getSolid(mkSection.Shape()); + // lets check if the result is a solid + if (boolOp.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is not a solid", *b); + } + + result = boolOp; // Use result of this operation for fuse/cut of next body + } + + this->Shape.setValue(result); + return App::DocumentObject::StdReturn; +} + +} diff --git a/src/Mod/PartDesign/App/FeatureBoolean.h b/src/Mod/PartDesign/App/FeatureBoolean.h new file mode 100644 index 000000000000..f6b937cfad86 --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureBoolean.h @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c)2013 Jan Rheinlaender * + * * + * 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 PARTDESIGN_FeatureBoolean_H +#define PARTDESIGN_FeatureBoolean_H + +#include +#include "Feature.h" + + +namespace PartDesign +{ + +/** + * Abstract superclass of all features that are created by transformation of another feature + * Transformations are translation, rotation and mirroring + */ +class PartDesignExport Boolean : public PartDesign::Feature +{ + PROPERTY_HEADER(PartDesign::Boolean); + +public: + Boolean(); + + /// The type of the boolean operation + App::PropertyEnumeration Type; + /// The bodies for the operation + App::PropertyLinkList Bodies; + + /** @name methods override feature */ + //@{ + /// Recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + /// returns the type name of the view provider + const char* getViewProviderName(void) const { + return "PartDesignGui::ViewProviderBoolean"; + } + //@} + +private: + static const char* TypeEnums[]; + +}; + +} //namespace PartDesign + + +#endif // PARTDESIGN_FeatureBoolean_H diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index 47b6930d3ea6..ac2ec7f27563 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -51,6 +51,7 @@ #include "ViewProviderDatumPoint.h" #include "ViewProviderDatumLine.h" #include "ViewProviderDatumPlane.h" +#include "ViewProviderBoolean.h" // use a different name to CreateCommand() void CreatePartDesignCommands(void); @@ -126,6 +127,7 @@ PyMODINIT_FUNC initPartDesignGui() PartDesignGui::ViewProviderDatumPoint ::init(); PartDesignGui::ViewProviderDatumLine ::init(); PartDesignGui::ViewProviderDatumPlane ::init(); + PartDesignGui::ViewProviderBoolean ::init(); // add resources and reloads the translators loadPartDesignResource(); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index b0e60d69bb1e..7fa5810d6a38 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -46,6 +46,7 @@ set(PartDesignGui_MOC_HDRS TaskScaledParameters.h TaskMultiTransformParameters.h TaskDatumParameters.h + TaskBooleanParameters.h ) fc_wrap_cpp(PartDesignGui_MOC_SRCS ${PartDesignGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartDesignGui_MOC_SRCS}) @@ -59,6 +60,7 @@ set(PartDesignGui_UIC_SRCS TaskChamferParameters.ui TaskFilletParameters.ui TaskDraftParameters.ui + TaskBooleanParameters.ui TaskHoleParameters.ui TaskRevolutionParameters.ui TaskGrooveParameters.ui @@ -113,6 +115,8 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderDatumLine.h ViewProviderDatumPlane.cpp ViewProviderDatumPlane.h + ViewProviderBoolean.cpp + ViewProviderBoolean.h ) SOURCE_GROUP("ViewProvider" FILES ${PartDesignGuiViewProvider_SRCS}) @@ -171,6 +175,9 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskDatumParameters.ui TaskDatumParameters.cpp TaskDatumParameters.h + TaskBooleanParameters.ui + TaskBooleanParameters.cpp + TaskBooleanParameters.h ) SOURCE_GROUP("TaskDialogs" FILES ${PartDesignGuiTaskDlgs_SRCS}) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 2ec6fb6b3287..f8145dfabb73 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -1593,6 +1594,66 @@ bool CmdPartDesignMultiTransform::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_Boolean +//=========================================================================== + +/* Boolean commands =======================================================*/ +DEF_STD_CMD_A(CmdPartDesignBoolean); + +CmdPartDesignBoolean::CmdPartDesignBoolean() + :Command("PartDesign_Boolean") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Boolean operation"); + sToolTipText = QT_TR_NOOP("Boolean operation with two or more boies"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Boolean"; +} + + +void CmdPartDesignBoolean::activated(int iMsg) +{ + Gui::SelectionFilter BodyFilter("SELECT PartDesign::Body COUNT 1.."); + std::string bodyString("["); + + if (BodyFilter.match()) { + std::vector bodies; + for (std::vector >::iterator i = BodyFilter.Result.begin(); + i != BodyFilter.Result.end(); i++) { + for (std::vector::iterator j = i->begin(); j != i->end(); j++) { + bodies.push_back(j->getObject()); + } + } + + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + bodyString += std::string("App.activeDocument().") + (*b)->getNameInDocument() + ","; + bodyString += "]"; + } else { + bodyString = ""; + } + + std::string FeatName = getUniqueObjectName("Boolean"); + + openCommand("Create Boolean"); + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Boolean','%s')",FeatName.c_str()); + if (!bodyString.empty()) + doCommand(Doc,"App.activeDocument().%s.Bodies = %s",FeatName.c_str(),bodyString.c_str()); + //doCommand(Gui,"App.activeDocument().recompute()"); + //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); +} + +bool CmdPartDesignBoolean::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // Initialization @@ -1627,4 +1688,6 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + + rcCmdMgr.addCommand(new CmdPartDesignBoolean()); } diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp new file mode 100644 index 000000000000..ee14dbf53e39 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp @@ -0,0 +1,355 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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 +#endif + +#include "ui_TaskBooleanParameters.h" +#include "TaskBooleanParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskBooleanParameters */ + +TaskBooleanParameters::TaskBooleanParameters(ViewProviderBoolean *BooleanView,QWidget *parent) + : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Boolean"),tr("Boolean parameters"),true, parent),BooleanView(BooleanView) +{ + selectionMode = none; + + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskBooleanParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->buttonBodyAdd, SIGNAL(toggled(bool)), + this, SLOT(onButtonBodyAdd(bool))); + connect(ui->buttonBodyRemove, SIGNAL(toggled(bool)), + this, SLOT(onButtonBodyRemove(bool))); + connect(ui->comboType, SIGNAL(currentIndexChanged(int)), + this, SLOT(onTypeChanged(int))); + + this->groupLayout()->addWidget(proxy); + + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + std::vector bodies = pcBoolean->Bodies.getValues(); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + { + ui->listWidgetBodies->insertItem(0, QString::fromAscii((*b)->getNameInDocument())); + } + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetBodies->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onBodyDeleted())); + ui->listWidgetBodies->setContextMenuPolicy(Qt::ActionsContextMenu); + + int index = pcBoolean->Type.getValue(); + ui->comboType->setCurrentIndex(index); +} + +void TaskBooleanParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == none) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (strcmp(msg.pDocName, BooleanView->getObject()->getDocument()->getName()) != 0) + return; + + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + std::string body(msg.pObjectName); + if (body.empty()) + return; + App::DocumentObject* pcBody = pcBoolean->getDocument()->getObject(body.c_str()); + if (pcBody == NULL) + return; + if (!pcBody->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { + pcBody = PartDesign::Body::findBodyOf(pcBody); + if (pcBody == NULL) + return; + } + + std::vector bodies = pcBoolean->Bodies.getValues(); + + if (selectionMode == bodyAdd) { + if (std::find(bodies.begin(), bodies.end(), pcBody) == bodies.end()) { + bodies.push_back(pcBody); + pcBoolean->Bodies.setValues(bodies); + ui->listWidgetBodies->insertItem(ui->listWidgetBodies->count(), + QString::fromStdString(pcBody->getNameInDocument())); + + pcBoolean->getDocument()->recomputeFeature(pcBoolean); + ui->buttonBodyAdd->setChecked(false); + exitSelectionMode(); + + // Hide the bodies if there are more than two + if (bodies.size() == 2) { + // Hide both bodies + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.front())); + if (vp != NULL) + vp->hide(); + vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.back())); + if (vp != NULL) + vp->hide(); + BooleanView->show(); + } else { + // Hide newly added body + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.back())); + if (vp != NULL) + vp->hide(); + } + } + } else if (selectionMode == bodyRemove) { + std::vector::iterator b = std::find(bodies.begin(), bodies.end(), pcBody); + if (b != bodies.end()) { + bodies.erase(b); + pcBoolean->Bodies.setValues(bodies); + QList items = ui->listWidgetBodies->findItems(QString::fromStdString(body), Qt::MatchExactly); + if (!items.empty()) { + for (QList::const_iterator i = items.begin(); i != items.end(); i++) { + QListWidgetItem* it = ui->listWidgetBodies->takeItem(ui->listWidgetBodies->row(*i)); + delete it; + } + } + pcBoolean->getDocument()->recomputeFeature(pcBoolean); + ui->buttonBodyRemove->setChecked(false); + exitSelectionMode(); + + // Make bodies visible again + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(*b)); + if (vp != NULL) + vp->show(); + if (bodies.size() == 1) { + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.front())); + if (vp != NULL) + vp->show(); + BooleanView->hide(); + } + } + } + } +} + +void TaskBooleanParameters::onButtonBodyAdd(bool checked) +{ + if (checked) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setHide(BooleanView->getObject()->getNameInDocument()); + selectionMode = bodyAdd; + Gui::Selection().clearSelection(); + } else { + exitSelectionMode(); + } +} + +void TaskBooleanParameters::onButtonBodyRemove(bool checked) +{ + if (checked) { + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setHide(BooleanView->getObject()->getNameInDocument()); + selectionMode = bodyRemove; + Gui::Selection().clearSelection(); + } else { + exitSelectionMode(); + } +} + +void TaskBooleanParameters::onTypeChanged(int index) +{ + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + + switch (index) { + case 0: pcBoolean->Type.setValue("Fuse"); break; + case 1: pcBoolean->Type.setValue("Cut"); break; + case 2: pcBoolean->Type.setValue("Common"); break; + case 3: pcBoolean->Type.setValue("Section"); break; + default: pcBoolean->Type.setValue("Fuse"); + } + + pcBoolean->getDocument()->recomputeFeature(pcBoolean); +} + +const std::vector TaskBooleanParameters::getBodies(void) const +{ + std::vector result; + for (int i = 0; i < ui->listWidgetBodies->count(); i++) + result.push_back(ui->listWidgetBodies->item(i)->text().toStdString()); + return result; +} + +int TaskBooleanParameters::getType(void) const +{ + return ui->comboType->currentIndex(); +} + +void TaskBooleanParameters::onBodyDeleted(void) +{ + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + std::vector bodies = pcBoolean->Bodies.getValues(); + int index = ui->listWidgetBodies->currentRow(); + if (index > bodies.size()) + return; + App::DocumentObject* body = bodies[index]; + bodies.erase(bodies.begin() + ui->listWidgetBodies->currentRow()); + pcBoolean->Bodies.setValues(bodies); + ui->listWidgetBodies->model()->removeRow(ui->listWidgetBodies->currentRow()); + pcBoolean->getDocument()->recomputeFeature(pcBoolean); + + // Make bodies visible again + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(body)); + if (vp != NULL) + vp->show(); + if (bodies.size() == 1) { + Gui::ViewProviderDocumentObject* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(bodies.front())); + if (vp != NULL) + vp->show(); + BooleanView->hide(); + } +} + +TaskBooleanParameters::~TaskBooleanParameters() +{ + delete ui; +} + +void TaskBooleanParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->comboType->blockSignals(true); + int index = ui->comboType->currentIndex(); + ui->retranslateUi(proxy); + ui->comboType->setCurrentIndex(index); + } +} + +void TaskBooleanParameters::exitSelectionMode() +{ + selectionMode = none; + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setShow(BooleanView->getObject()->getNameInDocument()); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgBooleanParameters::TaskDlgBooleanParameters(ViewProviderBoolean *BooleanView) + : TaskDialog(),BooleanView(BooleanView) +{ + assert(BooleanView); + parameter = new TaskBooleanParameters(BooleanView); + + Content.push_back(parameter); +} + +TaskDlgBooleanParameters::~TaskDlgBooleanParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgBooleanParameters::open() +{ + +} + +void TaskDlgBooleanParameters::clicked(int) +{ + +} + +bool TaskDlgBooleanParameters::accept() +{ + std::string name = BooleanView->getObject()->getNameInDocument(); + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) + doc->setShow(name.c_str()); + + try { + std::vector bodies = parameter->getBodies(); + std::stringstream str; + str << "App.ActiveDocument." << name.c_str() << ".Bodies = ["; + for (std::vector::const_iterator it = bodies.begin(); it != bodies.end(); ++it) + str << "App.ActiveDocument." << *it << ","; + str << "]"; + Gui::Command::doCommand(Gui::Command::Doc,str.str().c_str()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Boolean: Accept: Input error"), QString::fromAscii(e.what())); + return false; + } + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getType()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + + return true; +} + +bool TaskDlgBooleanParameters::reject() +{ + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + return true; +} + + + +#include "moc_TaskBooleanParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.h b/src/Mod/PartDesign/Gui/TaskBooleanParameters.h new file mode 100644 index 000000000000..6c64a9587177 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.h @@ -0,0 +1,118 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 GUI_TASKVIEW_TaskBooleanParameters_H +#define GUI_TASKVIEW_TaskBooleanParameters_H + +#include +#include +#include + +#include "ViewProviderBoolean.h" + +class Ui_TaskBooleanParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + + +namespace PartDesignGui { + +class TaskBooleanParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskBooleanParameters(ViewProviderBoolean *BooleanView, QWidget *parent=0); + ~TaskBooleanParameters(); + + const std::vector getBodies(void) const; + int getType(void) const; + +private Q_SLOTS: + void onButtonBodyAdd(const bool checked); + void onButtonBodyRemove(const bool checked); + void onBodyDeleted(void); + void onTypeChanged(int index); + +protected: + void exitSelectionMode(); + +protected: + void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +private: + QWidget* proxy; + Ui_TaskBooleanParameters* ui; + ViewProviderBoolean *BooleanView; + + enum selectionModes { none, bodyAdd, bodyRemove }; + selectionModes selectionMode; + +}; + +/// simulation dialog for the TaskView +class TaskDlgBooleanParameters : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgBooleanParameters(ViewProviderBoolean *BooleanView); + ~TaskDlgBooleanParameters(); + + ViewProviderBoolean* getBooleanView() const + { return BooleanView; } + + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderBoolean *BooleanView; + + TaskBooleanParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.ui b/src/Mod/PartDesign/Gui/TaskBooleanParameters.ui new file mode 100644 index 000000000000..8384eb9fda30 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.ui @@ -0,0 +1,72 @@ + + + PartDesignGui::TaskBooleanParameters + + + + 0 + 0 + 209 + 185 + + + + Form + + + + + + + + Add body + + + true + + + + + + + Remove body + + + true + + + + + + + + + + + + + Fuse + + + + + Cut + + + + + Common + + + + + Section + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp b/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp new file mode 100644 index 000000000000..ffeaa16e605d --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderBoolean.cpp @@ -0,0 +1,124 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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 +# include +# include +#endif + +#include "ViewProviderBoolean.h" +#include "TaskBooleanParameters.h" +#include +#include +#include +#include +#include + + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderBoolean,PartDesignGui::ViewProvider) + +ViewProviderBoolean::ViewProviderBoolean() +{ + sPixmap = "PartDesign_Boolean.svg"; +} + +ViewProviderBoolean::~ViewProviderBoolean() +{ +} + + +void ViewProviderBoolean::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit boolean"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderBoolean::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this fillet the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgBooleanParameters *booleanDlg = qobject_cast(dlg); + if (booleanDlg && booleanDlg->getBooleanView() != this) + booleanDlg = 0; // another pad left open its task panel + if (dlg && !booleanDlg) { + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + + // start the edit dialog + if (booleanDlg) + Gui::Control().showDialog(booleanDlg); + else + Gui::Control().showDialog(new TaskDlgBooleanParameters(this)); + + return true; + } + else { + return PartGui::ViewProviderPart::setEdit(ModNum); + } +} + +std::vector ViewProviderBoolean::claimChildren(void)const +{ + return static_cast(getObject())->Bodies.getValues(); +} + +bool ViewProviderBoolean::onDelete(const std::vector &s) +{ + PartDesign::Boolean* pcBoolean = static_cast(getObject()); + + // if abort command deleted the object the bodies are visible again + std::vector bodies = pcBoolean->Bodies.getValues(); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { + if (*b && Gui::Application::Instance->getViewProvider(*b)) + Gui::Application::Instance->getViewProvider(*b)->show(); + } + + return ViewProvider::onDelete(s); +} + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderBoolean.h b/src/Mod/PartDesign/Gui/ViewProviderBoolean.h new file mode 100644 index 000000000000..90de9700020f --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderBoolean.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (c) 2013 Jan Rheinländer * + * * + * 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_ViewProviderBoolean_H +#define PARTGUI_ViewProviderBoolean_H + +#include "ViewProvider.h" + + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderBoolean : public ViewProvider +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderBoolean); + +public: + /// constructor + ViewProviderBoolean(); + /// destructor + virtual ~ViewProviderBoolean(); + + /// grouping handling + void setupContextMenu(QMenu*, QObject*, const char*); + std::vector claimChildren(void)const; + + virtual bool onDelete(const std::vector &); + +protected: + virtual bool setEdit(int ModNum); + +}; + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderBoolean_H diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index b850295939e1..a4dc292934fe 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -342,6 +342,16 @@ void Workbench::activated() "Part_Box" )); + const char* Body2[] = { + "PartDesign_Boolean", + 0}; + Watcher.push_back(new Gui::TaskView::TaskWatcherCommands( + "SELECT PartDesign::Body COUNT 1..", + Body2, + "Start Boolean", + "Part_Box" + )); + const char* Plane1[] = { "PartDesign_NewSketch", "PartDesign_Plane", @@ -520,7 +530,10 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "PartDesign_LinearPattern" << "PartDesign_PolarPattern" // << "PartDesign_Scaled" - << "PartDesign_MultiTransform"; + << "PartDesign_MultiTransform" + << "Separator" + << "PartDesign_Boolean"; + // For 0.13 a couple of python packages like numpy, matplotlib and others // are not deployed with the installer on Windows. Thus, the WizardShaft is // not deployed either hence the check for the existence of the command. @@ -566,7 +579,9 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "PartDesign_LinearPattern" << "PartDesign_PolarPattern" // << "PartDesign_Scaled" - << "PartDesign_MultiTransform"; + << "PartDesign_MultiTransform" + << "Separator" + << "PartDesign_Boolean"; Gui::ToolBarItem* geom = new Gui::ToolBarItem(root); geom->setCommand("Sketcher geometries"); From c4fe27d0933f0a415a098508bf4921fff6fde636 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 22 May 2013 20:48:03 +0430 Subject: [PATCH 121/664] Miscellaneous fixes --- src/Mod/PartDesign/App/Body.cpp | 18 ++++++++++-------- src/Mod/PartDesign/App/Feature.cpp | 2 +- src/Mod/PartDesign/App/FeatureDressUp.cpp | 1 + 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index a31379f3a86c..8f7740750f92 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -333,16 +333,18 @@ Base::BoundBox3d Body::getBoundBox() Base::BoundBox3d result; Part::Feature* tipSolid = static_cast(getPrevSolidFeature()); - TopoDS_Shape sh = tipSolid->Shape.getValue(); - if (sh.IsNull()) - // This can happen when a new feature is added without having its Shape property set yet - tipSolid = static_cast(getPrevSolidFeature(NULL, false)); - if (tipSolid != NULL) { - result = tipSolid->Shape.getShape().getBoundBox(); - } else { - result = App::Plane::getBoundBox(); + TopoDS_Shape sh = tipSolid->Shape.getValue(); + if (sh.IsNull()) + // This can happen when a new feature is added without having its Shape property set yet + tipSolid = static_cast(getPrevSolidFeature(NULL, false)); + + if (tipSolid != NULL) { + result = tipSolid->Shape.getShape().getBoundBox(); + } } + if (tipSolid == NULL) + result = App::Plane::getBoundBox(); std::vector model = Model.getValues(); // TODO: In DatumLine and DatumPlane, recalculate the Base point to be as near as possible to the origin (0,0,0) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 2b56be6fb682..1e091b4abc20 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -52,7 +52,7 @@ PROPERTY_SOURCE(PartDesign::Feature,Part::Feature) Feature::Feature() { ADD_PROPERTY(BaseFeature,(0)); - + Placement.StatusBits.set(2, true); } short Feature::mustExecute() const diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp b/src/Mod/PartDesign/App/FeatureDressUp.cpp index b6f92218f583..8d8a42a64047 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.cpp +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp @@ -39,6 +39,7 @@ PROPERTY_SOURCE(PartDesign::DressUp, PartDesign::Feature) DressUp::DressUp() { ADD_PROPERTY(Base,(0)); + Placement.StatusBits.set(2, true); } short DressUp::mustExecute() const From 02ba800430efefead8fc50c4b001d2eda62eafd2 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 22 May 2013 20:50:22 +0430 Subject: [PATCH 122/664] Added a few preliminary icons for the new features --- .../PartDesign/Gui/Resources/PartDesign.qrc | 5 + .../Gui/Resources/icons/PartDesign_Body.svg | 0 .../Resources/icons/PartDesign_Boolean.svg | 151 +++++++++++++++ .../Gui/Resources/icons/PartDesign_Line.svg | 180 ++++++++++++++++++ .../Gui/Resources/icons/PartDesign_Plane.svg | 0 .../Gui/Resources/icons/PartDesign_Point.svg | 172 +++++++++++++++++ 6 files changed, 508 insertions(+) create mode 100644 src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg create mode 100644 src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Boolean.svg create mode 100644 src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Line.svg create mode 100644 src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg create mode 100644 src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Point.svg diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc index e3631515b78d..340e89dda532 100644 --- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc +++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc @@ -13,6 +13,11 @@ icons/PartDesign_Scaled.svg icons/PartDesign_MultiTransform.svg icons/PartDesign_Hole.svg + icons/PartDesign_Body.svg + icons/PartDesign_Boolean.svg + icons/PartDesign_Plane.svg + icons/PartDesign_Line.svg + icons/PartDesign_Point.svg icons/Tree_PartDesign_Pad.svg icons/Tree_PartDesign_Revolution.svg icons/PartDesign_InternalExternalGear.svg diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Boolean.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Boolean.svg new file mode 100644 index 000000000000..29c18fb50ccc --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Boolean.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Line.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Line.svg new file mode 100644 index 000000000000..bd71c8c6c067 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Line.svg @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Point.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Point.svg new file mode 100644 index 000000000000..1a0509b48326 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Point.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + From a8e4f0f1ca199197a08d1cb7d6b57193c97709b7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 23 May 2013 10:49:27 +0430 Subject: [PATCH 123/664] Allow Pad and Pocket up to a face with sketch located on datum plane --- src/Mod/PartDesign/App/FeaturePad.cpp | 6 +++++- src/Mod/PartDesign/App/FeaturePocket.cpp | 6 +++++- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 12 +++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index c57ebd17441a..6d6288ed5b9e 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -157,7 +157,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) TopoDS_Shape prism; std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { - // Note: This will throw an exception if the sketch is located on a datum plane + // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); @@ -180,6 +180,10 @@ App::DocumentObjectExecReturn *Pad::execute(void) // Note: Multiple independent wires are not supported, we should check for that and // warn the user // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results + // Check supportface for limits, otherwise Perform() throws an exception + TopExp_Explorer Ex(supportface,TopAbs_WIRE); + if (!Ex.More()) + supportface = TopoDS_Face(); BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); PrismMaker.Perform(upToFace); diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 000f4ac9dcf8..a06da743e8c1 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -134,7 +134,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void) std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToFace") { - // Note: This will throw an exception if the sketch is located on a datum plane + // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); @@ -151,6 +151,10 @@ App::DocumentObjectExecReturn *Pocket::execute(void) // Special treatment because often the created stand-alone prism is invalid (empty) because // BRepFeat_MakePrism(..., 2, 1) is buggy + // Check supportface for limits, otherwise Perform() throws an exception + TopExp_Explorer Ex(supportface,TopAbs_WIRE); + if (!Ex.More()) + supportface = TopoDS_Face(); BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, sketchshape, supportface, dir, 0, 1); PrismMaker.Perform(upToFace); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 57fb6b4d327e..7c81b5661a43 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -190,9 +190,15 @@ std::vector SketchBased::getSketchWires() const { const TopoDS_Face SketchBased::getSupportFace() const { const App::PropertyLinkSub& Support = static_cast(Sketch.getValue())->Support; App::DocumentObject* ref = Support.getValue(); - if (ref->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || - ref->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - throw Base::Exception("Sketch must be located on a face of a solid for this feature to work"); + + if (ref->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + TopoDS_Shape plane = Feature::makeShapeFromPlane(ref); + return TopoDS::Face(plane); + } else if (ref->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { + PartDesign::Plane* plane = static_cast(ref); + return TopoDS::Face(plane->getShape()); + } + Part::Feature *part = static_cast(Support.getValue()); if (!part || !part->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) throw Base::Exception("No support in sketch"); From 0e9ee59129ea22e8f07b414799ad6fda81cbc4d6 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 23 May 2013 17:29:40 +0430 Subject: [PATCH 124/664] Some code unification for Gui selections --- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 16 ++++++++++++++ src/Mod/PartDesign/Gui/ReferenceSelection.h | 3 +++ .../PartDesign/Gui/TaskDraftParameters.cpp | 21 ++----------------- src/Mod/PartDesign/Gui/TaskDraftParameters.h | 5 +---- .../Gui/TaskLinearPatternParameters.cpp | 5 +++-- .../PartDesign/Gui/TaskMirroredParameters.cpp | 5 +++-- .../Gui/TaskPolarPatternParameters.cpp | 5 +++-- .../Gui/TaskTransformedParameters.cpp | 17 --------------- .../Gui/TaskTransformedParameters.h | 5 +---- 9 files changed, 32 insertions(+), 50 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index ef943f7629d4..8ae2c4ae2592 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -116,6 +116,22 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c namespace PartDesignGui { +void getReferencedSelection(const App::DocumentObject* thisObj, const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub) +{ + selObj = thisObj->getDocument()->getObject(msg.pObjectName); + if (selObj == thisObj) + return; + std::string subname = msg.pSubName; + + // Remove subname for planes and datum features + if (PartDesign::Feature::isDatum(selObj)) { + subname = ""; + } + + selSub = std::vector(1,subname); +} + const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub) { if (obj == NULL) diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index 0055d65fad20..8046be6c9e31 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -48,6 +48,9 @@ class ReferenceSelection : public Gui::SelectionFilterGate }; // Convenience methods +/// Extract reference from Selection +void getReferencedSelection(const App::DocumentObject* thisObj, const Gui::SelectionChanges& msg, + App::DocumentObject*& selObj, std::vector& selSub); /// Return reference as string for UI elements (format : const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub); /// Return reference as string for python (format (, [""]) ) diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index c220b4683a98..3ca579e7e64d 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -110,23 +110,6 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p ui->lineLine->setText(getRefStr(ref, strings)); } -void TaskDraftParameters::getReferencedSelection(const Gui::SelectionChanges& msg, - App::DocumentObject*& selObj, std::vector& selSub) -{ - PartDesign::DressUp* pcDressup = static_cast(DraftView->getObject()); - selObj = pcDressup->getDocument()->getObject(msg.pObjectName); - if (selObj == pcDressup) - return; - std::string subname = msg.pSubName; - - // Remove subname for planes and datum features - if (PartDesign::Feature::isDatum(selObj)) { - subname = ""; - } - - selSub = std::vector(1,subname); -} - void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (selectionMode == none) @@ -182,7 +165,7 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) } else if ((selectionMode == plane)) { std::vector planes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, planes); + getReferencedSelection(pcDraft, msg, selObj, planes); pcDraft->NeutralPlane.setValue(selObj, planes); ui->linePlane->setText(getRefStr(selObj, planes)); @@ -192,7 +175,7 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) } else if ((selectionMode == line) && (subName.size() > 4 && subName.substr(0,4) == "Edge")) { std::vector edges; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, edges); + getReferencedSelection(pcDraft, msg, selObj, edges); pcDraft->PullDirection.setValue(selObj, edges); ui->lineLine->setText(getRefStr(selObj, edges)); diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.h b/src/Mod/PartDesign/Gui/TaskDraftParameters.h index 3d93f389e96d..ac4e07fa19d4 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.h @@ -83,10 +83,7 @@ private Q_SLOTS: ViewProviderDraft *DraftView; enum selectionModes { none, faceAdd, faceRemove, plane, line }; - selectionModes selectionMode; - - void getReferencedSelection(const Gui::SelectionChanges& msg, - App::DocumentObject*& selObj, std::vector& selSub); + selectionModes selectionMode; }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 6c1bcffaf1e7..8117f9d942d0 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -239,8 +239,8 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges if (!blockUpdate) { std::vector directions; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, directions); PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + getReferencedSelection(pcLinearPattern, msg, selObj, directions); pcLinearPattern->Direction.setValue(selObj, directions); recomputeFeature(); @@ -256,7 +256,8 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges std::vector directions; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, directions); + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + getReferencedSelection(pcLinearPattern, msg, selObj, directions); ui->comboDirection->addItem(getRefStr(selObj, directions)); ui->comboDirection->setCurrentIndex(maxcount); ui->comboDirection->addItem(tr("Select reference...")); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index 1c761560f2dc..7bce4d695908 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -195,8 +195,8 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg if (!blockUpdate) { std::vector mirrorPlanes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, mirrorPlanes); PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + getReferencedSelection(pcMirrored, msg, selObj, mirrorPlanes); pcMirrored->MirrorPlane.setValue(selObj, mirrorPlanes); recomputeFeature(); @@ -212,7 +212,8 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg std::vector mirrorPlanes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, mirrorPlanes); + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + getReferencedSelection(pcMirrored, msg, selObj, mirrorPlanes); ui->comboPlane->addItem(getRefStr(selObj, mirrorPlanes)); ui->comboPlane->setCurrentIndex(maxcount); ui->comboPlane->addItem(tr("Select reference...")); diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index eb3014a9a4e9..9de3a6bcb86b 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -209,8 +209,8 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& if (!blockUpdate) { std::vector axes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, axes); PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + getReferencedSelection(pcPolarPattern, msg, selObj, axes); pcPolarPattern->Axis.setValue(selObj, axes); recomputeFeature(); @@ -222,7 +222,8 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& std::vector axes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, axes); + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + getReferencedSelection(pcPolarPattern, msg, selObj, axes); ui->comboAxis->addItem(getRefStr(selObj, axes)); ui->comboAxis->setCurrentIndex(1); ui->comboAxis->addItem(tr("Select reference...")); diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 1c80e5ff1c3f..34e4aed8c950 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -228,23 +228,6 @@ void TaskTransformedParameters::addReferenceSelectionGate(bool edge, bool face) Gui::Selection().addSelectionGate(new ReferenceSelection(getSupportObject(), edge, face, true)); } -void TaskTransformedParameters::getReferencedSelection(const Gui::SelectionChanges& msg, - App::DocumentObject*& selObj, std::vector& selSub) -{ - PartDesign::Transformed* pcTransformed = static_cast(getObject()); - selObj = pcTransformed->getDocument()->getObject(msg.pObjectName); - if (selObj == pcTransformed) - return; - std::string subname = msg.pSubName; - - // Remove subname for planes and datum features - if (PartDesign::Feature::isDatum(selObj)) { - subname = ""; - } - - selSub = std::vector(1,subname); -} - //************************************************************************** //************************************************************************** // TaskDialog diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index ebcb0d47d1c2..6c66db7cd973 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -86,10 +86,7 @@ protected Q_SLOTS: void hideOriginals(); void showOriginals(); - void addReferenceSelectionGate(bool edge, bool face); - /// Extract reference from Selection (convenience method) - void getReferencedSelection(const Gui::SelectionChanges& msg, - App::DocumentObject*& selObj, std::vector& selSub); + void addReferenceSelectionGate(bool edge, bool face); bool isViewUpdated() const; int getUpdateViewTimeout() const; From 7983862b52a3ecee1f33c8c79a171199dd1079c7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 23 May 2013 17:33:23 +0430 Subject: [PATCH 125/664] Some code unification for sketchbased features --- .../PartDesign/Gui/TaskGrooveParameters.cpp | 17 ++------- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 22 +++-------- src/Mod/PartDesign/Gui/TaskPadParameters.h | 1 - .../PartDesign/Gui/TaskPocketParameters.cpp | 20 +++------- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 1 - .../Gui/TaskSketchBasedParameters.cpp | 37 ++++++------------- .../Gui/TaskSketchBasedParameters.h | 8 ++-- 7 files changed, 31 insertions(+), 75 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index d7e2f1ddb268..2a84a9b3df4c 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -128,8 +128,7 @@ void TaskGrooveParameters::onAngleChanged(double len) { PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Angle.setValue(len); - if (updateView()) - pcGroove->getDocument()->recomputeFeature(pcGroove); + recomputeFeature(); } void TaskGrooveParameters::onAxisChanged(int num) @@ -166,24 +165,21 @@ void TaskGrooveParameters::onAxisChanged(int num) } } } - if (updateView()) - pcGroove->getDocument()->recomputeFeature(pcGroove); + recomputeFeature(); } void TaskGrooveParameters::onMidplane(bool on) { PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Midplane.setValue(on); - if (updateView()) - pcGroove->getDocument()->recomputeFeature(pcGroove); + recomputeFeature(); } void TaskGrooveParameters::onReversed(bool on) { PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Reversed.setValue(on); - if (updateView()) - pcGroove->getDocument()->recomputeFeature(pcGroove); + recomputeFeature(); } double TaskGrooveParameters::getAngle(void) const @@ -226,11 +222,6 @@ bool TaskGrooveParameters::getReversed(void) const return ui->checkBoxReversed->isChecked(); } -const bool TaskGrooveParameters::updateView() const -{ - return ui->checkBoxUpdateView->isChecked(); -} - TaskGrooveParameters::~TaskGrooveParameters() { delete ui; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 2d5e503eb4b1..529e553d4d63 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -243,8 +243,7 @@ void TaskPadParameters::onLengthChanged(double len) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Length.setValue(len); - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); + recomputeFeature(); } void TaskPadParameters::onMidplane(bool on) @@ -252,24 +251,21 @@ void TaskPadParameters::onMidplane(bool on) PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Midplane.setValue(on); ui->checkBoxReversed->setEnabled(!on); - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); + recomputeFeature(); } void TaskPadParameters::onReversed(bool on) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Reversed.setValue(on); - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); + recomputeFeature(); } void TaskPadParameters::onLength2Changed(double len) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); pcPad->Length2.setValue(len); - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); + recomputeFeature(); } void TaskPadParameters::onModeChanged(int index) @@ -290,13 +286,12 @@ void TaskPadParameters::onModeChanged(int index) } updateUI(index); - - if (updateView()) - pcPad->getDocument()->recomputeFeature(pcPad); + recomputeFeature(); } void TaskPadParameters::onButtonFace(const bool pressed) { + TaskSketchBasedParameters::onSelectReference(pressed, false, true, false); // Update button if onButtonFace() is called explicitly ui->buttonFace->setChecked(pressed); @@ -340,11 +335,6 @@ QByteArray TaskPadParameters::getFaceName(void) const return ""; } -const bool TaskPadParameters::updateView() const -{ - return ui->checkBoxUpdateView->isChecked(); -} - TaskPadParameters::~TaskPadParameters() { delete ui; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index 0c28b737471c..575032319cfd 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -53,7 +53,6 @@ class TaskPadParameters : public TaskSketchBasedParameters TaskPadParameters(ViewProviderPad *PadView,bool newObj=false,QWidget *parent = 0); ~TaskPadParameters(); - const bool updateView() const; void saveHistory(void); void apply(); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 77b243681830..c0cc3008de98 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -225,8 +225,7 @@ void TaskPocketParameters::onLengthChanged(double len) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Length.setValue(len); - if (updateView()) - pcPocket->getDocument()->recomputeFeature(pcPocket); + recomputeFeature(); } void TaskPocketParameters::onMidplaneChanged(bool on) @@ -234,16 +233,14 @@ void TaskPocketParameters::onMidplaneChanged(bool on) PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Midplane.setValue(on); ui->checkBoxReversed->setEnabled(!on); - if (updateView()) - pcPocket->getDocument()->recomputeFeature(pcPocket); + recomputeFeature(); } void TaskPocketParameters::onReversedChanged(bool on) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); pcPocket->Reversed.setValue(on); - if (updateView()) - pcPocket->getDocument()->recomputeFeature(pcPocket); + recomputeFeature(); } void TaskPocketParameters::onModeChanged(int index) @@ -280,13 +277,11 @@ void TaskPocketParameters::onModeChanged(int index) } updateUI(index); - - if (updateView()) - pcPocket->getDocument()->recomputeFeature(pcPocket); + recomputeFeature(); } void TaskPocketParameters::onButtonFace(const bool pressed) { - TaskSketchBasedParameters::onButtonFace(pressed); + TaskSketchBasedParameters::onSelectReference(pressed, false, true, false); // Update button if onButtonFace() is called explicitly ui->buttonFace->setChecked(pressed); @@ -320,11 +315,6 @@ QByteArray TaskPocketParameters::getFaceName(void) const return ""; } -const bool TaskPocketParameters::updateView() const -{ - return ui->checkBoxUpdateView->isChecked(); -} - TaskPocketParameters::~TaskPocketParameters() { delete ui; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index 749129e66cd4..77cd96d8ec13 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -55,7 +55,6 @@ class TaskPocketParameters : public TaskSketchBasedParameters bool getReversed(void) const; QByteArray getFaceName(void) const; - const bool updateView() const; void apply(); private Q_SLOTS: diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index dcf9ddc85cb3..669f440e1162 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -58,27 +58,10 @@ using namespace Gui; TaskSketchBasedParameters::TaskSketchBasedParameters(ViewProvider *vp, QWidget *parent, const std::string& pixmapname, const QString& parname) : TaskBox(Gui::BitmapFactory().pixmap(pixmapname.c_str()),parname,true, parent), - vp(vp) + vp(vp), blockUpdate(false) { } -/* -App::DocumentObject* TaskSketchBasedParameters::getBaseFeature() -{ - PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); - App::DocumentObject* baseFeature = pcSketchBased->BaseFeature.getValue(); - if (baseFeature == NULL) { - if (ActivePartObject != NULL) { - baseFeature = ActivePartObject->getPrevSolidFeature(pcSketchBased, false); - } - if (baseFeature == NULL) { - // For legacy features - baseFeature = pcSketchBased->getSupport(); - } - } - - return baseFeature; -}*/ const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChanges& msg) { @@ -101,13 +84,12 @@ const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChan std::vector upToFaces(1,subname); pcSketchBased->UpToFace.setValue(selObj, upToFaces); - if (updateView()) - pcSketchBased->getDocument()->recomputeFeature(pcSketchBased); + recomputeFeature(); return refStr; } -void TaskSketchBasedParameters::onButtonFace(const bool pressed) { +void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar) { // Note: Even if there is no solid, App::Plane and Part::Datum can still be selected App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(NULL, false); PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); @@ -120,7 +102,7 @@ void TaskSketchBasedParameters::onButtonFace(const bool pressed) { } Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate - (new ReferenceSelection(solid, false, true, false)); + (new ReferenceSelection(solid, edge, face, planar)); } else { Gui::Selection().rmvSelectionGate(); Gui::Document* doc = Gui::Application::Instance->activeDocument(); @@ -168,8 +150,7 @@ const QByteArray TaskSketchBasedParameters::onFaceName(const QString& text) std::vector upToFaces(1,ss.str()); PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); pcSketchBased->UpToFace.setValue(obj, upToFaces); - if (updateView()) - pcSketchBased->getDocument()->recomputeFeature(pcSketchBased); + recomputeFeature(); return QByteArray(ss.str().c_str()); } @@ -188,7 +169,13 @@ QString TaskSketchBasedParameters::getFaceReference(const QString& obj, const QS void TaskSketchBasedParameters::onUpdateView(bool on) { - if (on) { + blockUpdate = !on; + recomputeFeature(); +} + +void TaskSketchBasedParameters::recomputeFeature() +{ + if (!blockUpdate) { PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); pcSketchBased->getDocument()->recomputeFeature(pcSketchBased); } diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h index 757b81825652..f72fe4cf230a 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h @@ -46,21 +46,21 @@ class TaskSketchBasedParameters : public Gui::TaskView::TaskBox, public Gui::Sel const std::string& pixmapname, const QString& parname); ~TaskSketchBasedParameters(); - //App::DocumentObject* getBaseFeature(); - protected: void onSelectionChanged(const Gui::SelectionChanges& msg)=0; const QString onAddSelection(const Gui::SelectionChanges& msg); - void onButtonFace(const bool pressed = true); + void onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar); const QByteArray onFaceName(const QString& text); QString getFaceReference(const QString& obj, const QString& sub) const; - virtual const bool updateView() const=0; + void recomputeFeature(); protected Q_SLOTS: void onUpdateView(bool on); protected: ViewProvider *vp; + /// Lock updateUI(), applying changes to the underlying feature and calling recomputeFeature() + bool blockUpdate; }; class TaskDlgSketchBasedParameters : public Gui::TaskView::TaskDialog From 999b1c028b48cab70d7a384816e533227cfb25de Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 23 May 2013 19:26:39 +0430 Subject: [PATCH 126/664] Allow inserting at the beginning of a body --- src/Mod/PartDesign/App/Body.cpp | 25 +++++++++++++++----- src/Mod/PartDesign/Gui/Command.cpp | 35 +++++++++++++++++----------- src/Mod/PartDesign/Gui/Workbench.cpp | 3 ++- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 8f7740750f92..b09b95158bff 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -130,6 +130,8 @@ App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start, const std::vector features = Model.getValues(); if (features.empty()) return NULL; App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); + if (st == NULL) + return st; // Tip is NULL if (inclusive && isSolidFeature(st)) return st; @@ -156,7 +158,11 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const if (inclusive && isSolidFeature(st)) return st; - std::vector::iterator it = std::find(features.begin(), features.end(), st); + std::vector::iterator it; + if (st == NULL) + it = features.begin(); // Tip is NULL + else + it = std::find(features.begin(), features.end(), st); if (it == features.end()) return NULL; // Invalid start object // Skip sketches and datum features @@ -170,9 +176,13 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const } const bool Body::isAfterTip(const App::DocumentObject *f) { + App::DocumentObject* tipFeature = Tip.getValue(); + if (tipFeature == NULL) + return true; + std::vector features = Model.getValues(); std::vector::const_iterator it = std::find(features.begin(), features.end(), f); - std::vector::const_iterator tip = std::find(features.begin(), features.end(), Tip.getValue()); + std::vector::const_iterator tip = std::find(features.begin(), features.end(), tipFeature); return (it > tip); } @@ -226,7 +236,8 @@ void Body::addFeature(App::DocumentObject *feature) // First feature in the body model.push_back(feature); else - throw Base::Exception("Body has features, but Tip is not valid"); + // Insert feature as before all other features in the body + model.insert(model.begin(), feature); } else { // Insert after Tip std::vector::iterator it = std::find(model.begin(), model.end(), tipFeature); @@ -334,13 +345,15 @@ Base::BoundBox3d Body::getBoundBox() Part::Feature* tipSolid = static_cast(getPrevSolidFeature()); if (tipSolid != NULL) { - TopoDS_Shape sh = tipSolid->Shape.getValue(); - if (sh.IsNull()) + if (tipSolid->Shape.getValue().IsNull()) // This can happen when a new feature is added without having its Shape property set yet tipSolid = static_cast(getPrevSolidFeature(NULL, false)); if (tipSolid != NULL) { - result = tipSolid->Shape.getShape().getBoundBox(); + if (tipSolid->Shape.getValue().IsNull()) + tipSolid = NULL; + else + result = tipSolid->Shape.getShape().getBoundBox(); } } if (tipSolid == NULL) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index f8145dfabb73..d2971b833578 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -178,7 +178,10 @@ void CmdPartDesignMoveTip::activated(int iMsg) if (features.empty()) return; App::DocumentObject* selFeature = features.front(); - if (!pcActiveBody->hasFeature(selFeature)) { + if (selFeature->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { + // Insert at the beginning of this body + selFeature = NULL; + } else if (!pcActiveBody->hasFeature(selFeature)) { // Switch to other body pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); if (pcActiveBody != NULL) @@ -188,21 +191,27 @@ void CmdPartDesignMoveTip::activated(int iMsg) return; } + openCommand("Move insert point to selected feature"); App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); - if (!oldTip->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); - if (prevSolidFeature != NULL) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + if (oldTip != NULL) { + if (!oldTip->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if (prevSolidFeature != NULL) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + } - openCommand("Move insert point to selected feature"); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); + if (selFeature == NULL) { + doCommand(Doc,"App.activeDocument().%s.Tip = None", pcActiveBody->getNameInDocument()); + } else { + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); - // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); - prevSolidFeature = pcActiveBody->getPrevSolidFeature(); - if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + } // TOOD: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see // others, so we would have to remember their state somehow diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index a4dc292934fe..665cda863d61 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -276,7 +276,8 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con { if (strcmp(recipient,"Tree") == 0) { - if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + + if (Gui::Selection().countObjectsOfType(PartDesign::Body::getClassTypeId()) + + Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveTip"; From 75dc92fd90e3a9ec500688060e58080b8b173ff1 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 23 May 2013 20:18:09 +0430 Subject: [PATCH 127/664] Enable edges and datum lines as rotation axis for Groove and Revolution features --- src/Mod/PartDesign/App/FeatureGroove.cpp | 71 +-- src/Mod/PartDesign/App/FeatureRevolution.cpp | 73 +-- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 92 ++++ src/Mod/PartDesign/App/FeatureSketchBased.h | 6 + .../PartDesign/Gui/TaskGrooveParameters.cpp | 188 ++++--- .../Gui/TaskGrooveParameters.cpp.orig | 458 ++++++++++++++++++ src/Mod/PartDesign/Gui/TaskGrooveParameters.h | 5 +- .../PartDesign/Gui/TaskGrooveParameters.ui | 7 +- .../Gui/TaskRevolutionParameters.cpp | 209 +++++--- .../Gui/TaskRevolutionParameters.cpp.orig | 410 ++++++++++++++++ .../PartDesign/Gui/TaskRevolutionParameters.h | 9 +- .../Gui/TaskRevolutionParameters.ui | 7 +- .../Gui/TaskSketchBasedParameters.cpp | 5 + .../Gui/TaskSketchBasedParameters.h | 1 + 14 files changed, 1284 insertions(+), 257 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp.orig diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index ede3a980edcf..8f7bbd8740fa 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -34,8 +34,6 @@ # include # include # include -# include -# include #endif #include @@ -181,72 +179,21 @@ App::DocumentObjectExecReturn *Groove::execute(void) bool Groove::suggestReversed(void) { - try { - updateAxis(); - - Part::Part2DObject* sketch = getVerifiedSketch(); - std::vector wires = getSketchWires(); - TopoDS_Shape sketchshape = makeFace(wires); - - Base::Vector3d b = Base.getValue(); - Base::Vector3d v = Axis.getValue(); - - // get centre of gravity of the sketch face - GProp_GProps props; - BRepGProp::SurfaceProperties(sketchshape, props); - gp_Pnt cog = props.CentreOfMass(); - Base::Vector3d p_cog(cog.X(), cog.Y(), cog.Z()); - // get direction to cog from its projection on the revolve axis - Base::Vector3d perp_dir = p_cog - p_cog.Perpendicular(b, v); - // get cross product of projection direction with revolve axis direction - Base::Vector3d cross = v % perp_dir; - // get sketch vector pointing away from support material - Base::Placement SketchPos = sketch->Placement.getValue(); - Base::Rotation SketchOrientation = SketchPos.getRotation(); - Base::Vector3d SketchNormal(0,0,1); - SketchOrientation.multVec(SketchNormal,SketchNormal); - - // return true if the angle between norm and cross is acute - return SketchNormal * cross > 0.f; - } - catch (...) { - return Reversed.getValue(); - } + updateAxis(); + return SketchBased::getReversedAngle(Base.getValue(), Axis.getValue()) > 0.0; } void Groove::updateAxis(void) { - Part::Part2DObject* sketch = getVerifiedSketch(); - Base::Placement SketchPlm = sketch->Placement.getValue(); - - // get reference axis App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue(); const std::vector &subReferenceAxis = ReferenceAxis.getSubValues(); - if (pcReferenceAxis && pcReferenceAxis == sketch) { - bool hasValidAxis=false; - Base::Axis axis; - if (subReferenceAxis[0] == "V_Axis") { - hasValidAxis = true; - axis = sketch->getAxis(Part::Part2DObject::V_Axis); - } - else if (subReferenceAxis[0] == "H_Axis") { - hasValidAxis = true; - axis = sketch->getAxis(Part::Part2DObject::H_Axis); - } - else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") { - int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); - if (AxId >= 0 && AxId < sketch->getAxisCount()) { - hasValidAxis = true; - axis = sketch->getAxis(AxId); - } - } - if (hasValidAxis) { - axis *= SketchPlm; - Base::Vector3d base=axis.getBase(); - Base::Vector3d dir=axis.getDirection(); - Base.setValue(base.x,base.y,base.z); - Axis.setValue(dir.x,dir.y,dir.z); - } + Base::Vector3d base; + Base::Vector3d dir; + getAxis(pcReferenceAxis, subReferenceAxis, base, dir); + + if (dir.Length() > Precision::Confusion()) { + Base.setValue(base.x,base.y,base.z); + Axis.setValue(dir.x,dir.y,dir.z); } } diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 83b9f69f25a4..35d56c930ed0 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -34,8 +34,6 @@ # include # include # include -# include -# include #endif #include @@ -181,75 +179,20 @@ App::DocumentObjectExecReturn *Revolution::execute(void) bool Revolution::suggestReversed(void) { - try { - updateAxis(); - - Part::Part2DObject* sketch = getVerifiedSketch(); - std::vector wires = getSketchWires(); - TopoDS_Shape sketchshape = makeFace(wires); - - Base::Vector3d b = Base.getValue(); - Base::Vector3d v = Axis.getValue(); - - // get centre of gravity of the sketch face - GProp_GProps props; - BRepGProp::SurfaceProperties(sketchshape, props); - gp_Pnt cog = props.CentreOfMass(); - Base::Vector3d p_cog(cog.X(), cog.Y(), cog.Z()); - // get direction to cog from its projection on the revolve axis - Base::Vector3d perp_dir = p_cog - p_cog.Perpendicular(b, v); - // get cross product of projection direction with revolve axis direction - Base::Vector3d cross = v % perp_dir; - // get sketch vector pointing away from support material - Base::Placement SketchPos = sketch->Placement.getValue(); - Base::Rotation SketchOrientation = SketchPos.getRotation(); - Base::Vector3d SketchNormal(0,0,1); - SketchOrientation.multVec(SketchNormal,SketchNormal); - // simply convert double to float - Base::Vector3d norm(SketchNormal.x, SketchNormal.y, SketchNormal.z); - - // return true if the angle between norm and cross is obtuse - return norm * cross < 0.f; - } - catch (...) { - return Reversed.getValue(); - } + updateAxis(); + return SketchBased::getReversedAngle(Base.getValue(), Axis.getValue()) < 0.0; } void Revolution::updateAxis(void) { - Part::Part2DObject* sketch = getVerifiedSketch(); - Base::Placement SketchPlm = sketch->Placement.getValue(); - - // get reference axis App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue(); const std::vector &subReferenceAxis = ReferenceAxis.getSubValues(); - if (pcReferenceAxis && pcReferenceAxis == sketch) { - bool hasValidAxis=false; - Base::Axis axis; - if (subReferenceAxis[0] == "V_Axis") { - hasValidAxis = true; - axis = sketch->getAxis(Part::Part2DObject::V_Axis); - } - else if (subReferenceAxis[0] == "H_Axis") { - hasValidAxis = true; - axis = sketch->getAxis(Part::Part2DObject::H_Axis); - } - else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") { - int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); - if (AxId >= 0 && AxId < sketch->getAxisCount()) { - hasValidAxis = true; - axis = sketch->getAxis(AxId); - } - } - if (hasValidAxis) { - axis *= SketchPlm; - Base::Vector3d base=axis.getBase(); - Base::Vector3d dir=axis.getDirection(); - Base.setValue(float(base.x),float(base.y),float(base.z)); - Axis.setValue(float(dir.x),float(dir.y),float(dir.z)); - } - } + Base::Vector3d base; + Base::Vector3d dir; + getAxis(pcReferenceAxis, subReferenceAxis, base, dir); + + Base.setValue(base.x,base.y,base.z); + Axis.setValue(dir.x,dir.y,dir.z); } } diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 7c81b5661a43..a4fabb94c61c 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -59,6 +59,8 @@ # include # include # include +# include +# include #endif #include @@ -72,6 +74,7 @@ #include #include "FeatureSketchBased.h" #include "DatumPlane.h" +#include "DatumLine.h" using namespace PartDesign; @@ -971,6 +974,95 @@ bool SketchBased::isSupportDatum() const return isDatum(SupportObject); } +const double SketchBased::getReversedAngle(const Base::Vector3d &b, const Base::Vector3d &v) +{ + try { + Part::Part2DObject* sketch = getVerifiedSketch(); + std::vector wires = getSketchWires(); + TopoDS_Shape sketchshape = makeFace(wires); + + // get centre of gravity of the sketch face + GProp_GProps props; + BRepGProp::SurfaceProperties(sketchshape, props); + gp_Pnt cog = props.CentreOfMass(); + Base::Vector3d p_cog(cog.X(), cog.Y(), cog.Z()); + // get direction to cog from its projection on the revolve axis + Base::Vector3d perp_dir = p_cog - p_cog.Perpendicular(b, v); + // get cross product of projection direction with revolve axis direction + Base::Vector3d cross = v % perp_dir; + // get sketch vector pointing away from support material + Base::Placement SketchPos = sketch->Placement.getValue(); + Base::Rotation SketchOrientation = SketchPos.getRotation(); + Base::Vector3d SketchNormal(0,0,1); + SketchOrientation.multVec(SketchNormal,SketchNormal); + + return SketchNormal * cross; + } + catch (...) { + return Reversed.getValue(); + } +} + +void SketchBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std::vector &subReferenceAxis, + Base::Vector3d& base, Base::Vector3d& dir) +{ + dir = Base::Vector3d(0,0,0); // If unchanged signals that no valid axis was found + Part::Part2DObject* sketch = getVerifiedSketch(); + Base::Placement SketchPlm = sketch->Placement.getValue(); + + // get reference axis + if (pcReferenceAxis->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { + const PartDesign::Line* line = static_cast(pcReferenceAxis); + base = line->getBasePoint(); + dir = line->getDirection(); + } else if (pcReferenceAxis->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + if (subReferenceAxis[0].empty()) + throw Base::Exception("No rotation axis reference specified"); + const Part::Feature* refFeature = static_cast(pcReferenceAxis); + Part::TopoShape refShape = refFeature->Shape.getShape(); + TopoDS_Shape ref = refShape.getSubShape(subReferenceAxis[0].c_str()); + + if (ref.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge refEdge = TopoDS::Edge(ref); + if (refEdge.IsNull()) + throw Base::Exception("Failed to extract rotation edge"); + BRepAdaptor_Curve adapt(refEdge); + if (adapt.GetType() != GeomAbs_Line) + throw Base::Exception("Rotation edge must be a straight line"); + + gp_Pnt b = adapt.Line().Location(); + base = Base::Vector3d(b.X(), b.Y(), b.Z()); + gp_Dir d = adapt.Line().Direction(); + dir = Base::Vector3d(d.X(), d.Y(), d.Z()); + } else { + throw Base::Exception("Rotation reference must be an edge"); + } + } else if (pcReferenceAxis && pcReferenceAxis == sketch) { + bool hasValidAxis=false; + Base::Axis axis; + if (subReferenceAxis[0] == "V_Axis") { + hasValidAxis = true; + axis = sketch->getAxis(Part::Part2DObject::V_Axis); + } + else if (subReferenceAxis[0] == "H_Axis") { + hasValidAxis = true; + axis = sketch->getAxis(Part::Part2DObject::H_Axis); + } + else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") { + int AxId = std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); + if (AxId >= 0 && AxId < sketch->getAxisCount()) { + hasValidAxis = true; + axis = sketch->getAxis(AxId); + } + } + if (hasValidAxis) { + axis *= SketchPlm; + base=axis.getBase(); + dir=axis.getDirection(); + } + } +} + TopoDS_Shape SketchBased::refineShapeIfActive(const TopoDS_Shape& oldShape) const { Base::Reference hGrp = App::GetApplication().GetUserParameter() diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index b28f18cc2be4..5336b218cd0e 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -124,6 +124,12 @@ class PartDesignExport SketchBased : public PartDesign::Feature static const bool checkLineCrossesFace(const gp_Lin& line, const TopoDS_Face& face); class Wire_Compare; + + /// Used to suggest a value for Reversed flag so that material is always removed (Groove) or added (Revolution) from the support + const double getReversedAngle(const Base::Vector3d& b, const Base::Vector3d& v); + /// get Axis from ReferenceAxis + void getAxis(const App::DocumentObject* pcReferenceAxis, const std::vector& subReferenceAxis, + Base::Vector3d& base, Base::Vector3d& dir); }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index 2a84a9b3df4c..27011e7ad375 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -39,10 +39,13 @@ #include #include #include +#include #include #include #include #include "Workbench.h" +#include "ReferenceSelection.h" +#include "TaskSketchBasedParameters.h" using namespace PartDesignGui; using namespace Gui; @@ -85,33 +88,8 @@ TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidge ui->grooveAngle->setValue(l); ui->grooveAngle->bind(pcGroove->Angle); - int count=pcGroove->getSketchAxisCount(); - - for (int i=ui->axis->count()-1; i >= count+2; i--) - ui->axis->removeItem(i); - for (int i=ui->axis->count(); i < count+2; i++) - ui->axis->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); - - int pos=-1; - - App::DocumentObject *pcReferenceAxis = pcGroove->ReferenceAxis.getValue(); - const std::vector &subReferenceAxis = pcGroove->ReferenceAxis.getSubValues(); - if (pcReferenceAxis && pcReferenceAxis == pcGroove->Sketch.getValue()) { - assert(subReferenceAxis.size()==1); - if (subReferenceAxis[0] == "V_Axis") - pos = 0; - else if (subReferenceAxis[0] == "H_Axis") - pos = 1; - else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") - pos = 2 + std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); - } - - if (pos < 0 || pos >= ui->axis->count()) { - ui->axis->addItem(QString::fromLatin1("Undefined")); - pos = ui->axis->count()-1; - } - - ui->axis->setCurrentIndex(pos); + blockUpdate = false; + updateUI(); ui->checkBoxMidplane->setChecked(mirrored); ui->checkBoxReversed->setChecked(reversed); @@ -124,15 +102,99 @@ TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidge setFocus (); } +void TaskGrooveParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + + App::DocumentObject* pcReferenceAxis = pcGroove->ReferenceAxis.getValue(); + std::vector sub = pcGroove->ReferenceAxis.getSubValues(); + + // Add user-defined sketch axes to the reference selection combo box + Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + + for (int i=ui->axis->count()-1; i >= 2; i--) + ui->axis->removeItem(i); + for (int i=ui->axis->count(); i < maxcount; i++) + ui->axis->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); + + bool undefined = false; + if (pcReferenceAxis != NULL && !sub.empty()) { + if (sub.front() == "H_Axis") + ui->axis->setCurrentIndex(0); + else if (sub.front() == "V_Axis") + ui->axis->setCurrentIndex(1); + else if (sub.front().size() > 4 && sub.front().substr(0,4) == "Axis") { + int pos = 2 + std::atoi(sub.front().substr(4,4000).c_str()); + if (pos <= maxcount) + ui->axis->setCurrentIndex(pos); + else + undefined = true; + } else { + ui->axis->addItem(getRefStr(pcReferenceAxis, sub)); + ui->axis->setCurrentIndex(maxcount); + } + } else { + undefined = true; + } + + ui->axis->addItem(tr("Select reference...")); + + blockUpdate = false; +} + +void TaskGrooveParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + + exitSelectionMode(); + if (!blockUpdate) { + std::vector axis; + App::DocumentObject* selObj; + getReferencedSelection(pcGroove, msg, selObj, axis); + pcGroove->ReferenceAxis.setValue(selObj, axis); + + + recomputeFeature(); + updateUI(); + } + else { + Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + for (int i=ui->axis->count()-1; i >= maxcount; i--) + ui->axis->removeItem(i); + + std::vector sub; + App::DocumentObject* selObj; + getReferencedSelection(pcGroove, msg, selObj, sub); + ui->axis->addItem(getRefStr(selObj, sub)); + ui->axis->setCurrentIndex(maxcount); + ui->axis->addItem(tr("Select reference...")); + } + } +} + void TaskGrooveParameters::onAngleChanged(double len) { PartDesign::Groove* pcGroove = static_cast(vp->getObject()); pcGroove->Angle.setValue(len); + exitSelectionMode(); recomputeFeature(); } void TaskGrooveParameters::onAxisChanged(int num) { + if (blockUpdate) + return; PartDesign::Groove* pcGroove = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); if (pcSketch) { @@ -140,20 +202,26 @@ void TaskGrooveParameters::onAxisChanged(int num) std::vector oldSubRefAxis = pcGroove->ReferenceAxis.getSubValues(); int maxcount = pcSketch->getAxisCount()+2; - if (num == 0) - pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); - else if (num == 1) + if (num == 0) { pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"H_Axis")); - else if (num >= 2 && num < maxcount) { + exitSelectionMode(); + } else if (num == 1) { + pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); + exitSelectionMode(); + } else if (num >= 2 && num < maxcount) { QString buf = QString::fromUtf8("Axis%1").arg(num-2); std::string str = buf.toStdString(); pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,str)); - } - if (num < maxcount && ui->axis->count() > maxcount) - ui->axis->setMaxCount(maxcount); - + exitSelectionMode(); + } else if (num == ui->axis->count() - 1) { + // enter reference selection mode + TaskSketchBasedParameters::onSelectReference(true, true, false, true); + } else if (num == maxcount) + exitSelectionMode(); + + App::DocumentObject *newRefAxis = pcGroove->ReferenceAxis.getValue(); const std::vector &newSubRefAxis = pcGroove->ReferenceAxis.getSubValues(); - if (oldRefAxis != pcSketch || + if (oldRefAxis != newRefAxis || oldSubRefAxis.size() != newSubRefAxis.size() || oldSubRefAxis[0] != newSubRefAxis[0]) { bool reversed = pcGroove->suggestReversed(); @@ -165,6 +233,8 @@ void TaskGrooveParameters::onAxisChanged(int num) } } } + + updateUI(); recomputeFeature(); } @@ -187,29 +257,36 @@ double TaskGrooveParameters::getAngle(void) const return ui->grooveAngle->value().getValue(); } -QString TaskGrooveParameters::getReferenceAxis(void) const +void TaskGrooveParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const { // get the support and Sketch PartDesign::Groove* pcGroove = static_cast(vp->getObject()); - Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); - - QString buf; - if (pcSketch) { - buf = QString::fromUtf8("(App.ActiveDocument.%1,[%2])"); - buf = buf.arg(QString::fromUtf8(pcSketch->getNameInDocument())); - if (ui->axis->currentIndex() == 0) - buf = buf.arg(QString::fromUtf8("'V_Axis'")); - else if (ui->axis->currentIndex() == 1) - buf = buf.arg(QString::fromUtf8("'H_Axis'")); - else if (ui->axis->currentIndex() >= 2) { - buf = buf.arg(QString::fromUtf8("'Axis%1'")); - buf = buf.arg(ui->axis->currentIndex()-2); + obj = static_cast(pcGroove->Sketch.getValue()); + sub = std::vector(1,""); + int maxcount=2; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + + if (obj) { + int num = ui->axis->currentIndex(); + if (num == 0) + sub[0] = "H_Axis"; + else if (num == 1) + sub[0] = "V_Axis"; + else if (num >= 2 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-2); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->axis->count() == maxcount + 2) { + QStringList parts = ui->axis->currentText().split(QChar::fromAscii(':')); + obj = vp->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; } } else - buf = QString::fromUtf8("''"); - - return buf; + obj = NULL; } bool TaskGrooveParameters::getMidplane(void) const @@ -252,7 +329,10 @@ void TaskGrooveParameters::apply() //Gui::Command::openCommand("Groove changed"); ui->grooveAngle->apply(); - std::string axis = getReferenceAxis().toStdString(); + std::vector sub; + App::DocumentObject* obj; + parameter->getReferenceAxis(obj, sub); + std::string axis = getPythonStr(obj, sub); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(), getReversed() ? 1 : 0); diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp.orig new file mode 100644 index 000000000000..e365cc7b2c54 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp.orig @@ -0,0 +1,458 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 "ui_TaskGrooveParameters.h" +#include "TaskGrooveParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Workbench.h" +#include "ReferenceSelection.h" +#include "TaskSketchBasedParameters.h" + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskGrooveParameters */ + +TaskGrooveParameters::TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent) + : TaskSketchBasedParameters(GrooveView, parent, "PartDesign_Groove",tr("Groove parameters")) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskGrooveParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->grooveAngle, SIGNAL(valueChanged(double)), + this, SLOT(onAngleChanged(double))); + connect(ui->axis, SIGNAL(activated(int)), + this, SLOT(onAxisChanged(int))); + connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), + this, SLOT(onMidplane(bool))); + connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), + this, SLOT(onReversed(bool))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature updates + ui->grooveAngle->blockSignals(true); + ui->axis->blockSignals(true); + ui->checkBoxMidplane->blockSignals(true); + ui->checkBoxReversed->blockSignals(true); + + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + double l = pcGroove->Angle.getValue(); + bool mirrored = pcGroove->Midplane.getValue(); + bool reversed = pcGroove->Reversed.getValue(); + + ui->grooveAngle->setValue(l); + ui->grooveAngle->bind(pcGroove->Angle); + +<<<<<<< f0798a82fe8f03db57aca4f634d2123486daaea0 + int count=pcGroove->getSketchAxisCount(); + + for (int i=ui->axis->count()-1; i >= count+2; i--) + ui->axis->removeItem(i); + for (int i=ui->axis->count(); i < count+2; i++) + ui->axis->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); + + int pos=-1; + + App::DocumentObject *pcReferenceAxis = pcGroove->ReferenceAxis.getValue(); + const std::vector &subReferenceAxis = pcGroove->ReferenceAxis.getSubValues(); + if (pcReferenceAxis && pcReferenceAxis == pcGroove->Sketch.getValue()) { + assert(subReferenceAxis.size()==1); + if (subReferenceAxis[0] == "V_Axis") + pos = 0; + else if (subReferenceAxis[0] == "H_Axis") + pos = 1; + else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") + pos = 2 + std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); + } + + if (pos < 0 || pos >= ui->axis->count()) { + ui->axis->addItem(QString::fromLatin1("Undefined")); + pos = ui->axis->count()-1; + } + + ui->axis->setCurrentIndex(pos); +======= + blockUpdate = false; + updateUI(); +>>>>>>> Enable edges and datum lines as rotation axis for Groove and Revolution features + + ui->checkBoxMidplane->setChecked(mirrored); + ui->checkBoxReversed->setChecked(reversed); + + ui->grooveAngle->blockSignals(false); + ui->axis->blockSignals(false); + ui->checkBoxMidplane->blockSignals(false); + ui->checkBoxReversed->blockSignals(false); + + setFocus (); +} + +void TaskGrooveParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + + App::DocumentObject* pcReferenceAxis = pcGroove->ReferenceAxis.getValue(); + std::vector sub = pcGroove->ReferenceAxis.getSubValues(); + + // Add user-defined sketch axes to the reference selection combo box + Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + + for (int i=ui->axis->count()-1; i >= 2; i--) + ui->axis->removeItem(i); + for (int i=ui->axis->count(); i < maxcount; i++) + ui->axis->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); + + bool undefined = false; + if (pcReferenceAxis != NULL && !sub.empty()) { + if (sub.front() == "H_Axis") + ui->axis->setCurrentIndex(0); + else if (sub.front() == "V_Axis") + ui->axis->setCurrentIndex(1); + else if (sub.front().size() > 4 && sub.front().substr(0,4) == "Axis") { + int pos = 2 + std::atoi(sub.front().substr(4,4000).c_str()); + if (pos <= maxcount) + ui->axis->setCurrentIndex(pos); + else + undefined = true; + } else { + ui->axis->addItem(getRefStr(pcReferenceAxis, sub)); + ui->axis->setCurrentIndex(maxcount); + } + } else { + undefined = true; + } + + ui->axis->addItem(tr("Select reference...")); + + blockUpdate = false; +} + +void TaskGrooveParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + + exitSelectionMode(); + if (!blockUpdate) { + std::vector axis; + App::DocumentObject* selObj; + getReferencedSelection(pcGroove, msg, selObj, axis); + pcGroove->ReferenceAxis.setValue(selObj, axis); + + + recomputeFeature(); + updateUI(); + } + else { + Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + for (int i=ui->axis->count()-1; i >= maxcount; i--) + ui->axis->removeItem(i); + + std::vector sub; + App::DocumentObject* selObj; + getReferencedSelection(pcGroove, msg, selObj, sub); + ui->axis->addItem(getRefStr(selObj, sub)); + ui->axis->setCurrentIndex(maxcount); + ui->axis->addItem(tr("Select reference...")); + } + } +} + +void TaskGrooveParameters::onAngleChanged(double len) +{ + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + pcGroove->Angle.setValue(len); + exitSelectionMode(); + recomputeFeature(); +} + +void TaskGrooveParameters::onAxisChanged(int num) +{ + if (blockUpdate) + return; + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); + if (pcSketch) { + App::DocumentObject *oldRefAxis = pcGroove->ReferenceAxis.getValue(); + std::vector oldSubRefAxis = pcGroove->ReferenceAxis.getSubValues(); + + int maxcount = pcSketch->getAxisCount()+2; + if (num == 0) { + pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"H_Axis")); + exitSelectionMode(); + } else if (num == 1) { + pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); + exitSelectionMode(); + } else if (num >= 2 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-2); + std::string str = buf.toStdString(); + pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,str)); + exitSelectionMode(); + } else if (num == ui->axis->count() - 1) { + // enter reference selection mode + TaskSketchBasedParameters::onSelectReference(true, true, false, true); + } else if (num == maxcount) + exitSelectionMode(); + + App::DocumentObject *newRefAxis = pcGroove->ReferenceAxis.getValue(); + const std::vector &newSubRefAxis = pcGroove->ReferenceAxis.getSubValues(); + if (oldRefAxis != newRefAxis || + oldSubRefAxis.size() != newSubRefAxis.size() || + oldSubRefAxis[0] != newSubRefAxis[0]) { + bool reversed = pcGroove->suggestReversed(); + if (reversed != pcGroove->Reversed.getValue()) { + pcGroove->Reversed.setValue(reversed); + ui->checkBoxReversed->blockSignals(true); + ui->checkBoxReversed->setChecked(reversed); + ui->checkBoxReversed->blockSignals(false); + } + } + } + + updateUI(); + recomputeFeature(); +} + +void TaskGrooveParameters::onMidplane(bool on) +{ + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + pcGroove->Midplane.setValue(on); + recomputeFeature(); +} + +void TaskGrooveParameters::onReversed(bool on) +{ + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + pcGroove->Reversed.setValue(on); + recomputeFeature(); +} + +double TaskGrooveParameters::getAngle(void) const +{ + return ui->grooveAngle->value().getValue(); +} + +void TaskGrooveParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const +{ + // get the support and Sketch + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + obj = static_cast(pcGroove->Sketch.getValue()); + sub = std::vector(1,""); + int maxcount=2; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + + if (obj) { + int num = ui->axis->currentIndex(); + if (num == 0) + sub[0] = "H_Axis"; + else if (num == 1) + sub[0] = "V_Axis"; + else if (num >= 2 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-2); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->axis->count() == maxcount + 2) { + QStringList parts = ui->axis->currentText().split(QChar::fromAscii(':')); + obj = vp->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } + } + else + obj = NULL; +} + +bool TaskGrooveParameters::getMidplane(void) const +{ + return ui->checkBoxMidplane->isChecked(); +} + +bool TaskGrooveParameters::getReversed(void) const +{ + return ui->checkBoxReversed->isChecked(); +} + +TaskGrooveParameters::~TaskGrooveParameters() +{ + delete ui; +} + +void TaskGrooveParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +void TaskGrooveParameters::apply() +{ + App::DocumentObject* groove = vp->getObject(); + std::string name = groove->getNameInDocument(); + + // retrieve sketch and its support object + App::DocumentObject* sketch = 0; + App::DocumentObject* support = 0; + if (groove->getTypeId().isDerivedFrom(PartDesign::Groove::getClassTypeId())) { + sketch = static_cast(groove)->Sketch.getValue(); + if (sketch) { + support = static_cast(sketch)->Support.getValue(); + } + } + + //Gui::Command::openCommand("Groove changed"); + ui->grooveAngle->apply(); + std::vector sub; + App::DocumentObject* obj; + parameter->getReferenceAxis(obj, sub); + std::string axis = getPythonStr(obj, sub); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(), getReversed() ? 1 : 0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (groove->isValid()) { + if (sketch) + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); + if (support) + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); + } + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + } + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgGrooveParameters::TaskDlgGrooveParameters(ViewProviderGroove *GrooveView) + : TaskDlgSketchBasedParameters(GrooveView) +{ + assert(vp); + parameter = new TaskGrooveParameters(static_cast(vp)); + + Content.push_back(parameter); +} + +TaskDlgGrooveParameters::~TaskDlgGrooveParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgGrooveParameters::open() +{ + // a transaction is already open at creation time of the groove + if (!Gui::Command::hasPendingCommand()) { + QString msg = QObject::tr("Edit groove"); + Gui::Command::openCommand((const char*)msg.toUtf8()); + } +} + +void TaskDlgGrooveParameters::clicked(int) +{ + +} + +bool TaskDlgGrooveParameters::accept() +{ + parameter->apply(); + return true; +} + +bool TaskDlgGrooveParameters::reject() +{ + // get the support and Sketch + PartDesign::Groove* pcGroove = static_cast(vp->getObject()); + Sketcher::SketchObject *pcSketch = 0; + if (pcGroove->Sketch.getValue()) { + pcSketch = static_cast(pcGroove->Sketch.getValue()); + } + + // role back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // if abort command deleted the object the support is visible again + if (!Gui::Application::Instance->getViewProvider(pcGroove)) { + if (pcSketch && Gui::Application::Instance->getViewProvider(pcSketch)) + Gui::Application::Instance->getViewProvider(pcSketch)->show(); + } + + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + return true; +} + + + +#include "moc_TaskGrooveParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h index d98aaddd3356..e4511475c62e 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h @@ -62,15 +62,16 @@ private Q_SLOTS: void onReversed(bool); protected: - void onSelectionChanged(const Gui::SelectionChanges& msg) {} + void onSelectionChanged(const Gui::SelectionChanges& msg); void changeEvent(QEvent *e); - QString getReferenceAxis(void) const; + void getReferenceAxis(App::DocumentObject *&obj, std::vector &sub) const; double getAngle(void) const; bool getMidplane(void) const; bool getReversed(void) const; const bool updateView() const; private: + void updateUI(); private: QWidget* proxy; diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui b/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui index 43f540cd431f..07f78e043d52 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui @@ -25,6 +25,11 @@ + + + Horizontal sketch axis + + Vertical sketch axis @@ -32,7 +37,7 @@ - Horizontal sketch axis + Select reference... diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 268c5cb8a51a..740311c50d18 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -39,9 +39,12 @@ #include #include #include +#include #include #include #include +#include "ReferenceSelection.h" +#include "TaskSketchBasedParameters.h" #include "Workbench.h" @@ -84,40 +87,14 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol bool reversed = pcRevolution->Reversed.getValue(); ui->revolveAngle->setValue(l); - - int count=pcRevolution->getSketchAxisCount(); - - for (int i=ui->axis->count()-1; i >= count+2; i--) - ui->axis->removeItem(i); - for (int i=ui->axis->count(); i < count+2; i++) - ui->axis->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); - - int pos=-1; - - App::DocumentObject *pcReferenceAxis = pcRevolution->ReferenceAxis.getValue(); - const std::vector &subReferenceAxis = pcRevolution->ReferenceAxis.getSubValues(); - if (pcReferenceAxis && pcReferenceAxis == pcRevolution->Sketch.getValue()) { - assert(subReferenceAxis.size()==1); - if (subReferenceAxis[0] == "V_Axis") - pos = 0; - else if (subReferenceAxis[0] == "H_Axis") - pos = 1; - else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") - pos = 2 + std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); - } - - if (pos < 0 || pos >= ui->axis->count()) { - ui->axis->addItem(tr("Undefined")); - pos = ui->axis->count()-1; - } - - ui->axis->setCurrentIndex(pos); + blockUpdate = false; + updateUI(); ui->checkBoxMidplane->setChecked(mirrored); ui->checkBoxReversed->setChecked(reversed); ui->revolveAngle->bind(pcRevolution->Angle); - ui->revolveAngle->blockSignals(false); + ui->doubleSpinBox->blockSignals(false); ui->axis->blockSignals(false); ui->checkBoxMidplane->blockSignals(false); ui->checkBoxReversed->blockSignals(false); @@ -125,16 +102,100 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol setFocus (); } +void TaskRevolutionParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + + App::DocumentObject* pcReferenceAxis = pcRevolution->ReferenceAxis.getValue(); + std::vector sub = pcRevolution->ReferenceAxis.getSubValues(); + + // Add user-defined sketch axes to the reference selection combo box + Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + + for (int i=ui->axis->count()-1; i >= 2; i--) + ui->axis->removeItem(i); + for (int i=ui->axis->count(); i < maxcount; i++) + ui->axis->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); + + bool undefined = false; + if (pcReferenceAxis != NULL && !sub.empty()) { + if (sub.front() == "H_Axis") + ui->axis->setCurrentIndex(0); + else if (sub.front() == "V_Axis") + ui->axis->setCurrentIndex(1); + else if (sub.front().size() > 4 && sub.front().substr(0,4) == "Axis") { + int pos = 2 + std::atoi(sub.front().substr(4,4000).c_str()); + if (pos <= maxcount) + ui->axis->setCurrentIndex(pos); + else + undefined = true; + } else { + ui->axis->addItem(getRefStr(pcReferenceAxis, sub)); + ui->axis->setCurrentIndex(maxcount); + } + } else { + undefined = true; + } + + ui->axis->addItem(tr("Select reference...")); + + blockUpdate = false; +} + +void TaskRevolutionParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + + exitSelectionMode(); + if (!blockUpdate) { + std::vector axis; + App::DocumentObject* selObj; + getReferencedSelection(pcRevolution, msg, selObj, axis); + pcRevolution->ReferenceAxis.setValue(selObj, axis); + + + recomputeFeature(); + updateUI(); + } + else { + Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + for (int i=ui->axis->count()-1; i >= maxcount; i--) + ui->axis->removeItem(i); + + std::vector sub; + App::DocumentObject* selObj; + getReferencedSelection(pcRevolution, msg, selObj, sub); + ui->axis->addItem(getRefStr(selObj, sub)); + ui->axis->setCurrentIndex(maxcount); + ui->axis->addItem(tr("Select reference...")); + } + } +} + + void TaskRevolutionParameters::onAngleChanged(double len) { PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); pcRevolution->Angle.setValue(len); - if (updateView()) - pcRevolution->getDocument()->recomputeFeature(pcRevolution); + exitSelectionMode(); + recomputeFeature(); } void TaskRevolutionParameters::onAxisChanged(int num) { + if (blockUpdate) + return; PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); if (pcSketch) { @@ -142,20 +203,26 @@ void TaskRevolutionParameters::onAxisChanged(int num) std::vector oldSubRefAxis = pcRevolution->ReferenceAxis.getSubValues(); int maxcount = pcSketch->getAxisCount()+2; - if (num == 0) - pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); - else if (num == 1) + if (num == 0) { pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,"H_Axis")); - else if (num >= 2 && num < maxcount) { + exitSelectionMode(); + } else if (num == 1) { + pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); + exitSelectionMode(); + } else if (num >= 2 && num < maxcount) { QString buf = QString::fromUtf8("Axis%1").arg(num-2); std::string str = buf.toStdString(); pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,str)); - } - if (num < maxcount && ui->axis->count() > maxcount) - ui->axis->setMaxCount(maxcount); - + exitSelectionMode(); + } else if (num == ui->axis->count() - 1) { + // enter reference selection mode + TaskSketchBasedParameters::onSelectReference(true, true, false, true); + } else if (num == maxcount) + exitSelectionMode(); + + App::DocumentObject *newRefAxis = pcRevolution->ReferenceAxis.getValue(); const std::vector &newSubRefAxis = pcRevolution->ReferenceAxis.getSubValues(); - if (oldRefAxis != pcSketch || + if (oldRefAxis != newRefAxis || oldSubRefAxis.size() != newSubRefAxis.size() || oldSubRefAxis[0] != newSubRefAxis[0]) { bool reversed = pcRevolution->suggestReversed(); @@ -167,24 +234,23 @@ void TaskRevolutionParameters::onAxisChanged(int num) } } } - if (updateView()) - pcRevolution->getDocument()->recomputeFeature(pcRevolution); + + updateUI(); + recomputeFeature(); } void TaskRevolutionParameters::onMidplane(bool on) { PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); pcRevolution->Midplane.setValue(on); - if (updateView()) - pcRevolution->getDocument()->recomputeFeature(pcRevolution); + recomputeFeature(); } void TaskRevolutionParameters::onReversed(bool on) { PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); pcRevolution->Reversed.setValue(on); - if (updateView()) - pcRevolution->getDocument()->recomputeFeature(pcRevolution); + recomputeFeature(); } double TaskRevolutionParameters::getAngle(void) const @@ -192,29 +258,36 @@ double TaskRevolutionParameters::getAngle(void) const return ui->revolveAngle->value().getValue(); } -QString TaskRevolutionParameters::getReferenceAxis(void) const +void TaskRevolutionParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const { // get the support and Sketch PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); - Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); - - QString buf; - if (pcSketch) { - buf = QString::fromUtf8("(App.ActiveDocument.%1,[%2])"); - buf = buf.arg(QString::fromUtf8(pcSketch->getNameInDocument())); - if (ui->axis->currentIndex() == 0) - buf = buf.arg(QString::fromUtf8("'V_Axis'")); - else if (ui->axis->currentIndex() == 1) - buf = buf.arg(QString::fromUtf8("'H_Axis'")); - else if (ui->axis->currentIndex() >= 2) { - buf = buf.arg(QString::fromUtf8("'Axis%1'")); - buf = buf.arg(ui->axis->currentIndex()-2); + obj = static_cast(pcRevolution->Sketch.getValue()); + sub = std::vector(1,""); + int maxcount=2; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + + if (obj) { + int num = ui->axis->currentIndex(); + if (num == 0) + sub[0] = "H_Axis"; + else if (num == 1) + sub[0] = "V_Axis"; + else if (num >= 2 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-2); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->axis->count() == maxcount + 2) { + QStringList parts = ui->axis->currentText().split(QChar::fromAscii(':')); + obj = vp->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; } } else - buf = QString::fromUtf8("''"); - - return buf; + obj = NULL; } bool TaskRevolutionParameters::getMidplane(void) const @@ -227,11 +300,6 @@ bool TaskRevolutionParameters::getReversed(void) const return ui->checkBoxReversed->isChecked(); } -const bool TaskRevolutionParameters::updateView() const -{ - return ui->checkBoxUpdateView->isChecked(); -} - TaskRevolutionParameters::~TaskRevolutionParameters() { delete ui; @@ -262,7 +330,10 @@ void TaskRevolutionParameters::apply() //Gui::Command::openCommand("Revolution changed"); ui->revolveAngle->apply(); - std::string axis = getReferenceAxis().toStdString(); + std::vector sub; + App::DocumentObject* obj; + parameter->getReferenceAxis(obj, sub); + std::string axis = getPythonStr(obj, sub); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(), getReversed() ? 1 : 0); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp.orig new file mode 100644 index 000000000000..3d058d31d354 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp.orig @@ -0,0 +1,410 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 "ui_TaskRevolutionParameters.h" +#include "TaskRevolutionParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ReferenceSelection.h" +#include "TaskSketchBasedParameters.h" +#include "Workbench.h" + + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskRevolutionParameters */ + +TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *RevolutionView,QWidget *parent) + : TaskSketchBasedParameters(RevolutionView, parent, "PartDesign_Revolution",tr("Revolution parameters")) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskRevolutionParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->revolveAngle, SIGNAL(valueChanged(double)), + this, SLOT(onAngleChanged(double))); + connect(ui->axis, SIGNAL(activated(int)), + this, SLOT(onAxisChanged(int))); + connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), + this, SLOT(onMidplane(bool))); + connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), + this, SLOT(onReversed(bool))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + this->groupLayout()->addWidget(proxy); + + // Temporarily prevent unnecessary feature recomputes + ui->revolveAngle->blockSignals(true); + ui->axis->blockSignals(true); + ui->checkBoxMidplane->blockSignals(true); + ui->checkBoxReversed->blockSignals(true); + + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + double l = pcRevolution->Angle.getValue(); + bool mirrored = pcRevolution->Midplane.getValue(); + bool reversed = pcRevolution->Reversed.getValue(); + + ui->revolveAngle->setValue(l); +<<<<<<< f0798a82fe8f03db57aca4f634d2123486daaea0 + + int count=pcRevolution->getSketchAxisCount(); + + for (int i=ui->axis->count()-1; i >= count+2; i--) + ui->axis->removeItem(i); + for (int i=ui->axis->count(); i < count+2; i++) + ui->axis->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); + + int pos=-1; + + App::DocumentObject *pcReferenceAxis = pcRevolution->ReferenceAxis.getValue(); + const std::vector &subReferenceAxis = pcRevolution->ReferenceAxis.getSubValues(); + if (pcReferenceAxis && pcReferenceAxis == pcRevolution->Sketch.getValue()) { + assert(subReferenceAxis.size()==1); + if (subReferenceAxis[0] == "V_Axis") + pos = 0; + else if (subReferenceAxis[0] == "H_Axis") + pos = 1; + else if (subReferenceAxis[0].size() > 4 && subReferenceAxis[0].substr(0,4) == "Axis") + pos = 2 + std::atoi(subReferenceAxis[0].substr(4,4000).c_str()); + } + + if (pos < 0 || pos >= ui->axis->count()) { + ui->axis->addItem(tr("Undefined")); + pos = ui->axis->count()-1; + } + + ui->axis->setCurrentIndex(pos); +======= + blockUpdate = false; + updateUI(); +>>>>>>> Enable edges and datum lines as rotation axis for Groove and Revolution features + + ui->checkBoxMidplane->setChecked(mirrored); + ui->checkBoxReversed->setChecked(reversed); + ui->revolveAngle->bind(pcRevolution->Angle); + + ui->doubleSpinBox->blockSignals(false); + ui->axis->blockSignals(false); + ui->checkBoxMidplane->blockSignals(false); + ui->checkBoxReversed->blockSignals(false); + + setFocus (); +} + +void TaskRevolutionParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + + App::DocumentObject* pcReferenceAxis = pcRevolution->ReferenceAxis.getValue(); + std::vector sub = pcRevolution->ReferenceAxis.getSubValues(); + + // Add user-defined sketch axes to the reference selection combo box + Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + + for (int i=ui->axis->count()-1; i >= 2; i--) + ui->axis->removeItem(i); + for (int i=ui->axis->count(); i < maxcount; i++) + ui->axis->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); + + bool undefined = false; + if (pcReferenceAxis != NULL && !sub.empty()) { + if (sub.front() == "H_Axis") + ui->axis->setCurrentIndex(0); + else if (sub.front() == "V_Axis") + ui->axis->setCurrentIndex(1); + else if (sub.front().size() > 4 && sub.front().substr(0,4) == "Axis") { + int pos = 2 + std::atoi(sub.front().substr(4,4000).c_str()); + if (pos <= maxcount) + ui->axis->setCurrentIndex(pos); + else + undefined = true; + } else { + ui->axis->addItem(getRefStr(pcReferenceAxis, sub)); + ui->axis->setCurrentIndex(maxcount); + } + } else { + undefined = true; + } + + ui->axis->addItem(tr("Select reference...")); + + blockUpdate = false; +} + +void TaskRevolutionParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + + exitSelectionMode(); + if (!blockUpdate) { + std::vector axis; + App::DocumentObject* selObj; + getReferencedSelection(pcRevolution, msg, selObj, axis); + pcRevolution->ReferenceAxis.setValue(selObj, axis); + + + recomputeFeature(); + updateUI(); + } + else { + Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); + int maxcount=2; + if (pcSketch) + maxcount += pcSketch->getAxisCount(); + for (int i=ui->axis->count()-1; i >= maxcount; i--) + ui->axis->removeItem(i); + + std::vector sub; + App::DocumentObject* selObj; + getReferencedSelection(pcRevolution, msg, selObj, sub); + ui->axis->addItem(getRefStr(selObj, sub)); + ui->axis->setCurrentIndex(maxcount); + ui->axis->addItem(tr("Select reference...")); + } + } +} + + +void TaskRevolutionParameters::onAngleChanged(double len) +{ + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + pcRevolution->Angle.setValue(len); + exitSelectionMode(); + recomputeFeature(); +} + +void TaskRevolutionParameters::onAxisChanged(int num) +{ + if (blockUpdate) + return; + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + Sketcher::SketchObject *pcSketch = static_cast(pcRevolution->Sketch.getValue()); + if (pcSketch) { + App::DocumentObject *oldRefAxis = pcRevolution->ReferenceAxis.getValue(); + std::vector oldSubRefAxis = pcRevolution->ReferenceAxis.getSubValues(); + + int maxcount = pcSketch->getAxisCount()+2; + if (num == 0) { + pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,"H_Axis")); + exitSelectionMode(); + } else if (num == 1) { + pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); + exitSelectionMode(); + } else if (num >= 2 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-2); + std::string str = buf.toStdString(); + pcRevolution->ReferenceAxis.setValue(pcSketch, std::vector(1,str)); + exitSelectionMode(); + } else if (num == ui->axis->count() - 1) { + // enter reference selection mode + TaskSketchBasedParameters::onSelectReference(true, true, false, true); + } else if (num == maxcount) + exitSelectionMode(); + + App::DocumentObject *newRefAxis = pcRevolution->ReferenceAxis.getValue(); + const std::vector &newSubRefAxis = pcRevolution->ReferenceAxis.getSubValues(); + if (oldRefAxis != newRefAxis || + oldSubRefAxis.size() != newSubRefAxis.size() || + oldSubRefAxis[0] != newSubRefAxis[0]) { + bool reversed = pcRevolution->suggestReversed(); + if (reversed != pcRevolution->Reversed.getValue()) { + pcRevolution->Reversed.setValue(reversed); + ui->checkBoxReversed->blockSignals(true); + ui->checkBoxReversed->setChecked(reversed); + ui->checkBoxReversed->blockSignals(false); + } + } + } + + updateUI(); + recomputeFeature(); +} + +void TaskRevolutionParameters::onMidplane(bool on) +{ + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + pcRevolution->Midplane.setValue(on); + recomputeFeature(); +} + +void TaskRevolutionParameters::onReversed(bool on) +{ + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + pcRevolution->Reversed.setValue(on); + recomputeFeature(); +} + +double TaskRevolutionParameters::getAngle(void) const +{ + return ui->revolveAngle->value().getValue(); +} + +void TaskRevolutionParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector& sub) const +{ + // get the support and Sketch + PartDesign::Revolution* pcRevolution = static_cast(vp->getObject()); + obj = static_cast(pcRevolution->Sketch.getValue()); + sub = std::vector(1,""); + int maxcount=2; + if (obj) + maxcount += static_cast(obj)->getAxisCount(); + + if (obj) { + int num = ui->axis->currentIndex(); + if (num == 0) + sub[0] = "H_Axis"; + else if (num == 1) + sub[0] = "V_Axis"; + else if (num >= 2 && num < maxcount) { + QString buf = QString::fromUtf8("Axis%1").arg(num-2); + sub[0] = buf.toStdString(); + } else if (num == maxcount && ui->axis->count() == maxcount + 2) { + QStringList parts = ui->axis->currentText().split(QChar::fromAscii(':')); + obj = vp->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); + } else { + obj = NULL; + } + } + else + obj = NULL; +} + +bool TaskRevolutionParameters::getMidplane(void) const +{ + return ui->checkBoxMidplane->isChecked(); +} + +bool TaskRevolutionParameters::getReversed(void) const +{ + return ui->checkBoxReversed->isChecked(); +} + +TaskRevolutionParameters::~TaskRevolutionParameters() +{ + delete ui; +} + +void TaskRevolutionParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +void TaskRevolutionParameters::apply() +{ + App::DocumentObject* revolve = vp->getObject(); + std::string name = revolve->getNameInDocument(); + + // retrieve sketch and its support object + App::DocumentObject* sketch = 0; + App::DocumentObject* support = 0; + if (revolve->getTypeId().isDerivedFrom(PartDesign::Revolution::getClassTypeId())) { + sketch = static_cast(revolve)->Sketch.getValue(); + if (sketch) { + support = static_cast(sketch)->Support.getValue(); + } + } + + //Gui::Command::openCommand("Revolution changed"); + ui->revolveAngle->apply(); + std::vector sub; + App::DocumentObject* obj; + parameter->getReferenceAxis(obj, sub); + std::string axis = getPythonStr(obj, sub); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(), getReversed() ? 1 : 0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (revolve->isValid()) { + if (sketch) + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")",sketch->getNameInDocument()); + if (support) + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().hide(\"%s\")",support->getNameInDocument()); + } + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgRevolutionParameters::TaskDlgRevolutionParameters(ViewProviderRevolution *RevolutionView) + : TaskDlgSketchBasedParameters(RevolutionView) +{ + assert(RevolutionView); + parameter = new TaskRevolutionParameters(RevolutionView); + + Content.push_back(parameter); +} + +TaskDlgRevolutionParameters::~TaskDlgRevolutionParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgRevolutionParameters::accept() +{ + parameter->apply(); + return true; +} + + +#include "moc_TaskRevolutionParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index 1f224447f004..c38ff7342da1 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -62,17 +62,20 @@ private Q_SLOTS: void onReversed(bool); protected: - void onSelectionChanged(const Gui::SelectionChanges& msg) {} + void onSelectionChanged(const Gui::SelectionChanges& msg); void changeEvent(QEvent *e); const bool updateView() const; - QString getReferenceAxis(void) const; + void getReferenceAxis(App::DocumentObject *&obj, std::vector &sub) const; double getAngle(void) const; bool getMidplane(void) const; bool getReversed(void) const; +private: + void updateUI(); + private: QWidget* proxy; - Ui_TaskRevolutionParameters* ui; + Ui_TaskRevolutionParameters* ui; }; /// simulation dialog for the TaskView diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui index 989786f40cc3..23a640d2cb81 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui @@ -25,6 +25,11 @@ + + + Horizontal sketch axis + + Vertical sketch axis @@ -32,7 +37,7 @@ - Horizontal sketch axis + Select reference... diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 669f440e1162..d239a5cb6206 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -113,6 +113,11 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool } } +void TaskSketchBasedParameters::exitSelectionMode() +{ + onSelectReference(false, false, false, false); +} + const QByteArray TaskSketchBasedParameters::onFaceName(const QString& text) { if (text.length() == 0) diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h index f72fe4cf230a..9724fb713031 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h @@ -50,6 +50,7 @@ class TaskSketchBasedParameters : public Gui::TaskView::TaskBox, public Gui::Sel void onSelectionChanged(const Gui::SelectionChanges& msg)=0; const QString onAddSelection(const Gui::SelectionChanges& msg); void onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar); + void exitSelectionMode(); const QByteArray onFaceName(const QString& text); QString getFaceReference(const QString& obj, const QString& sub) const; void recomputeFeature(); From 106efeec023db08f0f4cbff03eb669e447364969 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 23 May 2013 20:19:59 +0430 Subject: [PATCH 128/664] Miscellaneous fixes --- src/Mod/PartDesign/App/DatumLine.cpp | 4 ++-- src/Mod/PartDesign/App/DatumLine.h | 4 ++-- src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp | 1 + src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp | 1 + src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp | 10 ++++++---- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index bed809869c1d..66c233b09d46 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -269,12 +269,12 @@ const std::set Line::getHint() return std::set(); } -Base::Vector3d Line::getBasePoint() +Base::Vector3d Line::getBasePoint() const { return Placement.getValue().getPosition(); } -Base::Vector3d Line::getDirection() +Base::Vector3d Line::getDirection() const { Base::Rotation rot = Placement.getValue().getRotation(); Base::Vector3d dir; diff --git a/src/Mod/PartDesign/App/DatumLine.h b/src/Mod/PartDesign/App/DatumLine.h index a70956a26c6a..14eaf3ef1538 100644 --- a/src/Mod/PartDesign/App/DatumLine.h +++ b/src/Mod/PartDesign/App/DatumLine.h @@ -47,8 +47,8 @@ class PartDesignExport Line : public Part::Datum static void initHints(); const std::set getHint(); - Base::Vector3d getBasePoint(); - Base::Vector3d getDirection(); + Base::Vector3d getBasePoint() const; + Base::Vector3d getDirection() const; protected: virtual void onChanged(const App::Property* prop); diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 8117f9d942d0..42478242e24f 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -333,6 +333,7 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { QString buf = QString::fromUtf8("Axis%1").arg(num-5); std::string str = buf.toStdString(); pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,str)); + exitSelectionMode(); } else if (num == ui->comboDirection->count() - 1) { // enter reference selection mode diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index 7bce4d695908..f7e5f99f10b6 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -259,6 +259,7 @@ void TaskMirroredParameters::onPlaneChanged(int num) { QString buf = QString::fromUtf8("Axis%1").arg(num-5); std::string str = buf.toStdString(); pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,str)); + exitSelectionMode(); } else if (num == ui->comboPlane->count() - 1) { // enter reference selection mode diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index d239a5cb6206..efabfaa03940 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -96,9 +96,10 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool if (pressed) { Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc && solid) { + if (doc) { doc->setHide(pcSketchBased->getNameInDocument()); - doc->setShow(solid->getNameInDocument()); + if (solid) + doc->setShow(solid->getNameInDocument()); } Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate @@ -106,9 +107,10 @@ void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool } else { Gui::Selection().rmvSelectionGate(); Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc && solid) { + if (doc) { doc->setShow(pcSketchBased->getNameInDocument()); - doc->setHide(solid->getNameInDocument()); + if (solid) + doc->setHide(solid->getNameInDocument()); } } } From 026242231ea3f6ca236129e2f880bf5d87ded177 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 24 May 2013 08:23:04 +0430 Subject: [PATCH 129/664] Changed tree ordering of booleans and bodies --- src/Mod/PartDesign/App/Feature.cpp | 18 ++++++++- src/Mod/PartDesign/App/Feature.h | 4 ++ src/Mod/PartDesign/App/FeatureBoolean.cpp | 37 ++++++++++--------- src/Mod/PartDesign/Gui/Command.cpp | 37 ++++++++++++------- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 11 ++++++ src/Mod/PartDesign/Gui/ReferenceSelection.h | 4 +- .../PartDesign/Gui/TaskBooleanParameters.cpp | 36 ++++++++++++------ .../Gui/TaskRevolutionParameters.cpp | 2 +- 8 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 1e091b4abc20..da4990b117d5 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -90,7 +90,7 @@ const gp_Pnt Feature::getPointFromFace(const TopoDS_Face& f) throw Base::Exception("getPointFromFace(): Not implemented yet for this case"); } -const TopoDS_Shape& Feature::getBaseShape() const { +const Part::Feature* Feature::getBaseObject() const { App::DocumentObject* BaseLink = BaseFeature.getValue(); if (BaseLink == NULL) throw Base::Exception("Base property not set"); Part::Feature* BaseObject = NULL; @@ -100,6 +100,12 @@ const TopoDS_Shape& Feature::getBaseShape() const { if (BaseObject == NULL) throw Base::Exception("No base feature linked"); + return BaseObject; +} + +const TopoDS_Shape& Feature::getBaseShape() const { + const Part::Feature* BaseObject = getBaseObject(); + const TopoDS_Shape& result = BaseObject->Shape.getValue(); if (result.IsNull()) throw Base::Exception("Base feature's shape is invalid"); @@ -110,6 +116,16 @@ const TopoDS_Shape& Feature::getBaseShape() const { return result; } +const Part::TopoShape Feature::getBaseTopoShape() const { + const Part::Feature* BaseObject = getBaseObject(); + + const Part::TopoShape& result = BaseObject->Shape.getShape(); + if (result._Shape.IsNull()) + throw Base::Exception("Base feature's TopoShape is invalid"); + + return result; +} + bool Feature::isDatum(const App::DocumentObject* feature) { return feature->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index adba54e437f3..c9f0d170eb2f 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -57,8 +57,12 @@ class PartDesignExport Feature : public Part::Feature static bool isDatum(const App::DocumentObject* feature); protected: + /// Returns the BaseFeature property's object (if any) + const Part::Feature* getBaseObject() const; /// Returns the BaseFeature property's shape (if any) const TopoDS_Shape& getBaseShape() const; + /// Returns the BaseFeature property's TopoShape (if any) + const Part::TopoShape getBaseTopoShape() const; /** * Get a solid of the given shape. If no solid is found an exception is raised. diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp index 73a5a633b82a..978ef0bea966 100644 --- a/src/Mod/PartDesign/App/FeatureBoolean.cpp +++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp @@ -60,33 +60,36 @@ short Boolean::mustExecute() const App::DocumentObjectExecReturn *Boolean::execute(void) { + // Get the base shape to operate on + Part::TopoShape baseTopShape; + try { + baseTopShape = getBaseTopoShape(); + } catch (const Base::Exception&) { + return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid base shape"); + } + std::vector bodies = Bodies.getValues(); if (bodies.empty()) return App::DocumentObject::StdReturn; - // Get the first body - if (bodies.front() == NULL) - return new App::DocumentObjectExecReturn("No body for boolean"); - PartDesign::Body* body = static_cast(bodies.front()); - const Part::TopoShape& bodyTopShape = body->Shape.getShape(); - if (bodyTopShape._Shape.IsNull()) - return new App::DocumentObjectExecReturn("Cannot do boolean operation on invalid body shape"); - - // create an untransformed copy of the body shape - Part::TopoShape bodyShape(bodyTopShape); - bodyShape.setTransform(Base::Matrix4D()); - TopoDS_Shape result = bodyShape._Shape; + // create an untransformed copy of the base shape + Part::TopoShape baseShape(baseTopShape); + baseShape.setTransform(Base::Matrix4D()); + TopoDS_Shape result = baseShape._Shape; // Position this feature by the first body - this->Placement.setValue(body->Placement.getValue()); + const Part::Feature* baseFeature; + try { + baseFeature = getBaseObject(); + } catch (const Base::Exception&) { + return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid BaseFeature"); + } + this->Placement.setValue(baseFeature->Placement.getValue()); // Get the operation type std::string type = Type.getValueAsString(); - std::vector::const_iterator b = bodies.begin(); - b++; - - for (; b != bodies.end(); b++) + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { // Extract the body shape PartDesign::Body* body = static_cast(*b); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index d2971b833578..87d2609e0360 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -79,6 +79,7 @@ using namespace std; +#include "ReferenceSelection.h" //=========================================================================== // PartDesign_Body @@ -737,7 +738,7 @@ bool CmdPartDesignNewSketch::isActive(void) // Common utility functions for all features creating solids //=========================================================================== -void finishFeature(const Gui::Command* cmd, const std::string& FeatName) +void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const bool hidePrevSolid = true) { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); @@ -746,7 +747,7 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName) if (cmd->isActiveObjectValid() && (pcActiveBody != NULL)) { App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); - if (prevSolidFeature != NULL) + if (hidePrevSolid && (prevSolidFeature != NULL)) cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); } cmd->updateActive(); @@ -1626,33 +1627,41 @@ CmdPartDesignBoolean::CmdPartDesignBoolean() void CmdPartDesignBoolean::activated(int iMsg) { Gui::SelectionFilter BodyFilter("SELECT PartDesign::Body COUNT 1.."); - std::string bodyString("["); + PartDesign::Body* body; + std::string bodyString(""); if (BodyFilter.match()) { + body = static_cast(BodyFilter.Result[0][0].getObject()); std::vector bodies; - for (std::vector >::iterator i = BodyFilter.Result.begin(); - i != BodyFilter.Result.end(); i++) { + std::vector >::iterator i = BodyFilter.Result.begin(); + i++; + for (; i != BodyFilter.Result.end(); i++) { for (std::vector::iterator j = i->begin(); j != i->end(); j++) { bodies.push_back(j->getObject()); } } - - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) - bodyString += std::string("App.activeDocument().") + (*b)->getNameInDocument() + ","; - bodyString += "]"; + bodyString = PartDesignGui::getPythonStr(bodies); } else { - bodyString = ""; + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No body selected"), + QObject::tr("Please select a body for the boolean operation")); + return; + } + + openCommand("Create Boolean"); + + // Make sure we are working on the selected body + if (body != PartDesignGui::ActivePartObject) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(body->getDocument()->getName(), body->Tip.getValue()->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); } std::string FeatName = getUniqueObjectName("Boolean"); - openCommand("Create Boolean"); doCommand(Doc,"App.activeDocument().addObject('PartDesign::Boolean','%s')",FeatName.c_str()); if (!bodyString.empty()) doCommand(Doc,"App.activeDocument().%s.Bodies = %s",FeatName.c_str(),bodyString.c_str()); - //doCommand(Gui,"App.activeDocument().recompute()"); - //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); + finishFeature(this, FeatName, false); } bool CmdPartDesignBoolean::isActive(void) diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 8ae2c4ae2592..2a8df942b3a2 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -155,4 +155,15 @@ const std::string getPythonStr(const App::DocumentObject* obj, const std::vector return std::string("(App.ActiveDocument.") + obj->getNameInDocument() + ", [\"" + sub.front() + "\"])"; } +const std::string getPythonStr(const std::vector objs) +{ + std::string result("["); + + for (std::vector::const_iterator o = objs.begin(); o != objs.end(); o++) + result += std::string("App.activeDocument().") + (*o)->getNameInDocument() + ","; + result += "]"; + + return result; +} + } diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index 8046be6c9e31..46699c9de39f 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -53,8 +53,10 @@ void getReferencedSelection(const App::DocumentObject* thisObj, const Gui::Selec App::DocumentObject*& selObj, std::vector& selSub); /// Return reference as string for UI elements (format : const QString getRefStr(const App::DocumentObject* obj, const std::vector& sub); -/// Return reference as string for python (format (, [""]) ) +/// Return reference as string for python in the format (, ["",]) const std::string getPythonStr(const App::DocumentObject* obj, const std::vector& sub); +/// Return reference as string for python in the format [obj1, obj2, ...,] +const std::string getPythonStr(const std::vector objs); } //namespace PartDesignGui diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp index ee14dbf53e39..f5986f053674 100644 --- a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp @@ -122,15 +122,15 @@ void TaskBooleanParameters::onSelectionChanged(const Gui::SelectionChanges& msg) ui->buttonBodyAdd->setChecked(false); exitSelectionMode(); - // Hide the bodies if there are more than two - if (bodies.size() == 2) { - // Hide both bodies + // Hide the bodies + if (bodies.size() == 1) { + // Hide base body and added body Gui::ViewProviderDocumentObject* vp = dynamic_cast( - Gui::Application::Instance->getViewProvider(bodies.front())); + Gui::Application::Instance->getViewProvider(pcBoolean->BaseFeature.getValue())); if (vp != NULL) vp->hide(); vp = dynamic_cast( - Gui::Application::Instance->getViewProvider(bodies.back())); + Gui::Application::Instance->getViewProvider(bodies.front())); if (vp != NULL) vp->hide(); BooleanView->show(); @@ -163,9 +163,9 @@ void TaskBooleanParameters::onSelectionChanged(const Gui::SelectionChanges& msg) Gui::Application::Instance->getViewProvider(*b)); if (vp != NULL) vp->show(); - if (bodies.size() == 1) { + if (bodies.size() == 0) { Gui::ViewProviderDocumentObject* vp = dynamic_cast( - Gui::Application::Instance->getViewProvider(bodies.front())); + Gui::Application::Instance->getViewProvider(pcBoolean->BaseFeature.getValue())); if (vp != NULL) vp->show(); BooleanView->hide(); @@ -180,7 +180,10 @@ void TaskBooleanParameters::onButtonBodyAdd(bool checked) if (checked) { Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc != NULL) - doc->setHide(BooleanView->getObject()->getNameInDocument()); + BooleanView->hide(); + PartDesign::Boolean* pcBoolean = static_cast(BooleanView->getObject()); + if (pcBoolean->Bodies.getValues().empty()) + doc->setHide(pcBoolean->BaseFeature.getValue()->getNameInDocument()); selectionMode = bodyAdd; Gui::Selection().clearSelection(); } else { @@ -193,7 +196,7 @@ void TaskBooleanParameters::onButtonBodyRemove(bool checked) if (checked) { Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc != NULL) - doc->setHide(BooleanView->getObject()->getNameInDocument()); + BooleanView->show(); selectionMode = bodyRemove; Gui::Selection().clearSelection(); } else { @@ -247,9 +250,9 @@ void TaskBooleanParameters::onBodyDeleted(void) Gui::Application::Instance->getViewProvider(body)); if (vp != NULL) vp->show(); - if (bodies.size() == 1) { + if (bodies.empty()) { Gui::ViewProviderDocumentObject* vp = dynamic_cast( - Gui::Application::Instance->getViewProvider(bodies.front())); + Gui::Application::Instance->getViewProvider(pcBoolean->BaseFeature.getValue())); if (vp != NULL) vp->show(); BooleanView->hide(); @@ -343,10 +346,21 @@ bool TaskDlgBooleanParameters::accept() bool TaskDlgBooleanParameters::reject() { + // Show the bodies again + PartDesign::Boolean* obj = static_cast(BooleanView->getObject()); + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + if (doc != NULL) { + doc->setShow(obj->BaseFeature.getValue()->getNameInDocument()); + std::vector bodies = obj->Bodies.getValues(); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + doc->setShow((*b)->getNameInDocument()); + } + // roll back the done things Gui::Command::abortCommand(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + return true; } diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 740311c50d18..339592b9eaeb 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -94,7 +94,7 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol ui->checkBoxReversed->setChecked(reversed); ui->revolveAngle->bind(pcRevolution->Angle); - ui->doubleSpinBox->blockSignals(false); + ui->revolveAngle->blockSignals(false); ui->axis->blockSignals(false); ui->checkBoxMidplane->blockSignals(false); ui->checkBoxReversed->blockSignals(false); From 04e5d833669ff4ac14ac224e38a38d2111797806 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 24 May 2013 15:13:53 +0430 Subject: [PATCH 130/664] Revolution/Groove: Check that rotation axis is coplanar with sketch plane --- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index a4fabb94c61c..4f0d74c21f84 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -1009,12 +1009,21 @@ void SketchBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std: dir = Base::Vector3d(0,0,0); // If unchanged signals that no valid axis was found Part::Part2DObject* sketch = getVerifiedSketch(); Base::Placement SketchPlm = sketch->Placement.getValue(); + Base::Vector3d SketchPos = SketchPlm.getPosition(); + Base::Rotation SketchOrientation = SketchPlm.getRotation(); + Base::Vector3d SketchVector(0,0,1); + SketchOrientation.multVec(SketchVector,SketchVector); + gp_Pln sketchplane(gp_Pnt(SketchPos.x, SketchPos.y, SketchPos.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); // get reference axis if (pcReferenceAxis->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { const PartDesign::Line* line = static_cast(pcReferenceAxis); base = line->getBasePoint(); dir = line->getDirection(); + + // Check that axis is co-planar with sketch plane! + if (!sketchplane.Contains(gp_Lin(gp_Pnt(base.x, base.y, base.z), gp_Dir(dir.x, dir.y, dir.z)), Precision::Confusion(), Precision::Confusion())) + throw Base::Exception("Rotation axis must be coplanar with the sketch plane"); } else if (pcReferenceAxis->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { if (subReferenceAxis[0].empty()) throw Base::Exception("No rotation axis reference specified"); @@ -1034,6 +1043,9 @@ void SketchBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std: base = Base::Vector3d(b.X(), b.Y(), b.Z()); gp_Dir d = adapt.Line().Direction(); dir = Base::Vector3d(d.X(), d.Y(), d.Z()); + // Check that axis is co-planar with sketch plane! + if (!sketchplane.Contains(adapt.Line(), Precision::Confusion(), Precision::Confusion())) + throw Base::Exception("Rotation axis must be coplanar with the sketch plane"); } else { throw Base::Exception("Rotation reference must be an edge"); } From 401c4d6dc06766d36a62dfbde0b1e97f71bb1e6f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 24 May 2013 15:15:08 +0430 Subject: [PATCH 131/664] Miscellaneous fixes --- data/tests/PadTest.fcstd | Bin 14782 -> 43355 bytes data/tests/PocketTest.fcstd | Bin 13766 -> 43830 bytes src/Mod/Assembly/App/AppAssemblyPy.cpp | 3 ++- src/Mod/PartDesign/Gui/Command.cpp | 27 ++++++++++++-------- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 8 +++--- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/data/tests/PadTest.fcstd b/data/tests/PadTest.fcstd index 8a7223083d43f88af19d30fa4f4f7e9512152815..3fe36983efa5729ae3361301cd8c327a0ce8b464 100644 GIT binary patch literal 43355 zcmZ6yV{k4^u(li9wr%r?ZQHh!72CFL+qP}n_DZs%^X{)sojUvbGe4%MXR5loru&+^ zMo|V73=Ief2nuL9x?LCmYqk&o3j~Df00ad0->j&EiJP67y(@!=ya(wGws6lePRKReyU8rP1@Z2I4?|4t7HhYw{gS0pY@W_2!W zEouo9aDS-5p`_l7I(V?+F&DU7WWCWmZ1#m==lexSF+))RQiyr+WaFXZkgOq@;>C;8 zhe%^)B2pS_d|phyg|OJN5KE!=yB}vFJ7n=_x5{c~sFwowxexuImn&LD9U9m@eji6j zeOkl_LunGP<2gib0os6Qpqu+4b%N?H-RXOD|$S6M| z+9VpBBW>YLRU*wi?C3i6EYF#q(P?g!rb~CiGP6`qNzp|YLj4TC zcMR~kTv+c=Xu-rN=$ug$FwVzY- zA#B??s%hU_?`u@;WAXhCw>>pX93O5Q07m^qS3Hl6L=d@_kjgsCS0m)bnoNB4MKBfqvfzOyCD3Dky&5VMUrxhXq><~c!3k26E5SOa)8<991IP^^Ku4S zm}eA_vX}VKmtckp`nsw(kR#!TI4l*Aq~gEP_8ctfnOF|X7~!WIxaWFX zJg6AjzNxV0>3jb!W$+U1CdPZMquFw)&6J&#%WxH*j&GY2RUO$uA*=&u1A&5cjFSN5 zi%s@G>=}~=)1QY5qq%NQW$5cIjEIng#&hk~pR?oCW5|lmxSMQ>FIVO}`6gr^tNuPqMcT>I` z5J@c#Z&3U%XP^I^X$Tv(_zEE*rM3u9cDF44K*@lMZW1EqLXyiR)jloCkittR+H|Ys zsL@;ju(t6&18d{N>Oa}x&$@uKZb45UK zIZx{jONgYmRM09U6r;dGx8;mmz1a?mogb>bQd(T7P>3@z7K+QM6yp;t!4qCi;$0CU zm8~n#KCVUbS_6Qqo7LaOp&}bFC%qJqYd0;6ELqhwDE`Sp>bCAlD_d7f%KmG@FDDgI zd5tu}dhUdYStO?uGrgovSmLHS4N@)%3hzPxA`5cnI-AG1+$2x;BhNGI`-HAUuIu!P zCla7~c}^~!!+ZN&{g=i&A=_%!MCmxEQPsZ1)AW4&6-YK6^Xg11$=O6sW$m0W^^ZJj zS}<&+wt>er^scCc}A0g`EAwC;eIa0dXCb!epVB0@}HJvAzC6JAtXgo<|)A&PcbP^OQR!_*{q1BDW@ z+N@WEOLr5YOf@1b=ZW+clgok~vdY4CPJ67BDz|3wzf z=%?(M&2SwBScVs4CSv$2HEXpT;y^3x>*gT*#DBipSfg`uoOp+2YMF?k$R3Ve6X|aa8?kefse+s<1L0dtTI^`J6$PDl)`b%M>A9AHfSv!0!FL*3#DuPQK@I z2g0iL^}sRdEnj{>+4)zja<(xauNiC>%imoc*`^y+DMg?Ke$5V?N z7#D`5PPJl!#A2cswh)e_91!=1*&LwfWj+Cm4@lq z7qXxdtwgfrbMmpl&L($qn+bDd{Sf8}q+)+^iqH)98n3LgW>x-XEzmpoE1s89bltH; zxteT3`5Rk3mCmHSc1DWN?PRkAEF#p)tMSLxYHJSX%JC(!4hK~%9sNCf+#F7mB2)7v zIeSr4GtU(gWyjrCD*B8)V@d19L`K`AaUuo7AjZ~e?yL^V{Tg1lx>bmcv#fY(F;<*S zeRG+==0c9AT|>l68L~YV{*ounzO=}Durd_eI>Ok*C2L&)9Xw!0eLrgsqMk0Rz{y!=Gog*^tzF&K-qu*Y{Ca`gDp09q0eR>IAuLnO>&qyZxH+qg&{UWb z78uURDT0v3;!uja-)RlSG;fc*RRl%kK$iq%SO#B{7Ne9|FIGL?vqaopUbMchSB#kv zpZP$CB-=tAXgmu)3qcla!<-jk%E>Fy4BNnOtR8(VMY0QCImEpboDhZbMUPSAH$8i94Aop`hMLhJ!*WiMbI z<|^W^$6d7T_#DkpUuiAv{bvx~FawgqIVEvk$%ih<^lS7c%{iHcj~bU;YDC6AE9CC! z)AP5&@g+qs-7{RS0HeW^O=wA~ruYi)2Q~w1h+Lo+l(d;=?57oU9k2?W{fsud5wV); z8Rd3;mB4w2Kf?NqfuHL<3haD0Q+*hz(cBPBm2TGdGCoQo_+inT3%VMs80jX@bwY(l zFa7?mFIjCQBr&UaR#hhlk4}Ruxxj3-bo~4YSO$rLpkP7xom=60(Fr@1X%Xbt&51g? zZtkEJqczV?hV9if{_8&3{Vjf<4!hPa0orlHCMuvNM0(aY7FtU>oBO*Z>&jGZv$%#M zwqKx>74cQpVV-!}Afs$Rim)X6fI9}%o#;dCUFWtIcY%q)b(;!+F_O3yzflRd%PA0F zM-Wenp9j7`Z&LD8xYbTs3$k`4sfbj1`-1GF4)*MKc%|)UCi1NwYugLefEktFA<}>m zTkN&zcJmyb+ksK`f)`V0eceq*NLLqpbA=vd6pj`06Rn$0R<)>_ zlFY`2nMD}dN?fauUrj8+f#|~uJ%P7l5YE0jz`R1u)2tYgSy_Ifdx@O*55#;Lz5Qe)I>U|qF@Awl04!RtTTnJvf0&H zEl$s!%-$Mm+J9Cnrf8F!*|D6{I0XOCXi?fenRDHM61s|YUZ6>6iXIc;2V&x6JzIdw~ zooEcX1OnJqB^A&x^!G#(|9!nF`{Hq-HsS~w=df;Gyn22=n|%M8zq9#g=WV^8yMT7- zUETd%-Fo|1-?tsR?sARq0K%8$utJvxdt*S1RrHabM00C5o5rguz=S zJnyoLA5h56ueE~}7Qw@{1*&m0TH3PW{xEVZ z5>^p(Y$LnPycY;Yk=Xt@X?Hkz#^g8#2`32(j0h8%G5IMD33)s>5P68|NngbH?3x@F zTp6@NRcD>0Z_o)<;sf1HeExJf(}WV_H*;NEN^ojS&3vJSlp73ikXio&(8#TUH2#^F zx+HvD3G+FF?nI>u{f%+XY}W+1gfp{GHuocxv;Rb+wz7XXMk_Nq32%x_AroD^k>{v{ zwd)|odGJQb#XfzvxhF>XeGTRH#{7PBBfgnS7b*s>8{6s&Z<^zQO-aWSw-hzQ6w=r!)r;5W@dIk(vJ|lUH@7 z<95c-cb{oHWC6rV_v1^6Ich;*iH3~9aezc{C>)_A{P%m8Ir^q> zJ3usykn0+lR?wN)fI$3v|4@_|x&}xwBnjE{tCLeHu9@Rr>=W1k<7w@ zjZiqcLiipsj#C{KC>v=5#Dxf^W?a-?qXQDXPoZHJ$HJrdNZ7c~nt2iB44%%ZM2;Xa zEmELDwI*SxM0)z_SecM32sBip0$j1?Xs{9Lym2nW{!heW6POuK@iat^khiYG&*xXMsHi9T6V(XibHjl<^(Mf26gd4VSbe2}Qy*=Y6 zaqL6UiVkVIc7iQKB4Q2g2KkN!g`nv*TuRMUN>BmxVLK!keHP;pbeS0+N|%GA(zbjy zv+_`$+F({nx!cZZBDm~QFJ^+BQVdk65-SImIL4BnVPFVUX(k>dpD#3|q5b>L>ST`9Weu5s>5XT_I@Ma4OjqjnsJ@~r zZe)##iP#g-Mxw)f8Q4n;H8HbdL5{>Xmw0{e>p|I)3e=P8YO?`ztk`*F; znG3o8B6zCH*Jn>rYt(d&WUw+qHZ9p2Vyin@hAWkl7*L}3w&@RMH(<9%o$%*pq1QA5 z0-H)&D~zK3KZ}sG*68T98f*B6ttFovccVf?Rfg@#Fht(tNrAQ6oM56k*2EhBmV^>J z+vxg2VEWwZF{G_*aLg5KB2cN~k-Bgg)-^PjMwvmnlOBwA)%Lz(N8<%f=>{*4HObMx zeqg|jNPGR-(QP;yx&-le6BAGb-VE96xj_GhOecQx;@;W2UmJ^nf1iQDq+v`b=(t2W zF;@p^@;o1aiicpBV2DbJHdg-NtQt z-#ZZUZ=`1=%K86(4__gR&;N1p2*xYe%>hlYC%F;k8OH+#MYgBB zVIt)*z19VZUXY+=)yTam;_iIKsD&6~vP9&9Hp*|z;hwuRI)4)1$LER=mT9H5Vl~UC zOP3{;6q5zyx?rsl_owj~jJZHq^ejW8+MTef&ADWjB*rn*2gYI*%$xM~ri^KQ&go@8 zDkiS-_vTa+u$p62=}TsM!&s_5zqYhZ4SR?A@#SjChA4r<3oK@eD9%liz1JzgPWb5o zZw^clCr`f)L$V+$$sXtdQZxDz0zaw>c%pD8Ezuq!`W1a0`C&90rhol$6f*r)q%V_B zG`Tpwo#%7^GVISO=bxmrkXoyXkrVREaJWpZPaWb_C|W$+dX5Rw?9ok1Yx|XD^FeSB z<(wL^R6n2{EAzeCR_>XOZhAdv2{)<8JM+BMT=r|Eq_y2^*}v+`P3OGnn*1xPy3wD; zh0p)2=_0)6wQY~mvl$q;>BeT9m?;#Y-*$^ad`Y?M(}`>(rTDV^C>kVH?>SQ(shHIh z_}Y1G>H>(3SEKm!FuVfla`Rd>!XXfI&WEks0MA!$1bH(v>hmw%~vjle^Tox z?FwiisZ#3@D7CxFsJfc?|JB)S7~DM>^FyD;Nm#-;iTCMX$A|kOU2lO<8)8iO%8wU= zIl%{RjFaI|Kz&{632FW1e%vE|%p+bL=r;X~sQz&t2qQ?WX_eV2#!1Oln)g(kl3NcH zzKsK$LWem?9@2r9Qw`X`7sJ6O z?(9gBfwzgGpjvl|i8Dn8Da43Ugu$~EsDqoI(9@b~t5BaM__|Y%9=S~@b|>2uFKgnd z>|?Mc5-^Vp6+^I%z-8+;L?B69mJPEB1rLL>ftdvy;9Hh;j**dxP^dA6L#U$Js&M>Lx3}rgqdQddLCG%tCZLN#p@7%O;A&bC&T&J{L}pQloSY*c)~0AI&cg+xydmr5F+b)_=YTREg%Rp0ZxVInYu(S@oQ5sz zu7q&_IjON5!maU0l%@EMhf09@Or74;B@OdEVtPgs#$1y${}Y-D4<*-G%N3Kn_k0p+ zUq`P#DZYSjQ=Ys|8AeuLf9Jyf|{$rFz#@vxs(^s09w_ z9S-Koc|f`K7#CKUTBW#q)8FFpf)ge5+UG9_vTaiankSGn?o!U*(K8kY%ejGu;?!*l zLbI*7f-Zo?p6G;_f`qKst`XaB3SF)a6h7WGexE$v0D&vBu`*D>NYjUzot_;9zXHL$KuP+^sAODTaC)hQ}#$88RzQ3 zT=DZ|oBv|Nlot^D{UZKvLP)`5Ubp>^ zag}-gFG67XA3`|Io{YmAM-IFHM)Pf9uM@tTR>C+vi_6O?B8`ujuD z)YY9A@KD*+CA>i_j5d3oxU&d^Kj+(e)ODf z;PZ1deXOA%0OWnhhxkC$AQ6seO%;?n)mD`*NxiCCI)&!CYm!|qPt66 z)gNd2JfjBRcZwtZ%7$&Qv-SblNIuNa?(EmJcV3j8dgZO~O8i_FYBJ=i=<%;-#UF9B z5_{Nu#a946PLm;C$J2TBv_jPPO*-wX>x@Gsm^=roJzsgp(I)8x^ z<`rw{*}0VrSmhgf>a(iq14Zjy3qDnh;;xEn_I%v}7ymjzv{g}`$K~#PgHDHi!e(B_ z*?!`fwY99MXl5`ŁdCyycRJSr1MVw~fmd2XHTY6fJ03k^kT2#SedWZtK}7wc0I zZY(E9YKHUdsxTlTjx#JpN-s60PlkF@6*adxY?Cv!-oe5$cw3e&h64M(`L%KE=)H_# z@E=E06jq=aNJc-n+@8$n*w9iEs+J8)%LkoJ?c|n+4H8%V{7@Y7ERPP|+Wi+iF5)l!{Tl&iGZ)|sMiRgw*M;%tTGKkQn26kE5%eJUOef(de}Jv>j|qHouDMW_Msg<=!{WkbyzzQR{XUY z!(M|WClszEG_SdoH@QV@Q@v`gPy{*l&xY|%ob{gP$~rSrL700B#rVr+_RE1_v2oLY6?UR7-YtxjNF8O4pE@hQh7pWc{O!G=|G)alppf0 z#VDjsuoc6gjw(K~=BD;=H}j>6juN-mdZIal1#&k{WrbYHM| z9lBMU(!}dMn|Md5d^L5BTDexR4nYbF#{ogT43mli2046d5q_2BO+FToo*0yH-Yq+M zCC!xzGh-Zn-ZFy3s%stspDXj~{+7@eIxd9KCs301bRW-egGluxNl zr??SOCZRL+1aT?nptzm|J&%u;XgBj*QO%oFW!);Abl*#fC*e`UCgQhNVMmP9pb&k# zW4tiefd=1iX(&3EzKy}zKYTjA=BzV`w>_8347mkMzK~fc5PMqX_P2~=bjk(Tp?bT{ z-EVwZy+}bUn}&ymOdzzK9xF3%y?JnBW8f_8{buapVpAsY4KS?}+}pRO)RFY}8BkMe z1o3?ak*SS%V!&~Ra@~NjPH$J;Pbf&-8 z>*6Q)5iW7Y`SbL0w!hEU`^sp!DKGH*ajS8!FVOdWSI)W25zpQ8b-61**iQ^G5vLFh z>{l|GbwQqWv6&fJB!Bz5i2q1-sEG`Z#?!f6bqc>}Qi!Suhp%=Wgw|v4e##qfBb$p# z&QJ2qApOIKf5%s!D4saQc4j5DEK-JSQtDabHhj?`g4^8iCJJD^?SoUHBTiNhXKz|{ zvlhP(W!psG_Jn08fp{HFv4k{L!fb5x_og&%n=3AGCO5s46YSc2mJ8Lw+taxi&u+$2 zE*g~#pJ-$s;7_0u?lkn(5sJH}3q6Z9uGd<0&Q_#D#8C0T{0v`aY%%DU_L@7Y(6ky( z`gxAM5rH8x6q^3^W=$)Tn`bEDju+m1y!t%NoLjhuVR;B zY{wk_uAKd@bS{wX$xf2n?N(6PG)V#hyEiQ+n`#@X^|?!Cf31@lRM_6RNkQ~Wvh7Qj zA5(d|P+|Y=EqUn)--&(er&+x@ZK(zRu)_IAQ4R1ZwTRy%tmgLlz6$7)<9`9M^p5>;(!KkNG`YEhJ4DI3mZjtZZ1#ich# zsof;cb}7osvaJIbFWE>wS-6GHe#qQjy*kA`8o059iDeF=Hd!=J(a0n$L89Ga7w7YN z^U%HyZ@TJ2y|hN9BmjCZfR-g5HvaPvAwRFkkVfZ~RY=k~ip5nrATO4HqU$o`0go;x zv9*-WvA$R^b8E}*1`({8tQ6X2z<5^iH#z&;H6(9OIXT5eI%}H)wlqqa-MLd(JD{+A z9h15~$IOEpjBG-dMXZ%CGb(bX88kL13B4c(JZomz#F$xsG(Y7 zRnz(GBtB^yy@E}QW86Zp^qSA)6skYkrVYDWll-ugc$BYZVJ7r0N8&2F_^I>{c_QQ=fx}L zg63S#aCg-6W^Vp4(U7U10T1@3Q6H@j*LX9u-09Nv9K90LAW2_#{suh*c+&fUjnRQ+ zQ{9yI-;qqphn|6T$AoPA1DjzH)(H~$UO1IcD~uGCDTG3byZM8p_&pa>GB@Vv;b2iOWLV&$~o;Q{g9>!BHefNxm zD%AIIYh*K;Ar9e_B|eBo1*cbM%)^$4o}?k7&JihyUFSqwpXl&3UudyE%aSd-&VrZE zw1Hd=D@S@7r~y;Uy{6FtoV#WjTgUs{Wi!E_|K^b1SP*R{_{u>O?F?ztaH~=Td^A*@8 zG@U-%QJtO4Qqm0}ih$%N?r=1K==OokBC`6aAJOB0UKV()|C!dFX z&Ks9s77<$Mx81%hn&~Eh?hYPe@I|Dlv`1cGTEVeCcErIGyMC&SMP!bLPl@4m;UX{f z%eJ^uZgI{(s$Yc5W$P>>%c1i~6~2su%+m9|&a-qvA=O<+X}%oW3|n{BF(`ENQ>V{w zJ6n5Ctc^MrDOc4)k*ii!h$X#j1uW39xRQmO5xiW?gHnu8o{Upc=leu;5kT?y2wOi@ zLRu26tPrqyYIn^E?}`*fHW8>p79x{?UJ<=F!c_++m`s(!ktoSStUz1ujWzspb{Y5d zj&^4xLR`B1?{a+l+^k)K`BZ1NHUgoP@?2sm#L!9YUaf|xQdO#(IU8_d^3}4S#$&6f zW*$n8BQgjt#Kur5DSjjT-&|IuKh&ZE3=@SC zmRoI+7VmJ_;Y8q{v`U{kUl6B$#MG=!Pdiydi@9?K?cMv=7|N1P;@%v{7 z%|swKUThrH?4{#ywTgW16V4f}ve`iVTlI_$((ji*gi;!}^tf z+~=$)AgY2P9rW18lh$fGZxCDCp2*0kK~1)1=D}h^Lv37^&Iw$BUlYP|V-;oilSFh|<|`@9~R0ju{zob!F~0(Sd)4xH!P?%Rm<_WF9g znSMQ9ZNB5Pa#YFkM!#E@8!eqD_UxxLYTk6|xV48TM~CXr%TkrGv*t<4i7WIns%UA! zwZs=!*m~u+Tq(m_jI{d&Gha|SsCa9gYnImJ66lF+Gg?}C;mg;<2zje^Ur(2Qcha5t zn(^x26DV=ZPEQe^{{n<{&wxF4a)K=}^ zpR{P9re4^4fp+86b>!dbOh~159ajF}|YWBD>M)7D!wgKZnk4C4&t`VFv|$HnEICxJfU7?!=rg?xRsASA`8G7hIlAS zgvS&KH^`lYf&Mr3>M~*upVY!IfYlh5c=&V&H)LX!9%G%7wKB9_II?J`!xy_EkY+*H zO!4EPt_Hc|Qnr}KR9pk^KC>suGLadg;2mj$1mQko*gV3}``>w+vr*-&?a ztS*_HarBx;8E)}c*bIyQfr88-AV7|#gB}67-?*S55Mv2+E6t{b&_R2zEraF#wcG8v z<9 zVmg%uvDFAkAXi!Juf~7-^>FKgwN2lh*&+YIjl+gFp`-E2AfqV-YaZji**7R%L@B|x z917Yr0l?RrLq(=cIsZxwXJy>oWsf@QlZ8d;lohaLen=MTt~JFgx0HuE zD5WQzeQ@LJ@=rZR^SO5o=dohL%OUuV@h{iE-@Lfvmf#B*Ueduu6qpZ-4OK_^9tOz+ z4^u9afFRBf)$Ei=63qR@^DXqqdYW5VcCd_Nr4&566d4rC_kc+n#DH?a@q+dRNoA=YDN| z5{Gbw+>{%+#!EHonOjU1dz(7aFB8V+b&r#3b6=n;TooTT>HU-2;&lDTY=!Ca4hX?d zq|0iD@;+1P@$>qqRS#O#i{*Im_-=MHI|P(rr!#%zgrO}wHXhGwliEq}&7LPbCp_JR z17;(YcGhV3%1X=7+pV_z%_5TV(NLLI>pfLmO5DSpTHDCGO^@s9x<%Hzci+O^Wyo0pbv&yVSTa9J>Tr)$PH_L;w>Yoh=!L3 zAjIo(z8*|QLVkN8d3bHaS`W`0wkaSA+F(9=I%+vXDkWK!cPKpie>L4D{xdTf}qYynDR%w9kh`cFg~L= zB4#{I&zI6s+WFr-%gsBW)9=w)5u`E%aY=wBhmqs8Z~u_OYj+ z6&R~b^+1I(D_LOu*tt^Xnb0Rp0s+7&)g^$b6n8FQVimC@hqVdkoH?cmhqAZ7xaAH2 zWJdI##?J&@DHnm8tG9CBM&!si3~b0E z8fTJ4rNQtCVo`5)ijKyLa%*Ri#{9^v+RtV(Y_o!CM%%^=Ah?sYOtB{iX0I*wW0uSe zir8fJ`)E7brwQ;=>S$V;Ci3=5o$vgYC??wc<{h%@C{u`!4mDNKP91yBhJcMd$J~)n z-dHi37u`)>w)fTC@d~|j$1H8KcjCu?d~qJJd!Xkta;X_1Wsx%wW0Mm;S(?Fjg^4Eq z#$KPhcV4}`fw>a5de{7t%A#i4F$;8RvS?=O^)wm$6t$l~cq10G4zqgnSuXiX|0nX< zUF1a`oB1a!wD$OJ>U3zd%RayMpC=vbl?c3Szw8OKR`*N4KFB9>U*>jG>ZlFbH>3w=CqAztg)Y%=6J96OCkVsXczEX*QZWI>gS6(mg%&)YPFMlNf;uq3U;UxA4yU$17vs-NvnNP`E>6>l zTDk|-sZH95*J)APdv2xbtXR9VWI6@*5AsA#-@loV&hRB1LnxDPERz}_McFXLT$MG{ zhwUmr2?di=_jl0hI4+>G<;Na>O4PvKt#T?36sh>fniWW^07*>ATFiH>p72RWtj*F$Y-X2kOiWljr^MR%eCC*bTcb(|o zWB`26Ff<7}to7Yw*AT(!B}%pO=dRz*ZToST8I@qpq?xZFS+c}sqKA<)3x`Ln;9-N$ z9Evr@yy2e%imYDfj}oe6S)V6ClW1(rduT3Zn&&T{EO{~n0fNM!lzf}MKAGPW4}0^$ z=@2%1f{zwi64)wDp5I(?hEZ&$N#-0BX`cZ&%%TEw8#bNsl$GNw+C=Mer~IR!3R;l~ ztVBZH@kwalz&GYaIpR1bZd~^7~RFtvR1Xg_mCb{RxM25Ly{}`MC z3|n^3owhfq1<$am>T9nKTft zis+g4Xv}e?5u#bf;JT9#w!S)eS2=Dnu_G zn4Cz)VJt7C0-8?KRWr2MI`q0k`G`Vq%ui^jPyp2&1eLPbs`YRkMl1QahZ)qQG{$o> zvhyP(!c{>pDUdW2UC8}*x{@P)G)ADLUhe9NaI+?uumrLz8~9tOhkFx0re#4PEGXiq z8|Pd~E03&n%XTX&l~qH)Glu5uJDAWzx&{0Z3raevar0J1N8+!9UKP#SY8)zcvCyN$ z%_Jt~!?XEHazGH!WV~QW=pbV<$TQ|mOljlR1#==yJhk(x|IBHicQ`RDQBV?wSb2Sj zm6aLFY*U12N9fRfI}yDDbRU2@krCp!Jm5mALy7<<=IZo#^JD^Z#MtoM-w5iV1YjvSP-o!r!+1>t%c~B z1>iHR(2Lk+yS3MbJdI(+I$^mac{H;Xr$2e`J; z$75y>+Iw8vVJsFeX)Cnop&UB=lv~9~aj}Q|0*usV`iV6iXZdW{3-{h}j$@9_y4nM? ztfu`yH&#&Xusa$_y1-vMk+gR!tSY+FF2#Vc5DcSKOVm6q!95hcP5dWO7ga9}-}hKr zlO*!6Yj_q8Ox5(8+FiwR!TIgAxdgMz^-)fZsTPf+5#m(6>v1q48-}Mw0!vm|-U!uF zoM6~jq=yobsdE{0*9qQlCD3Z!Xvohbi`F; zV~m>*Njg)XyLbH9lFV>XfR^>{5^4rCE7WO#Q8Vqc3Gr{0znb@*_0@AqN%zkO;L0 zkz`+=I04dl6+#upj+fg^8hQ$O4UQC|$?2n*Y5X6sFu&hcYi;*o%aL5$37La&+4SL@Az zVe)A2cFXGneAb!qRas!kLjDh)^KZ#!2ytV?7>BevSFw>_R&4-+apE zN+gi@N9va_xhu5JbP(S*jICENkJUH^ddJ`97$M$|5mzg>cimNgMw`yR#O{w{4t3_` zmhPZr+O%uM)T@k|svDa=_SLBBVufaf{c5|rz?e6+-cB1RH!ZUPPMq|-`6;a0Qxk2z z6q_r4DBZBzA-g z*Wf-L#@`@iEiw=V0d|f}mCVcTte3hvlaQ`zxRhHdru);BX8W(xyJYZdv)oyN3~)xHW=Q zk7_AmjHdWuYKSb#2!T-vS@+8Qy+z{JP%OLX)f7kuT@2-99N0=l;L2R3X&0n{f}qM2 zpfm+EPw7?d74$uWbc3xe%YNr?rD1E;<2HsAsgahS2DW{MmZzWYVShgzxvE|5vlYRf z*qC6V4Mm*J*Ze%>SG5-QMwClwNy=B689e-gftkXAk-07$=-V5}Now2|TgNM;l$6EW zs@$*-wBF$t{TF#TSR3{crmm%#GWVOY`w3^yDRi^7LMkcLXe|Ui`lppp_IRweiRHa+ zZRNHpM$%XwdvYONhLC7kP7woB>-$*Q%9%{M+t@8;l-Ub$T1Ag$<&YXrjVIIfgH~}1 zTzIisoAM>*_$6cKN5ti+nGs_IgBS2qImH~qt7aAB#R>|{t7I|xQ_@=bX$)1HKj!w7 zU8H|YTsKW? zZQq*J>g9b_38yN{+O+-xdp5WxqD&=0m4#|dTf_rKr1{l(Oz3#Y*Qmey#EE#RR2NHY zFgXN@uxZxybF&CF=9E(wmA#xw(Jf*^RD@aR$zw6n{p!PA(X47b2JUo5Q8#vurHBtj zWt8NgePM3ERgw$sB2ZD+?e-;xv>E%-BpWIYdY0^*pyiq{NRHpN17oUCUoWz_t|VV9 z7FxtVmjsU`sWDesd_uvZQT1IZ*L_sFl#7gtWkV}a`IzDD0E?C?l`(u}a-;5`u4p^; zUcElz{?Uw>NZOB;NKQrRrZUsP`i+#$M=LM}7YY?Gk;Cp6I`NERt>@~k=+pv%Y0;n@ z+I3xeFOm8fc)Ak)Fv#VeN_TrW(Xb2&A^aVf6~*(BKs`W(QM+RFGCe-f=1~ZS$XbV} z49fLO|0oMu^x5Z8znQ#JQ}QiEma2Vi@Ug?oE#r|vPdV2u!*mQze4|Ke5d5M{V+rLD z-<666rN@TQX$7K26zP;Ud6Z$1DZMD^{~xaIv01PnSr_o$-P^Wp+qP}nwr$(CZQHhO z+q^w-ryQPz7fx3WXpm ztJrzc%`8HE55&^3e8nX^zsZ+0JvJ>*m4<8Zsw10fuy3npbm-ElO2`rgw*zGAh z(s;Q;5)XT$qN3MOXz?@(7WP8o8DQqBi?PkaZrYtIBT(FQ*!jN zDAKME3GV0I{GeLvQMN6>KwJN^(l<+aAlP%3CE0aN0M}Zy9)-yJj_Zpbu4t%&D5)sq zj}DWgpqkClO6bVWZy6=!^GcsQlT@FYH`uDj=v3=ok9XuIAvDRvQ&N_OogE{2qCWzg zqSD(_80>4kcey40xy9twWos5!mvhV4_Z&723@J9F#xTiHjvLWy_S3o1&bmv`?u$;f z5};1s3%`7Y4x^HB%ali#D&5xB(}q)$+Kn5fvV0hN;Bi-G28vf6hm*Mt?nZW35O+VM zevP90>KIF8O=YnfGfZK2*HDOFujLkzt{o-OyshtgdoN*R-o&MVuc~ib`(BwU{e5m` z0EPkJEW7UQS_Z!b&*E2EIenJ=7AcaV+_`9c|B9?(5^D#_qizHykj;Y?$h?Y1IyM5R z072{9L2l(&O2b04l_jRJ+o1~kIYn0Q(EI5XB`s?YDuK?P3*rDcR8AE)Q2^SMRu1J~ zb!t(@j%d!JI0TZH^Zj^u?a)CAW}q^qILobDG;LR0+1E?a=&NQZPpilB@QjQw=f94x z>XAW@D{@)Q+P&C;QfRV%`DCp{AJ$iOkmp!^URmXW-oVl;IND&>B#uWF!`8X?i^=BZ z5)|&3pHdGJ@KA6JHn=)YU+2!V!}h;$nb(Z@tA( zgnJA`+k$ksom9j{HEOBmMMCk{SgP_17jU2i)B6To*3G!(e|jjzNMYIMnZF(AM$$Xm zoU6r9^eN1u)@|qbb2`k0BC=;`&%GnW&}Vio;@%dnO6B5$m!r(Sx3YtpEc+bE%dO75 zwuKs0X5Us~oA^?-NWdSGo-71h>$%Q%aO37ZS<*Ae;!nH32y+;6#QRc zDNqeUs6h+>Am8{uJxG@S_8_yx6Ny@#M{mE$FU&f(k=toS)01R(29(A`N7V|5Md;Wd z6cPq^cY1$4$0~+Yl9#s$LLZol%WtTN?f|;H0eikeeSbe-f8UQ^aeqz+eZ4=QReOK$ zLTht#dftXrb-xZKb#r{4?_qI!zu!84xxYKUKNokuPHbg=zxHEyecj$4261`6-ZOD~ z-ru$tdA+};LwO%2VM~2HEOKS$Wifx7A7+46851>96y{Q)$Y6lmdzc0R>OBF%ExcRa`e9)gI3r7PY zd7smCJ$%l;IzQdMe*--t8@WWfe=fW~4CWQ9X55xC!&1F<(2TmTJ|=W0k83Y&k*(I4 zeYF^%Pkqw&pAB1SrWyFm*+X_yNoX0vpiOEWSE~-Y(2RS;MeymO=x8VxBN(#CqRfkK$!a%J z2_g!iTmlH+2uG#_i*82T`gG4N+^EBe>wcYo^7?Lnzl17s2KJJ5OrIOGwO)6~NS5l$ z`-9L68fr9|^-IrLo`uw#chu*ewp*Kya}SofYh-}Cv(+8~fL^%U{E1-|)w!CH-fdcB zka^^&rPd(V{yQ;^54<#;qpt#~(5;?Xf4Kp2maSVH8yEnXH`tz@(UZIBqcvK5ICus^ z*4Tq$FK722MX@#j;clz3VXtqID92pb?9%g;EMw_h{36_S$AWb2Ze-l)VlFS#S#r7l z_wCKjWcjlhyVK;Rv?tr|69=iK^wouAJ1zXYo}Tsf82Gpp8EOTyGDMqVH+P{{|t=9{%jeW7`MVpgp3GV&H0{R)DDV@;xB~!P%c$e%Fam zB*x#j6sFrX{jO=mY72Jy*EW0U&VsvkK9-K%=)HA%so6oP-!^ScM`q=md3!*(Lqz{76D=7WZfIHA4{H>+^ihjxOQ00E zx9sMY9SD?^nGXH$ly1nd$W|0rBWs#0b za&e$Jwcegr8t?T`b4y~kZIqyBLTHUkSkW^Jp9s=3m6zxvPNert@VPyO<(Y<2tR$k@ z&I(nYRh8&_sh0bOmx-TQp6cW}T`L6u{j(g?RHY$$CqEWOXF0G~6*+*Obm<3tm3*T2yDl3tMoOz3 zA%ybhfuyZQTF^a~NA6%>!m$^6T?$TPH#ZYy8*Vl3x6U|$s~OlmRfdOK3tbLjMlm#l z*H6c6GmNUd%Jr(a)1^x2)NaHi!({6qZGKHI`ze#NjWdT+>#VFQjlb>dZI_z!Dy6wIfaCM+NbSIcc1ebCt=dt-i(qdq61s37UUfI9<)hdM~5-)B%6`jleFZ`HQM*)erRHk*!v} zmGxkNG|GJ~y*y|H8FF>t@eeID*;?i+l6rd+YL%4`=Vm7+Hw_sb^S+N)nU-Z-V9OXY zK4umdWX~LmGgN5KQ}GT{#$KZ~olFW~W#;YiP#0-D(S=Q06<_cl^V5<|GngJE6E+ug z^o>V4XUj;{q~8vEbF76@(U44J9>J&(T&-JRFr-=uqG^JJIF6!u2I0816v+AhPwP;9 z8uF+!HDP>@#Qu_l_cOhzfimYa3SEi zW=pjg6jYv>qI%r$=LE_iH^a=8{6SN+mm0xl$>Z|&UG*@RIy)e4G39Hm?Ft^*qw)qi z50?)%I~2nVy4bn)`s);s=gsVmhs_CAN!RxxnZb_Eyl+eNjek zOF`q3(+H${y&1!jlRSV&ZpFu%z&s<~9?@CiWh`wHXF*4s;Nkg1|X_%=9QE{;ygY24zMYOe}~IvOzCse&*s*|FA3$11@B<`_Qal5 zrYGmqJ|nDm0=Pnof4nL#aXv9&K3NKd?Pq6(BO>Ub0JQe7fM{F!QtTOa0JoYY)-bVT|B>wgB6(Y zrl@{+pFQfRvk7Hs{F+ZT+;vS}`Myz~T^6w%=}0lpkf*xi4Y!ef~&Tut!STR)*f_&79 zhQlhj1|*?9{OiqxA=QRa(x7C7ZaF;iNy1qJ3_TYr)?*Sra$JIWjR6?OfuwVK%sfL& zwGI*AL^m!%f~mKrGggMuOHL6}?YJtV+Qi|GgK^O&3N~rZI5a!`0Hy(dF_3?4Te(a( zR)&ZpeM?aqmCYCIuHfW_3cheVBOtT@l?DZHv^)7Heh~a!SAxW>;sp}INK|em8TNnC zAffJG;wy^O_~f(}qdAB&>19>=UI{yDDEHst8Q3rK16kEchE2KexDJ`w1-eA;tO?8G zU}K;Nqa;a)&4;VOXHYad`spR=oBrhBU03LAc~UXK6W|DjV+eivk~Mg6tQWA{0K0UV zGSh_U?*XHpyc()nz7<{D5rFnnOSVi{ZTr*VkGQ?X&4gtl+D9-SR;vqKs)SNnH4*x!kVUWjag!5*&Uz4B3b;X*u z$CMcm{55WQX+Wc~^i~(5W+@MX<0KC@va2h% z=QQ`~Azw<=3(mJ|=>6bsvh1gh!~PS}R*kJ&gUynu5SJm-mS?XIFlP9a2##WYy@ye> z0$vylsmbZI0vhlIWsJr1GROK2HHn(E_&91j<+Wx41 z`$!Y@v4$Dao;b&oq4Z5 zD@m@Vl{6B+7cG_F07oA1<Uc65KnrZfmlUQ?9N%c zV+8&yH$&p7PcV+~1LuR$12-dq;gCvD2ZJF4l_SUEMM=%%zIU`=FD~!-EU?@J_6Uo5 zdbQ^G}~?1BPMEd?87ZZ2vd1`-k#!e<2K6}(1im6>wdSxoF1dqU7ohUIS$9TGoQohG$& z{0Q&hk7CuQ^8VZ8VQKt$Kr1e3+gC)^9y|qwqdTu5VVB0vuNc?-@|}=8e%%fFSM9tv zgK%+KlSjyEp@gL{Ntf`jk8kmJ+=FF1tuH!HEbh0m!dsdfk%99x#FA}$w7nP?iU=j~ zY*Dyv-F*a;Og1JzS|;iKnjS)I?fKWXJek;|x3QABH4-{;j$dZzV_leFsF0r##85RC zCbj*~)hekXt{C6UWw&ciAU)f##PpasfsFVcIC~fY`XNOw{(WRS?8W>YBYv0o&sbFZVpLi^>PPpm8*K!gwnkg3d~PB)(!)+#0>)wX!0$oTNU} z7WS<$wXgi^NN@v$qnqf&Mo4>+b3#rg<|0W^K;xaL?n&-O7j=!O9oAt!iB}(bk3@7G zE`ub@1~mc3pVtbyQRSLI2(b*wT=-|Iq2&5Ljw}fQU+|^fP#TpQd3!{qHUXXE;r~ z0jQ}kqJ(@vyw=O3kJ>CYW$y5cN0Y6o`nN7FR|Pp5Dp$xJ>){-s53U8}C%;|$bRzx1 zk^%)_l+P#Ie=VxrUGJ}&--JfT!Q0=D?b@E-lR?+s&&Ae#r=OGaN?z~ZU0feQteVAk zLX^-z%R(TBEp#d2;!1{)t1e+I0-~vNFY#nMS09y%ztxJz?0~Uf6i`?&7W%^8#Cs67^-)fP5Aph|w1-v435zXnZ3xX!#V|OgmBG}O0AzDrye1x~ zkkx)#fH%x^knu>cr$#~!*uziFa3!s!vDS&BN#com$QC*c5GeXM4`VH?9rXBK`lb0K zT)zw0qUaRu@UoEa4rWa~!x0m|S9mqRHC*q?_e})q7(G|8^sxDl8jjgl4Y7vZ@l=-n zX4sb>;epy=ed*LuHcI(rxk(_^7QC;+@t*C=^4m9*^6mM+fkpRbF-F_{{H0B4gWx;zMqoc z$Fc{?+lnU_eF-uDL3`B1#u)dwQ<}ggo85Q7zhD;VkW;~PvgfO$EPmGSmNOq*_f$Cg zMl-dDnjayTm*=injaSJX0Ung6`blergigCKvIr;}Dl#fyCgjVxoXEP8D%>bbX7Aoi z@@d%+0PKdyX~FPtpNs0_8Rlf`YNLo0pc_q*@XBAGO0x?B;<^+8#KCc79f2f;0)kTh7`MAuKr>_ZbkWRp2-%^q++#8sT z3ThGS)KcXkP-q8c+&Y%HPRnUI0zCKfbnITD~Ic7cZpfl37c~z9p1; z&WBDjruCcptJTzPS}8mbHJ=8p8uEr-9G}{AKclQY=Pg%u9F*s z_kYD4)_1s@lB6F;aLhqstbjVpjE_x-CF%tssOa6#rx|PH>&CxOx3pA*x!-_J+vT{T zOn4M0z4^PpiU%4jQBbE8k#BI|GZR%Ndt*uu%0%m3j9CXgv-AmqS}MVtbLXPD@u>DC zYeCItHx%$)ttGpE94{+WcTYlLykR$6OuR3d()s9vy|o8=K0v2NUXqDIt#kpsV&NiJ z?!W+FUcu>X71kJQb9dT+$?@iQ3+fI^sF6&~OoDnRngq<&KANcsA~0X3eovql>x|E1 z(C_DIuPKGvl7ZZ1v0@NhrhZ7;x#sjkAVqvZ?89NQ0my4wU>_TJ9Lt1zbgO24ddsR~ zUnr%$BcBN^P6Z8QT0DtGZmKX#YSY)3+XNo(T2*$=_yq6;@HIJ?s7Zzp;OJzgXRh1IA0~vKSyRK<=)hH>`2e7<3H2Pt57_la{p_irDfy3;nivvqM5wEy z{sPkN_2KKm$iof1M_gbbISX4?LtPTM95lfd#_$6&`Ezcsk@Awhp)t(_4K7sOFO2zG zhzcF49m>%`0ql-ofSPawG0k)UZr$!eNh1E3{P-tZns_3);GvNS?_;cB1&+9<(?T1Y z!LQiW5(uKCj^qPm6ta1VsSNgbHs=t+|T#`Aar~V=Mw}&14)4^Czz;3|*?$Fp$&s#aYi`o+D}mBI0c?kiiWY z6_%biyYy_cx}UZU?MEfs9v%1JXJE(F^nAp&vhQ8_oAsaw+9rrjxHHfZ&O`m*fq71$ zVjP{W2H6QLjd5qz`tUyQNU}JLa4r5k1|9@r$1(8I>Cb-YNx(lAK2D!EBSEz-Fn}#x za`N|w#-~kVFuX>GZ=hI3k$w;y@Q+2;Jpg{P6R3hZx1SPfEj^GW{o@90iIY4ut-fex zS=z(Ct(fI1Vv3#f6gf~DwO!p(5we6Q2TnBlp@xw$5r6SgG2XX}Su(&0=H_iXb7;PI zj-;#kp?J$1KzgSMTTpR>*DuHu2gw@^X`z31_IOuNFjll~SYu9u11C<5A1Oaww34(; z%;Vw%RopBjl(yJZ7>xz#(=h8jXQ3{VvxUHT<2sCzBCmXG=1ZPPKQh43i5GaXs`yXH z=grk>yLBe7GYP&DMlBc#qOj)kYFt`>PGSoC=oAV6p`&uLc1Lox#t}<;#-z0CDN09y zIf6fmk?J6f4)=Mt!Z&}d!ltie`?0X33ZT+qsro{p&GiOC|2j_h8P$PFRr_SS)JoB) z#v*vcu3h3ALkt8)lcfGyztWy9G$L};v#nmU$aSgI?U3criIH8%fqO@DG_9k1n#xBW z@PX93F!|u)EOtANo&DJ~-LBa>S?gdQ5L$vX;n*0G?N?mgtc_LtRF5mq;2aHTO1RKx z1D-#=;H8u%l+9TD=WFJ)@c(5*=dtc&{cTjo0H z?tKp3V*GFIe$1n9^LTdWyzVR@M=DMN4Y#Nc9Rk5nLIH8i=!z9M=g_5;6)>i^f>;WK zHGxD~;%RP^d9?QQjPAK}uUdJ+U-K&;(>=-326cXzXh*<6&V{ zg!idNqE-|(bu}g{%_u~;ZqV>YS9Cw!>aiLsL7OGCi~#&^uOb~P@n&qFnsp@w0tJi> z{6MYa3>)d4Z#~fS!b|ONTcn4(vN+7&9S%)ahF;osB$>bie}eB!>=B$%e5@Ey_#|id zKp7EXOb`Y8pTmh!>6J4EW1%KtnPN$~}r{)|yxrMf-$^B1HKlCuM9GU~pvkanPiA}3~;xBei+Z_*(0pw!ciihHc;%9G1e zZI^hKHM5HhYuvWRn2c*?6ic%lim^UT2x3MRR_FN_!)cf$B5rxNq{FD#*f?B?oqnzx z>}*(BF9;{jZfT;8W6|?%Kr6R*tPj&vN5yC`2CG5w-i-%d2MRb8{UTXSu2g=4*Qsp{ zpZOcic6Qv-|t8&^Yd{yu{3oUQc9zD1s4tU zXhDuR?{(4WaDRC=#)EYcw1B(XzK+bag@!w;M*XSn&b(i>Bp!K0650iXrFT5-Bo4nQ-&Gby-i*a0bhUXC!b)^Qs( zP&vNDAG0fL)-D=CKXd!dbw*W^6Fp6?hmlu2T661T5b_i?Ha`EFrFuOYpPt2pd;J^V z0F(73Fxab=owj=#4n?p;;!qfMXYGt!^)OU5hhgMGr{?V+e;HRhYtnu?Bex@-b|P%! zQD^bV7};|U2o12|AWeMhL^U3OrsYkV--lBUGTiod-=1B>zU6DyGY7Au8~>-U`oMbm zLL12-W;8rG-L7jutAhoC0Fa&%NTtBb@+NALRetC;Ew=MPJ{{Jc;fkin`vzA-Bxm3~ z6d;2D0|R{rIZ?d*>u~4#X7aQLVw+zp2wK(#1hl2=Fah5NxVP1`$42l#(^&7!mJh2f zh@T=6qgK(LT(%fN0e=42PJJ``Hk4J)^Df`VNF01rL|%?M_um5dPcPd%+*jZw4Ls$# znj&M=%&Sy*VR28Q$qFQmo_+ZJ4Pu*1h53MWHPAIbNL8@p$zgVoz|Bgz-{i5uY!fX@ zVV2zO8uP@ZV>zC2!)bi!l05WXYuz*+nEi}DfhzbU8B;F}=o3SB&{Z1&*?FFly)mg% z9N~HP3EN%FzzNMrEtLIagG40wQt=r5ZIot<%L_Nohp21hi z2`g%v1T9IBC6?@sr>;Zja}rtizKEv8R!{06((>oFJusVp7aJiRvVW{1ZGz0Gl({1f zP3rLuktIGDyCep4l20TESi9N76HcZZ0rG~~A^+Wx=qYN)I?$2vU1~~K!;NKA@C4Sn z2ctP|JLDIc4%JkAv)XMWbpkmd!7e%OdI{p(Bmv>%w@s{z?+C(np6f$^*=dW^H^P+l zm&G}c`G=2hww>gQ?MxJeoK^s&x_q7d${jxN{+Le1ep>SR@t4(capAV8)4>3#c9yUm zn{4v3H^C0#whGVdEqLkyYl?700=)2KF*I&utgaVJdUlCkP?PuNCjzM{JTORBXnH7z9c^FgUvdtApo}zW1)p zFY!W7qc4zK1AGxIs{G1d;SO+kT7il4W7O-q;=5%r)|-2AFk|#Fh^F!m8(5_oF?FSH&aUY#M$1@@^8=2(;j&*wzH;KGU7&H`Ux2-bI)Bq}6EZeiFrx}@^Ygxk) z#OATeuZ6I9NzI+Bv(oe1w>62j=Hykslj&ja*JeEsekby$cDWc4t{%}DtW4gIGJ|7y zk3&JyAEG*7jIv{hbG;;pIuI`%dmFP$^4&~}d!I0`N}RPSX`F`R9|Eof=K_TDH^cu}3OctaRzV`CA3faXbBD`z*3R|&(jxHNQhj80g}!)ZWyy^&Z>{&IvlS?g^CCm(Bxc7gjusEm|k#7H`f{*{pnfN~$6RiK4!t#z6mmQ*m3cme8=4o&? zD%Etr(qQxFYdVOKA}>~0R?-HU?j=p*Y_nOujS0B@s7CmFZ$(4a?e+upSPMj%Jpepc2l&!6HIhMVE(6 zK4_kXAS#4q5xs*PDxYOnrHvlVs|p7{@Jny#vyUAX6QA}{Bp4ftyMuiTZYVmDVy{@4 z3T{r@-PXF@QtzGSd)e88rFouN{D}p{UmsPg(C(KBzo1J0p;))6)1Ql%)CqgvZ)vZ7 z#F4j@379s{9k&Oyx0T2PAoqVZ02sF(cEA5C&F24>hV4J4iI$&~8T_{b;8yi2K9#UG zJJgX1Jc|zx!Csgo4enp&SrPfgZleu+nH*6UPZTa=BTi~6tc@21>8DMur)u~5JRnkK zg<7(z+UNXh&-MYK_MW(7M5_z8y8K4-wv*#2Xxn|XHe*`6ALRr?wODaD3AynVP%#;q zLOFxTBMh#|1h}*t-B4_E3fONR{x^P2;Zz#a%sRa+qQqJ}GAuWE?2GdkIEMj!B1ZP8 zhyn~rsLMHTVS*g>Vx@IjUwZx*#Z7qq+O*#u zD*VMZD)2$GF--y@17s>-n2{Lv48Tm_!vCyEu*MbbDf(9+Mxg&WKkWZ4lA@$-CLdhS zY;BsMWk+SUx1*G_O|{0dibquoj6Ie5$RAGSA8%87A%{QmC_yMLz3(`UO1i$wqrA$Q zKgGSD9?xkp%zY0g&0Xa-_S;yQ-i_WPoF4(XEV=id9L?fN=Sev(+coTcttN>wT<3Cs z0mtE@NUpQ-i<7E>-I0izSLrc+1|s=a2jFy|?=QB=f?)gNOd>GR4W3$zMiw|7rpAzK z*}+Mjr8VgivKm+1stuYf$ja(f{UB0KU&>crx7n`e{^XOGdl6BL!q1zFX9dF^mik3R zlJ%hN1u)UC^>xr1g5-Iupa;<_#J9{u3q#pnzrKcn%O{3KQoXHT<+e`uD_L2m{jybU zYI9i4e&#|>+1E-#o*0hkGW2F zm&fzNgR`gin_C-q*Y8G8J#W))_jk{?@$0$Is`d@fbHhF08FyR zJHa4TLmd$m)%8M2yFMNDf4)T5GQUEGzZxtt@Pk?r!ZEvlljs zw^fbwftPv_b|r6a77o(4^R{?Qdc|_qZPVSaNYtQrTWEekU23pPd|z0}h3os$l5nf6 zXXKL0UYeQsDvX$NsHv;qi~?{+bRL*~A+O}?aQdU%7c!#UnR||4{cf`}ViiGbmWpDI z^v!Uo>`~yo9XZvrHhXc7O9*vzS49$#^65-8A>RXrsv>sYb-A-ZldwtP#}19V#y3e85Pn8cs>H* zAYy|^s8c~W2iqazfTNlQ*RxcCgG^V(OQzyz`igKp8>DL~gFgF$u9ZKwizK@3V{nOs7SfGl_#( zhn){?xc5*30XFAS?*@)Yall*FiF4W2qkG8<4+ReiiCi}BX$dVI`T|Z zy^k#)x3Q|xdVg`%12@uXf+WcYAg+I?g`5&Vpk%TMU2wfr=$tGo%A+CMUb={f9V9Bq zkkBtJA~v*Hn;+gxmr*QtA}ik?F)5aE*3&C$BrZ#FYZlC0s%dUf7RXC3sVuIwXovX5XJb3#W z$Mf^ITmH42?e$r0y70@P-s=*E!8ZCpXU#sO57N{g)X95(v<%dQyEqBRUpC8(dd-Mb zjOSh!RzMy7W{!+?U?bq6q2bU%A&o^v)tQK85U1|SLa={&$P!ZWOHy|LFB03w81tjt zLW2tv~wrb_1m{L^?($XE6)llW5berR%(N~93i)5i|ELw@c#^ci_lik-$r zZyG|;k_w>RD6`SWdX7DvF_jDej2_sLf@CUp^EQnUE#|9bFI&Ryzc&;q5ubG|oK_nt zk?Ttwr0FQ=ia^w=!bnP&gH<3UN~Yml1?hcAvKrwSyTvprB9ESpfmn?!c|o%f{q83O zNFx@YL4t9EWOGKy!V7Uis=yQ^DVTgHx%B+K(okvWD7UrBq&?AuN0vQm7LIgJ#;l#-Y7H(G)PcBOO0GcJ2@K zQJ01y92mH1;#3PzGZzEDeie)gkX@XlxZBS3z-Xh5&YrSGrCTR}F5oSm(Vw0Mt$DQu ztefdRTB6!!@p|7aoaq={rm6gUsm;>o+hUu`S=s=35@?4OC=vcp9LaHra9WvS^!2P^ z0!kYA^QH-7rv%q;FAJd9=_n)y9d9!c;uG zw_n=-`@W3X6te{&0RW(C`roVezngikvo#Y5{|SiQQ^h;_aU(VFUM`M=$0SW*nos)X zc-DprC5==g&STr$-Cr!HMt_ho5>u*cipl0-eMBG_KgV7G-JeC@p5H@X@AtvZU+>r5 z-R|ED*xR4CpY!ubUGL}N+MciHb5`7+xBs8P^0fJZE9?9Eyqo*;yq)Xg_WE$#$=m%o z*~;tlx&K+}`+oP_$$LKGw zeyRB6A zbx4ywJn4k<(T?8fQ#ImYgWirKyB>P~XHK(4870e!;NG-)`x@T+dPBcz)ZFH@=K_Nz zxi3We5r~>0uM}t_ zd(%8<^>vy{SrN4Ox>!2du9lnC6Fr_DEZyCzq8*nsF@ZD1A(GvyR}?5$2=H=ZsQ`); zf-uA_9zrtF(&ADpkM(m#gn~(}zy0~USq4gN-Yx|b2f=qKO z9hA(0Qlp8AOGCx$@l--G)0Cgc`~DR7=b`8QJGRsV$X6EmSEs{Kd-joz83P5m4Dpk> zL^u*-3#hxJgE`Ja4P{wE(0F~eta)D*2Q%mY4HSH24Dt6L zGgjz9Qy#evD!n2qVg^-kYE+Ik*E(r5QZ~~b1h3|o&2m$2E-6M6Y$!=j;`EJnGFI-) zIPWSMayC5!Y_;aqad$T}o{vCD#YVSx(9)9eI`5j(lkA<30OE1B$$IAWuR;K!T~yS1 zjKXBz1%>R&JaZ}iy?d>zY-u#ko%J59dSeYhn_j999)Q}{9GK?FNA5IM3x-*LyZ-*Ut-&}i{{w+fiV3Jh1<6F;BnNUtwv!)Cb{iPh#3L)`3R!v1Utg2% z7qxyRB)tYwdgByZV*CrWYzw`{-=er1EpRm=?d%jV(4)I1ZbJITfb4@BfJ6?KhHxL* z%I+I^bppKawO5>opfi2S?h#G^QuwOrr>!rky+OHXesi3=7*9!t z+7?lA7}D4(`CCj%dYtA!_+3Kcv5w2l&N=N$L34CGLf`ji4Yj!{{u@CsQH>6~Vn15u z(f@H~W@^S#zQZJGNlrBOkZ!e0sEJ4aq!76V0z0@M;EOqoU3}MJ(h@8MuP#XM)VB$3 zPj!_04}Ey}4}Bo{4}HMOa?e4(0__bE8BY;hjQtONAo)ihRs>h26_p2@OM4tr&HqCm zv?O=ihW|f(5K`>S{SSRe{4agbea?T-a?JEdL?==l)?jOiEX!m}@G(0@QRT|OL%=0b zS@NhwCn6tr2Kx(@2tkeD3|3uWQDh`h#d+Ar3oC(zg)#>m`)Qb+0q}bvGKi4&S&rCtPP}UQuW6b z8?|{Q6Q2;Bi6aNEveYfL>6|NQi*t<JZN?3Fe6<^7B&fl?kH3Ps}EbG>Bh7U>4EwH@`-1}sJ(z(Ks zzy`dsPBO&FS{SXyCoP&HcwL~G`i#{f4`(+#-q^>nj&1~09)qdD87X3>8nrf*98@=R zzW$Z2(y@tho%#lZYpP!DGkbx5Gq10Qg4fL;>}HKxhz*t4k>QUx>VWOuaEtwQcwyqYFwv@Y6 z+t;Md7&FsB%E8KFU;bgTyFXZuTp(-t>^Qm&vc9~&<4NH%8T2IFaL*liXVCCpZU5YZ z5i8t(-2)@6b0OF~G~u&~nY%44%(kqFM@q;>dJdz)P$2tjdPer2saC1!OqhVI?>7|g zQzb{IbR|5KXaRHhT2=_ym=dO-s@U$ThOP39#P_-`AC2X$`ilsk1!Je??4Ol%pN7?k z+toB!*i?%th=C)#wi5bVC$FfhZK8$|zM1QzBlQO0m>A@)vdTx-8TCIYLl~Bm{Rnb( zXxcy~dtXE2(mwq(8+kgq0dzXG;ti9=@+idS%HlO-x|bM2zn4pk*5vmY5ki@5Ez%S;NqrGsMs^`+a@Zu9y+Qi|bb!D)2R{9FWQqj^kqeQ5MiVaO2@Hig{efooIPXQ%9Qfo; z!=qFX)r%-sLyY@=xEurMko~RbCtcM?C~hZikODva)EaZ66!^2g?cz}7LMy=r7=4^2 z?I~Mb^Zkdm$~>Z!s9Y8})tP#y)tjnrRnxKj8_fv5HD&i;q2O^C_m*^P zxg2}F9#`u~!)UK7d3cOfAjtEI3*c*yfMy2oKUM>NYP4A)tfT8<#YJMo3ylu2s;asUXz57VUtvJk2f==NRtvv=$j*zv?jdt~#jJmUG< zXJS*C=u*kb`^F}y4g2h`*PY`Z84YL3h}asOJI!lOAr_Q5Mx(9-!9EEUCLr_+I{&cB zEnALsEPklDz>LT|FkF>dj|udVf-uL^mw@-9hQg!sna}}CCL1dbOfpuCA#VhxKFH!Y zy|2rlcp^xKqADdK2%{q9fOW&G4^$3ACg<_?rziLHy`^9PYE~lm1S}^;_zn0`;@E(m zFUI9IbJK7y^iQ>t_5**4uA3o&-I%h(Y1yOwzs}AAsI8@8!?=awUZBM#xVyU*yI7&c zA-HRCEAH;@v`Eq7#e=)MyHiT(pZ1&YZ$EySJNINxl9}wYJ9Cn3&gSg1FVj9O&f8(^ zbCV5ET){jcT2S&k-LU1e^xG*v77Fv2CG#)}Od1Mfkw*E)4*NY>Hpvg0#e-A6Eflp0 zU-%=y!7i|!Y@{(CA|%9E)j@sQtj3`C9pWnuCZVGR(dbA(6OUX`)nw_so-xcX!Lq8h zFbRgPftI2C5lCu9eOA6z(E30PBUrGdxpt>rrC`5^9dKj2dVN+&RuFT z_6J$RJl(xy9Je4SGs1T>2wV-lEpdG3NG=c%t=VNX<)SYS!|aKGMw@7q=j0D2n1DN* zi(^3gl6WtU-oXnlQoE9oYg;=M<@|_ZMRqqYN@@6}%LgY{qlS1%b)F&TijN`?-82qu83*Cnd?DXR`K;OBLYnB5~qBq^C7&XhdLR< zkfs=8Ge9wNQFilE(eG1kTFy@)g1@f(w-7O6Cp%LLEguLV!bkAskrE`Lm8y5Kd**N$ zINlXhNWypM%eoR3)84R|tp49Zgf2ckM2MiInL>M^g{C21+gfJ{dRwPP`KAtOSQS(Je?Dyc}t{OIg^>IBo+2tkKVXL@=`5}i7%G~w8eF(FrT18zQ zm`c@gga$@EoO5Usg~fr>*>!-y=v|OSBc~Xs25G%ROoLr$ zGM^>FCsN=X_9V`ID#KEd*qpF<7_z8hTVRR6mm_Z@gf<9^qbns6^N)7kM+xca^P(Sz zMHjs(@hllF@uHQx;MEHLjAM+$tS&HpG=NicxB6Y5MMl}11K$1X?_s!ov&1@^5IkZ{6m=opIyx0K9bk*U`RPBj_4?)0mto{lPywv42xqhU@3c08k5$%?IkemG9% z)#o8Kp*K@mv=`QAGe}5ZyeCt2M3MD0MtpHnqhxOYUWYkJM6?tADrP%uwbCYkDQQ*C zA`^<#dGk!eq=xUbkL@J6rJ+C$cz zOhvTDY&z1-9aTe=#r%i?t!^;uRpLlZL2~NQG8m~LUgeVvGtNp$jfG~{%hd&t(B|RG zya+C-49xLeGqMQcirfY5r3lUyY=P1$OT4thn3xS)TJ%nCZRf@=Ww`TprcYDaL_bi! zjaHxF2W{F$XG>9Ik9faZa{xN{OP7=^4SAB&yg~b#f^r^zCZXAlEg96Z;6jPOQhMpo;jR^!+j_*631a{pm6FFQ zt3Rw22V%wCUaveK6@Br}u*tN*6r+gpM+ggIEI}6?dbhJeh({vy!z3e{Y(Zc(@)jd9 zALKfG*N{YZXxDlSd6;~HH5~)lQ9c8(kjgGht1_c?+qXK20Y*&S7#%)!ZdYoNN{p_p z;Zhd1@4-xX98vf7qPh>>}To{^#P1>==Ovh$Il3=Rdk3s}|Dyo}IdAR@SBv$AB{ z_FzSe4#*zDT~J|?!dV%AwbaULEk@4+@VPK~Y#LrX@__4OCAG*y%vdi6BYDPZIgHt0 zj$<@v2Ju!okf@7{=-x-k3NN((Jq^|B7b z?8nV+SD)`Y-M7cd8JW)?A8${6F1s5}A!fwrYEb+`dGUwGhwdMrzoqf$<~vF=pdrpm zA#XLZr-aFAnxM|Rhx17ECr^HjqhGgqs8C1LDIRo$A>IFL&ur^Dm4lhkGib*Nhab%9 z+8x?bm?d|tC#|_=ONv(~2PcNO?jB_+>@N z{jwt1+6@W!gSRO-Is9)#l-q@2_?8_>UjcA~}PJ&X-aQ6gXQRC@AH9;*={Inv_ zAXbFxA6CRSh!yb`Vns|4y_^6jzWsC@d6I+lb`Dg6Jo>g}lU972YXd~4hZZ^0pe6eC z721aC8vRxW_N$?|!u6pWj7tnYX3mC;uZqNniN@L}5{FuvrLZqp=Tea}=DYT!;KS~< zL1Se%w{1MC%p{P1xE%4jL)MXcq8+QNqwUwa)W(*b^D>4KfMmtdc+<5R9hM8O6>Ai| zKm38sZr5VCfn3hE^mF?9v(nL7d{w&*R2rI z6{-P}3!y@a4bBw)LGM{N!)z-x-$*^kCF`)n)vawz+jz#dX<);&t4c2q5@s8^q&o%) z8-B_{ORUtwD;xmjV-NP@6z@$iZLk4_;@J|A1x)(^&E1_+&`i_nB(B1$+qn;pgDXy> zh*&ayTyi9Y*0DtMyC;}Kt|kwe7Rs5{3Iin9S(G`8psqoC!L3zbC=TQ@S9LWEK9Cdt z%C^6MBEY7^cIeBY-Qo~&e(c$x(D6?_qIyxozD8qu(sotYuX6eh4!%?;T4FDjLcwF1>|jOq zKvhM#@jLPhAhfnxKo(M(prA@>@x|w2pZ6ZsmW*@k^pxtcA$gtI^pFwe)#0jerj=Eu zKn`%)$t2HY12%a%o4_j&vY>i!XQ;fOAbWWHUt(&$?qQ;`DM7Cpyqp2|Ug4-E`1X1dpd8^qS#QsbfI}q zdv{#BY#|tVxWDEq`mM#*tIvAez)@pbZm_KtTE}^V4lq7>lf7Eqd$?nhTWFm2)~bGA z5-~G!>M|yIWdAvFtJrYEcB;~u<6QhmSwZkJi9=7N8h5aJSqFkC4_m+VLcb_@Qa}T& z_Ur@?lPt2!o9{rSOmA-Vj9-ZbQ*3cKa6zTNmlPxMtY^bxWIbl0r@jctpv-?EAAfM*Q+o-8N>>@4~U-XY6Wg3qZ^Az8c}11f=XK zsHJYlS6#sVAMb_2yOK_gXiLFkpWl0JgMu1AURyqwK;k}1@!5fz{AjT6{mYU7eET#7 z>;5Vu9P4ICC|;X%&n^V{rzH{f(~_vD=XR_Xay;4hZqUj;wo%c{KGDcSb0<|wLwD6T zL+v?c;ZOuu_25Q@jOw^qcJ4ZvSs_bPS5WCn#_Iv_Gvi2zx)U_eXNR`hY#XB@|x+1xfb*~gn0bzY-n&DzA%_983Q?&+${L(>FShBpI~3( zHc?(XY|L&4ZVDAk>DlRJYtz}|+hT0Sb;7^%)7EpbIUQ0qw{A%eHa<9`?p&Og2NDgR zZw$0p>`EV<59S&YP-9ePO{K$C3naOs67L>YGU9E}Gicm_!{FYG2AEe9qXx^43#h*q zYIYqt&FC*t3s(*g$0uZO;X^}MD|pWo>Jj6!s|+$2MHmU&kJ2H2mK&e$P_m^Dr6h8# zJ3ErA=d}*^{(as6blxSgq-XRVJ+v&omlPJgW%iq-c2KVS zC3OHdVZ}<4>yK8BD~V@$KLFo?48V3-T3T`!R7);=B6u=U!@Z;71ojg8=*fx9K+kHY+;OVucLT z22e>j$(4pb&bWBRZxi)B#^tVh1#7f6^VvMYs>2l>WH`sjBBNl5yd>w(w5NyMDbH01 z1=p-b)ScfDR}A9*=rThgzDU>;OmoJj%kncoSlLsE?RGyJZlVo0u^mAbCHK6fCN?p) zwSegkWQDsVH%VFRN;2pgAP+9>(R&A)`zQ?=_@Xa8Qm3G?5Z4Bai~80PuLcB(O1_o& zjADSDB%};Qb9!*c>{#*zifO+Gu>>k3ktti3yk>>o@S{B?-j6EoIM%`@JrM4wDbM~r z;*ydFcbL*{trS~QjEJML5cTft#-ZYfBNmje2+n-v6da0-Yw1b^B3|H)zK0D~| z7*%T)(}{#Cl3b5VTPaTIB9_=ZGkAP6#x~qhG{L7s)TY>A{wUqvidv5Tew!fy&TXI# zF|ed&i~!8IRk?`x2^_@}NFy`McF@!2SvB5ug(>*zOT-PxR%s#UGGU z!739$KK_|Ws#VC*Q&m5$RFwR3)hWGomp)~%*OpbAk|)#e_~Cio`;IBYoz95Q(tDw? zwlLp}&glyDUC^k{!!rXIJ3@ji^t-}g1D5>;^f6O(zLQ)ZeD+U_O-xY{J0G`=Qi-&m z*wX3THbvAcb`eX)J8fP;h?_-8dftPLfGkNuKfr8o4v#OCf@eiyu*CJkYeGhj!*;`u|e8ouKc`4vCij7m9vu&)70@QpV79f8nEpJYX>?lTt zwMFfSnL3_~Q<`fVYkh(8h0LK_+Jo3oNZWvCR2;V<50m8cC@@!sY-)y^pcaeB6!I4a znHx*JY2|yNtbooD;+)}hMLKehMyC7?^ zZ1N(sb$6CgwFRJfNnUpvFcE~8p$oYdSeE_|$Kv?6V^Ouac)bIIs1|FBw zt2(T`B$f2oN4ww$`4AHjv)eo3}@3BvlR!sdi7FzRup^AH4 z4im~?AmcbLb5*<-wYM!SZU!K%2o8GQV(qYFI;}FcO&v_Q{U#4I|L)EE&YdF3iumr= zjW#*EIqwb%u=C^&63~$m!|w}C(Fn56q|)ijYF}|yhoKBRSKN25ZdlaFsj_@6Wfeb37NSR4mHL=2sQsRFaE=!Cml zt~ucGruqxQ#7@R{h8W|HUGc=EKB%=U+`Xq6(S=MZ2-Z%N0m0Nmh3E_sno$oQ&y0Wm znz&;C}b90j9)qrk;Hz`x&H=?3^6Fw;Q+f+&4@wAjrZmvpr zLXJcB&hI5=dn&CbWOU9%@QoXrC|pgmod}{a3YmmKyxa`JLu_ox4K^xE z#Je6QLSI1NzCNoY8l>wWyFQdE|NP2uau$zMwkihPg~gbt-4 zisaeBfC+6CuPukAYjJZV?7L#kp&PV*>?SH>!KE|$v=4yULB+KbyTnbz=m*Sw&ZM@^ zq%>?^%8TP0v{1bk^H#lX8oKh>-6gZ)^hTd=>E?&UpVdFxK4Onvv5X&P4 zH?J(}Mq*l{WG8ru>yRHhVZ7cK&%N1%@Qx(5z6_6LraJZzI|nc4k#ZeHMV$s=YO>e= z8>wd4OHK({s7S$^;8}M#mSr1W&~8^Ru@xZU%~#T`#EY!smpxbj723xnK7NLy4p$wv z6$VOZ;G$w^OpobtXrrHeg- zcOFml6pP{v;Y$rDdROaZ`goTke~&B|;AUKd72Y?gDyQ2?U#}0`TZtRk+^$n1H_tG~ z=T-_fXIwlHgRIdU8j56@FTr*~p`%`1o(hmRnS>?{!!vBbNgaDBH&Ud5r#v?$KCC!H za^TexmXjcVnd4;B^F`{2bhk5Uzp+M_O4WUg^-Q0RS(`Ls@TCZGmX?jsmL}&&;(MyX zl>Pg$<;&+AD07rmckQ9&#ARPI{F90W__MDsI-Is55{iUhKLW{K43)3;NV-;28Nm&5 zb7aVNmjvzTHywVKopN4%hp$}M2%_c*r09zKv;;K3Ou`=;_BaPKI2y~SB|BBqWc{$f zJS;X-wGQl-fhP;t_0lTYo5wQ85IA6s%SuO`~-Uqg&P65T1 za#Db>vPbN`ue3KtWiEd&)gcO+>ZR_$HSULyPP*_3<=ivpvw73D6Q#Eg=|42eUmy#( zYP5GSqZXKZ;uiH#&|Z?x6D|cx*$tq{H%ghf4&j9mcV8*V^losK2A7vQjhcl_Diy1u zHTLleyvmN=5?2N#ESnCUuq68-8s6g5c)&Im120k$Fpd0?xPb}f=QW9fj;y6jz`~BS z=S?izBh7LdF{F&f%UOle;T^UR=s3Qk1nUGyp@!i54Bq}%L=*N*h`S(3hmkE|P> zJGemzWYcWmYuv9{eC9$l!WeYjPP*RMJ~XTeJtkmBV&g;MlKtj>=b2*u=W!OcW`RWm z%)8jBszGtH1z4vCNrnMJdKaLisWoJj+t?_goez`)|vK8t?kiU<%gBEeF$O6<2lHm z*NG;~Pr3AXN8VkByjSUOmnIAQmSZO|}! z-mR0JE#X54;egM#6%x3rq%@)-3V=i1E>^bha4{*sg0PrR&tHzLjr@uSvS`8PVI_%uSeFu#Rr_AU*AK2r6uGS zK8|lA7%5^<7miC|WmBQ&6XGKhH}aB^)?hGo=7`V_1CQ4ZCh z9XRiCABUj^V{;X9mjg<9Kg9>QEIx zH9P&bKLdfC$5J66Wjacum9%izOn(28fXU9DPKrToFa*PI-B7GYq|^qD$mQ zx@aSzSFeI8&I3aPjO~}o=aVd%g{xNmsHs2%((3;Hj82DTtY3}zE)FY&*bu#YM81h# z9~C-w8+i}GR^fehS`RIpROEzpVjW-2w}xLW9M^O*UJMoNS2r!bY`3^Ep7#U$}l9BVUqOiSxcxtje<(|Y063)fJJn)X5dZ!F+U0ZQSLh5 zI97Ref4cmTWlU%5{C$E^%ypyBCIu&5Rf~q1)-BJ#KnLQ(sTKEN|2>Pn)Kq55FC}yY>bPV2N0)z}1RM3^boe?<Na!tJYgG>iQ-wxSlM;upnc0%} zCUhsBYBe((LcGQDaB&^;y<&iZl7j2Zw}KX5IEHRWlYF*&xgE*QB6qeOxlFrdhE1>^ z%YHC-OudzSL?(P#lpI{O$F4V?;iy|m)BGx4*PkNn!OGBBqclcV^)07@F!kK_rMtYD z;|yJGyV0N(`qz2IFvqmM2ts`3bbFO%Ddr|(N(UBh?%^+-B`fznJGQ^`PTRIaf?WC(i8I*bmbw_* zjd;oEmg{ED9rymc7eFGLfr^F5J)cSjY#gv@K@$aeF5X(wm>?_B#_{Y0TF_kagS%xf zZ(TLzIv&2q0h&I?#-R?QEK3^2eBg7%yu6Jc6p)lhZOx0rYl0RH^uoNEmSx@MT}o-s zRtI%Ic!5_(^?1-PZ?mg7v?_S|sJ|ToGK%WuZ5Y5G|-1@YL@QE zh(zkQ$CH#4$3Z=v)jT{nu&X!+qYP+|A9WhNNqoH}J9yV*{HRA&A5y-U9A zL1ol7x7V!mdn0bfSx~3D*g?&?ETfI#YwzOm^Mzr&QgOy?m)hlvCvtQ?uu z|NWH7&c+P(iSve1l=B4{QXUDiqe6BGkg2J&qlvh!m92x3F_b^M*$CACgFJhJu>J#v z?H@4g|A6862Mp&wV7UHZpkZ)eA+ei~!#f$?ASM7X8S@1|L1Eke>tI7(__fvf{e1ZI z=UrL;KS>PT1gI>?`+Eg3wSFG+e{XeuWsv$H;|eD=a|1h*pT^cx^mQ^$+YO|U9M`{u zz2B%K#Q*$n^w$*hr)&Z->#P-|JypJ^Y$DMgEZhIq?$a>y-|aHe{=xo=Hh-$|x4y2YpJHr2u{LgRW`m$E!OWUK=Pg$KFO!$We43!tDd Rprjm3OvFVcUjDmh{4Ztnj5YuO literal 14782 zcmbW8V~`-*)8^Z@ZQHiHr)}G|ZBN_wv~AnAIo&;NyL;!}ci;WrI~%*Pv8O&%L`D57 zPMpefG9&Xz`ES4=C;$Ke5CC!+{Q{3a%P<7M0RZOs0RUirKNYbva*bSg2M$7`9s*WN~nL)OIRA#mIOd~MJM8O;M|cIcP> z07;1F^Et0}ZJM~BIRCVmeUe0DJrU4yLtB6S?nTrQOw=kwJwra~u;&;;IY}~c zn@-Z#YE8k?f;S4~C*yw)*0o|*Q^LHXg`CSpB9OX0T#Vl3u$tp)9UrB3Sm1VACB(xk z(qh%>)1fOzHrBAg`CvdhXH-*i1N$0~iv6r77XhZUss}1uQ`cc*VxFrnb?$Zn3n#7D zha%JWC1ZV$XcxaNzV2RtiL4^rUVd5zXRtDz;2qd9@2q&#r-gWg?J6wk=!+C4Mg)pf zyqabhlHdPe@to6_wA@TTYn{ypf{3? zdLxBt4gljZVm$KNl4*U_UgCg zLyRW#z*i4m$*OSo;wIE*`J5=}jmkg&&01)4S-38C#Ahss`Fw#IiQ|bb4H5r-Dk=p7JTO5~+q&vo!%WbJR!;k61<}ZL@_avBmIm^`LY+;6vTPy#JUFHhJEdL`{h|bG@O{CVn0N;b(x*1Nd2_EwR<+Renufmx>AN(^kg zpffXh%JDinuVk2CgVwUg+wQZ5p7TgMQAh{S>}r!fn~huh$&y%SQPf%h)Kx8@GH(zR z{BRjDjr|IhblS5;8UVq5GjOz{yi;^ZD!D)&5Cu5P*ttDP%&NvhfKuwe!C2XG^WtcrtZIgF!6`<|tfV=q{{=4cP!=XL zLD{$WQ-HIMoIDprtBzCjo!XIM%Kisyc&oE z7zY*zoRboGELre6{EdM^g1fLN2{6lITu@`j^wX#LtsOn^nk zK^r1{_rRODls7v47eU;5p|3~I z-LON?47;0lJ>kkQ6Rc%MguG+dgZ=q5{!hPp5XQ43ghOmh5Sf_-+)Df-MX5x|Rj8BE ztWEJ3^Avl1%&-_#vL20BjhF^+2PvW_j0`1!XLu5UXq`-~hj*>XB9V(P)Qz1E*HeyJ zxIz?Vw2Y`Ar@UnXk11p zAvCOC!i0(^NfYt{J*6WA`uT(U-2z_<5<)-P%+E#fCHh$&$_D_7bOn@Z8f)dRGLm9Q z;du3)G^4jozgZ(1XxJ=gf&f>-*Z? z`!x=xLlt(+N7M((ACBp{XK=y3xKcwM@34;RQe*9Cm3oM(0{r$xxO{3dTc)~m76-I8!@MsOKWyfcS=c&|Y> zroqZDVAp1+0!+)W-iO!HJ%6e<@Ln$FxR%kdx=kNgGb<7f!f#y!PVfNxb)1MpxN;QIFu;Ufc|+l@xI>Ao)h`&KKQ$W+AUTf+e(RzUKmeDW&$r`GXx@-| z^zW4c8bBiTMS4l39)F4?d(g=Myv-kV2fuCYN zH^;+g^SK`jmyH$h*KOO+%w1VYpdhH;3^-KCu`VoRUMK!&yPXt@QEYCMSVr|yMtB~W ziUmf47@hspxkFSTQiV*loh)+6K0FUKlrZQD z@+UjF3JgxncSBnyDM{@3G>!!rPW{k28O#O4N5Nn+JUBTyKUA-BTOJ5$DdD!>RtDPF zUIrfPuax!mT`YXxWQO{%R`qFti0e4q%K)ftpicTBf`J&!<9r#QFQQ(EW@K^_5V9Ck z*a`{{M!YWZ1tXNkA;@DJ`xK6&1dp@!K_gtosce`%yFnG|OM+eVrmpm zqM)LPNtmcq+j`Cj?W`(1wB zKX!axh0)J|KiEGzK3{wsKgr>D^ze4^diUYydht59pP|!t;XDpFRz@=N=|T0P-}8xC zH9~IxGQij@oX?L_tWhjepewA2lWMo#lx^#>t&n8uaikgs>q9z{%C zTw1LB7OWlJmmW-OVWv~R8hxtvI0_!4q`o89G-`g@O1SD_BxZ%61qL4GymwC2EVghp zWuEl}XNw!eCfmE|f3#L;p4FhM6mRWdw|U~t0NDO~f`j=>qfAS@!C?+b5XaV_B2~t# zIn?pg_%)P`o;`Tuh}~MC3Zw7HriDk7)%iY#!Ex?1v93>(m+LGM4-uYDy`Oj4W^~kM zueo)WBP3NzXuy(v+)iC+^UU12Rx^{Ogb)Oznp-SLKC`doI~X=PYcXVSsyHz3x!_xU z>M8bm=O&nK>P{?}XE+}Sf?5q?toY#u`mx*6Y@M{T2-PJX>}8#;3DjjQO}+yZeM_(y z%PK`rpOI?#HmEItt(z3I*_dFEhwqzxt;1Ya1ra{n90;$bmG^8AB(b|rqF~L9hQX5A z7+!3p>EZDqM+ za3OUW?&{%$%IpNQKiE)WD9{rypw*2dIdNGIjN2eiKXh;fd8NEd*5Xnth&ia)L!KZJ z)=Qag7MDn>T8&5@`0bvfJ?EE)a7#y@wHg|Kf$s}+G3quWlKxGx!Xo^yCGtXEWF8$* zzq_#{H1eeD#X_9+6}{XqFZU?*nk~!9 z+`wpeO&bG>s~>j@_3x*|vJj;7S(b)q-3byL%~KyGrseU6ZeG=t*zp>4nQ~3AEA2om zGeMQyQ5no4_S+m}gFq9!%?URWKdo7o4}ml4sAw;g8s~xp^5%trU>BPut-$ZXX3v_> zc~}Y8oX6iW2Y=FO6t;8n?pQLlkRFe*+TM<;YME$lcHh9T6(4i^Z%dHEz9Pp`-VI-D zrPN;qTu(*33?rKlzQcmKGViN2pKV`0Q*m>jooAifiWTY!ake?vGxgZ+4wE2CVS;+jOrsPV`Z<>q zroMtk0gH_I`>2mC1aW{3;20UiB7=B;=@OVc&N8o-Vi6}@-=)(SeeZrd0|fUJVOoKE zm`6gP>|hHdN~{JBY2?P5P0JT}WZ6Z@EUN_-t;++Wx}#x}B2fqhWnX4tL8il?bCnG* z3r^cYqjd95gn^ECZe57;|4CGYAek1I!pamaY3yxCVr*Cz7hqwcFP4$e5tUR(s#p9N zsON^B?u^S+v^Cb`0|tsqe7X@xmLOh6;kxKARt=l2kGS?Nc7R1NNDh4#fdVQ}EiZli zQ1T~4dQm$JtaN-Gr7;s#k!i?OFqF7iu&h4vFcdb1dZ_RSyjO%Vxv68INXT=iev#oo~pCbdG`CxNoH4pOt>L;hME|^Y+?l3_@32PD%5xHiWh`b^Yh5J_gB{TZrrN&RwP1Vh` zeB)^sLWD75Udd4m^0VJ&|0FY3cEHA7X7@z?l7XXks>gv$O zB*+j}$Sbsbh&Ld4%A`C(8EStJtY_XXFCd8cVxVxUGGq;L8Y;l`tfC@rFH!+=QyH(| zV)}97v_@Ms5ecM5+Pc!;-!>cy;)%}AI^f8W6xkDmf!#{40VKI`L4vYE3T2KlLsNhv zHJ4a`A_xfe>o1We@{cQ`_O~a%6xgML_AfH&s$xpuR0DD*f^?3ny$|_D_;Jf?C_^l; zXs%@_SC!xrn+<~y%}f7Xo&e%I1roGyVH$9A$aHYhH$8PFU4noDR%nvYP?joyjJ&G0^~dw$>D|Ie=~GWMe;I#_pZn9uja>)*4EIg#Tm9S1 zz(iQ7+<;#0_C@z@YO2DTAnd`p_!PZ3XAjyED_<^jFZv=INMZ8hGzDd`56ZZjq9$!J zW)qf6fO5U)_d=`?tfQ-oKGl8YgXP^|_TY6-Ohb8vinwJf$at+mfwBm+gR?{TMu^n9mPSg-5Lm|#g|(khW^JN-mRK;;$lO?rDIee_6^_3G$@-AV}-v+G+bnOrj&F@sqd_+*6~Es ztJvTK4T{_Z=k0pXL|@ptyLm;cl*`XnnN)CjGE=-_RUOYyx&wTw5mqC>J3!@%{L=(_ zf|$M!pN{K__vU5L%*p7?E>sppTiq`*{Aw)7rNnC2J)ZYDsfd!QNqGu?4i1!+qejbE z*UM+NSikY-`>EwdMx9K@YB*Am*TPkfGE1e~;}sugl&jG`4)@nhC?Tv%zL zT_*dl_Ec%+mOa60wX4VVyIGKrC2m|`OResKa8HvZ}UZj?+y^+?nrd zKs((_b8c$Lz2%qzL7>0iwt0#IJTY_`Au!*L|0{H)4$gF2%>z@gG@k)n*I((Jb4DFy zZX1HCdp-?LET!%9xQL;c?&Yn&*G?{9JI39(1Z&Wc_Z9efM_>0n&sm-d0$NtKyYJ{* zc(K8L?zoaho=Eb0mUMidUcXI0%xVE0XBIy|jCiS^QB|q?v@)!kD((c&C1s=kIA==kNpKi|o9;iVK-y z)4w;~<>Q|7=d@^HYa7oF7E=rAF(s?*xI`tM8TVzduQ4w3_DPV+(F_cZBzJ_ACB0v-~ttH$2=fSs=`>9rU$lP>mcL&o+A_J)K;w|5`K8vwPtzcCU5NR)WM6wbj zy)Wpw1$_KnA4d;Mkw~LWDir#8ZF+Trk=8uJOO<8KAODcV3#wjAROPC8TLGK>={yqGYF>l=VkgMy6|Jz+sq@?OdUp>9-r zu}^ZKs9IE3MT_#BCDMlP6tH+Vkl3B`E$vR+S#x7A(|b`@5!_kc-MeNmE3tsE(^AZZ#WgGf^r>#!0tRi%pyNPUZuX_C+IWtOrB|^h;87VTD5PRPPDFB-zjLqH0%I)IzU_ zvW!9x8tD{!D(H&8D@ef8iK9?lyFo*b4MimhACgP(nxcb!O$MtFG03N}q3w;IXEZ>L zP}EJ*O-62=k8{Kq(`sWBsrs?s*t(U+GGQ9z2XZIY@r!DFXjp2$VTnoOK?M{809 ziKH~E%TU}ml<1u zZ$wko)%mLg({5irBrq;lbD<-; zw}>sV?a5@PFdCECa=HiXPXtSDwuHnxgV zABH*a%;z?LAbuxN90xQx0&8WaL2;c%&`O6(LlYjuayU^pB6q6V#X z`^lo$KJ*joNpEDZ&>OcM?VR<48=JY6`AkpeD@BL1<*{|!hq}5SgFH~dZ>xO5$EyQ< z<+2rE5OPr?z$E8uwNoX~M!N$f${q)%g9-qnJE292mMrVJPJcx9m>pS6wE)FtZy%=N z5Vcqmx`Te=lopM-6S2!L_5MTU& zics_pYKkAE3pBSGuo{LHf~X4w@5{Ft7xLnOkv74q;qieUnLNpfS?ok`a%#Ca@%sIKs z8@&T}4=ah=1U_mX*PhZKZ4HDLU4{t+M79R62mGQ3mt{3~#{%1x;13!N07afN{lx!w zsL4rV8Y2h@0ATSu>-?{LA@g6MX0k$`Z9fA{*BiC>rv8ufV7AkE1=~zE*uhvOFw6?& zrZP~nPhVN^M1SNNg+mID8G6^7XEZi^(KEkyGgQ+ZUt|EXgEeDqX@_m=jB*Wp`#yO0 zmd+8g9-A(z_vNdJYHLe(%M@Q~$uKMoj=E*@Wev-;a4|uL(Br(j!u^H@L!s6X|6hvN zin|3sMEU!J#wk@3GCA`SXI8mH&{*+Dv`Esf7knowZc^OFZ7RbgNt!lHFIMnDp-4o{ zDR;<4x-cnm;~$afGL^2x&4YnFj(bf%;Lb|eLXtRt(m!<4`gCopjL;!Zx?ZH}g`OP! zg8TUaz|B$%(JL4qva0A(U#w6XF*jW|k?k+o35XB{YlzY747z&v2@@1e-cCA+bOF<` z7{@{<=k#2P2m?E8JIdz&ghXID_HIxX!U2FGR;Bmv#m099xNQLj05JTW+yB>Mv-};` ztIF76vmyXZVkbN<&F$W$$bdfkc{Y`QN#icFd1`;e){a#lWM#Xs>99VNnt-; zCg60l-0b&!P4xG*p!QzTl!S|Fjo&2lWqHDYaU=tKd}xvYs7ksPGp_Luv9 zm9LhZaG2^#4JpudWyN}ft<>R5QkAD+zWdxu2S_Py8iYRmAdzEz+Ci!c^sL2mv=q^V z8k5}gOdPz#ndHt*trB6`B1n3zkYnas+)Z@JM@`)uPhgY}d0#XyBeM+sX7MDx1g?+K zClp6sTRxcIlw}auDw*!7-)CK$@zH^AP#s zBXb^G7xS@L@oi>L$B>^v8Se!nWmdv^tabq#>cxNvxUrg^?2sE?wrN7#H!Qr+ zgB~suP2L*n#ZPxyUSnWy;g6jJQqi4=_~d2Aw{;b87Q4tv&*cW#1YWld*%yRbf`aay zUm`hadzD1>MpaS!0mfADgzxu>En(e*lT}sAYW^!NQs1w+l)5E zlUG@uoHj?z|UbRUA*`P1G>-HC$OnZK@SPM(L2Zcm0@9GNl9fHmmvy{#_u#};S(Yl~lKZzN#1Ao?7uT{AK=E4Aw3 z;f{HXR}rOtq^+-FYp76FeXGyD-8pte=4zdA+=Rd)vAkIZC|e);&McjNEu z!PedWuzy;}gtx=nzW98e%aBLwW>;Yu{WAElK;C5!?`)k@f}VoA?;)P{9#)txT}C# z#!us&$?@!KxT3!Zw(7f0C&0I%#2cdO{?lLYYBq~wrF4y#XnMXd?WWb2SdG7=>)FV5 zqqm-mAZ6fayC?aysf$%buaGOJxhS5|zH9C9Pqo>1+(FF989Zfcc9f}|n4J)lRB@TL{5H{%Muw*e98%z59^omyXYr4b zbKzR94dcLvv9mWqGOTgTssuL$uR;b?6BY59JFRKWnjqP}pK%Kx2sE&4$O2{_RP0vv zApJc2^G^#uGpb7q3k(Fst*Ef}%aYy5H1UIk&g-5(D`{XX6Q<`#ONHb)xivjUd?6<0 zhU0kLBbMYR^gZmQ4p$~CDQKDT z>T?nU`L9|*9+Snp?SY_&;hN1`J1?i)iqA$ul|D$nMhmtyZ=MZYLyCDTf>c-SQ!;uG z6YJo0pl2NPn|E*Gz{pZt7r=5R$|;jvTwo-~s&?%5b}Pps^}8<0zDdjA<~mN&756j>$QZr#(N1cW z9MptK!RP_a5WQBa&llM3>!X-&c_yF36Uc_hD(rwP4e$+lzp>8Ol8|2JtVz6_SJ}>0 znGfqM3ZDG%GaVfn_qtGwHPD}d@ip^il!mi^S7d}8X9~r63Ih%yfrHUQu z1tj$qcn2<`6@_*s6d%>=S%E%#)!kZ2tnSVJgrfv@8D`zKg8;#RB9T`!NQ)ti8dbza zz$4x^=Udn!0*8tqQuX%->tblnj zBCJ)f&};O(}FfFwOwNb$2Wqi379GLqEfv@ zI2$_{8;1}FyLKu+?IaeOy2_uj6mF}Lw}hKQqJ-^n+^vV)D%g2==4>#$^ZGoQdmLpt z&%G9K-g!Ad>j&6PW!YM};rF%3+SWLLn)u(4obkD`?PGZ-6q7XoHkxhA`3#I?`H49QVyq7?KvoKP1)dodzGf}i=8{Ez zvMmSLoVD@VqFe|$M&nmWo}8GR%K(NYpMiSkGx+(rzuldMxjmA~!Y1{6Jzh>c*(tPY2~CO?EwVs4fi7qft`f#-EtMPcHws3T7M4bH5^8dCD~fcIy#8XDUSNuNp4iDqtBY;y8yClpe(nWoyWT_QGD;6gXc z@uf|_quc5Oyq4PQCCnQsSa0vVmsJI^HPh|MPf_Zy5Hhb)bCmAcswT5ZlP6OA6mX|G z->0PyxS8_SLNuh$wK+fTEaru0wZSFzzoy$j_Fy;8s>S7HLJTmaS zi9P-{5bo3jMaUCbivc$b6rQZ@{8SG|u?Mw} zr=c*J<{6i@Y1N~VJGmF#zDhDufrhdMu2e=@!0T9EHaBzpTYdNBN^1T6&z6=f7HM=` z*xTLdH43!u_3}9!=xun@(hsyHgKP2>H0qT+r9&a7Sxjp%8I;F)QA;OcRgfpyQ^P$S z(*o^W@Fu4aENBsn4HE-pwTDRWB#kP}Sq$Zyb1>*}g{zlpg4g})Ql;I_ zOC|);0Rm;nM?-h1Q>=_IRS_J#7)Sa-eb_x8jGJKIn#F=N$;1w9qA4YWzAOfRpgI#e zI3k(Jv0U`UacJ#o%1@6`)ou}1P^^HF5nSxmBLy_E7}LbOzh{|WpQ9E)d_sj|T9;?Z zM_1!ED&;jGg_vL{UWV7tC3;Cp^VFI5v1>vi6cwVz8%WeT7bi~z}xi1wl3IT}}YBUEn1Sb3gialA+!kk0#5jN0L{d zA4QOf)P{IMhgBORHoD-6g$Nl6z(^g#lP*VKku^7uIEBna`kF5jsx+NLB?5v0#AlyW z2%jp)n&|I72X~Vq8C&eLD71qehUjsk#na^JFE58GBA^vFmyM%VT}LTL5^ijhr$~Y! zbk?RL*!&VD&}=@Ki_@ZQlp|EF854dyZxA+a(9Sx?H)bS{<5PHhzbej zJrn_Yx|9IaQ+&?dX4p17w`*%Y?ysGxY+biYa)5_Hl#d_sNyy*`ra4H+fUqCsa6f+K z>ASMf(Gg_EP+X8VB+0|xCwYZQ?)8le$x1;sYf;Tvr`J?>3;11Bt)U$hYD5jje|PtY zgg~8jS(Y6WA67j7o?&#bw87${WX7`2!*~1#BUzS0qvJ16VD8W`VytrDgO7#%%J@mt zkLB-C@HX%7DAfq`qXNMDs6DT=;7pEQul2ljGRGTF_9*dfe6`D8G~zoc@M`n*X+aQM zi&g#v&m;)7E|Q}xKiqkaeaU@7b;F7+Hwl2IU5IJpsltr1*OK58zMJ_{f?^^;5Ym=W zhHX^R4A3AG;)a;$b(U9(rm33H%YWjip$d|E|6I^xZmQECy>bUt3Uu!cNOw;&p~@Nb znc`vtSC%_XSj<2U-d9#;aiqKKhR*AqE4th${UkBZANnnYe^KF{)?dI&Dy+FErvw>N zE)z`>Ue($N5}6{=HmB2(QlC>w{URo4A-Czg~qA&_TjuqMYB5udY5C4Y4VqMaJy({44lKn;D9y&9dn{EL> z*&Ropfdpt$zQp2nT7G%Z2^JYke?TZWIjEz!Ln6c`nM_{Fv7<2vWKcZfVj3hw{ty7D zGYkD>;<*8$BD2!GJQ*VM7IS|(bMFZy`#~x74s$Vl;{~QkY?Mh05*G9NBK%_Tx1$hm&=F+7+(C%<(sUA1E6Kt61$YfEaBWF z*vX;W1lVq@NCBdoNWtDuk%BEA&%9)dGre`P`ES+iffNN`@=l!vBSJw$qh_+YE^4(w z?AYP48wfIlo#sH8b-Xs_GbS8ApDZ_ikcC89$3O?EixPcTQ+4O=Ai+*^<^p zCyA2W?HjGj!)RsP}

PRq*>42O03P1^v|#P$@HIIK6?4UliZ_|#7K$qdn3G;9~A0F zD0_!zIH6~4Re1-^I;CZ1GsZcllr}Kcl_TzeT(SF%Vu*h8Vbk0>7EiB5l=Ou#d|f-& z+1#vc#Qv9S%$1&ic2K!A@XGVzSV~P4>;^Ry3sZIM1fMhl=C)u6Z$hEmJlojxtDiaU z`GGf0moI(K`>U^K4&Hkqd_0)3U!neG8<5sJfGFw=*Ia~fI`CEJ`HFqB7y5;jF>(5+=o2VBRSIc*Acae{@BZevMCN<_eIS%iwfbKgh zfuWJFAzL~pK<6|}9GeB??})YDq95HEF2BWY&KjDv1-@>ig{bT4VReDxqXHCG2a&J5 zE*X-dAF7L2u7-wtN*6n=Z9CoLD{Z}8{O$mpJwU=}_46-oagd?2GeV-?RQ5=7_9`Fb zLgsMkgOKQPhe;&Yl)vEpUQL|8HuC)5Zk+IcA=CYsUKfEKVe_dt;Iuge<7yy>09w42 z*|Bh;LGL~kGHWoQ%z;px;2G7mY2t$GY_XZSyKn`l!R zO&V>Q?7iJ!^9~}zK4OEo+w85+$2k+>c+h|re*Fp##lw3KAe3XldkGib#;>d#!!$320;M; z0Du6%c5D-R?uIDxf(8KiX9oZP^WUzBy|JsUshta*yRFR)uC;Sk=cDrzb^Gt4mpL7q zd=Rtb9Es)9g^W`s*+qwJA7VVR7B-JR_sqwOTL=PufCmQBQIhvyqQGX^KlQH31^m7= z=v(wh?=9EZy-4E&+Ay4@7Mrt!_ZzPCr_U|^U0j@>s5AI>XZV7qq_=IaH68i{4GG7SnKO9>p2nUH7@~Ua8Mi`N9i@;?3@0hMF@k^2Y2uOr+eK`%G*(I z5$U5k3qoSkVO@{gAaj}{GDDilwL}i(c0a%7pugyLXRm-mJ;&$U{TamWCLuio;yiBW zH8}?!B-CxhHy+2>29dEMX154J499^bDBs*_wXm>-DS7q)@cFR19!?_ucKuN!*dwu| zdt+p-=Hn&mA&<+GB|Ih|lbqK#$NU+u^umk7zc8BHMfXFJ3}o}L!haOu*(Bje>fnay zv3@|RnQ~knE@>8zLkCgp9Pghc8S)GOCh#IWA@WB=H}lQxa4smS`;MC-aWk*Qk4>#nHupo z`r{z1$6UV{$tNa)e3$aKd1Upmk~twdfz_U^h|bd$hC6{mQ7&sG4Tmy?U?Js}K(;GX z*GQmXA=O3lzAeTXlfDmEo2})ZD=nAyzcGw4bUBgd3A+p}<4}ssF6rEkdw+cTnY;E@JLv_u9Aa z!FH}8`S?9=Jw?~vH=6Km%8;PTYC*m9LDb%LLMJ>_n`6Zv!@r`|H3u~$ehii8o`h+|a%*+?za4?0mK$Ql zyFrRB@wW@Bc1a~7B(uT5vLykKGOZd}M zklYh_z@$O-=^;UBteH_5_;?A$!H`gT4##x~#7TYluiQfNGQ}6415#kbd-q$t1><2# zC_Mx4`?#GeQsUQd@)n4LC8F>y>lTWi`~p_(AbXk+NG=$6NS`^nDF-l zlXnH;G5R9u`bkO&r`EfAMi%*P{4 zkS4g8z`wvjYFJdDd|LaUu?7TQHLtmiLqsy9PkPBE(pqXDnpBoVMzyU3tZm(uQnIR& zk@;-IU1^|`&Mdt8v>^jDc7c?})bxZZc7c;>$xp5@;IjthkIKi9Z8VQs*f1r-j^dsA zzQ=YV!7+Y76zo*kM?I6%U7wxHdht0WU|va;F6yT=sMz(q8lQ_phD`b5& zOim0^*_;!Vggs7bM^y{6n-@+$5|gLCa6H)@9?N7oBa(6_JjVFaYyAl_M)d{XJfM!|^EZ1Xp2)Zg7Q)RN>}9~h0HC^Om^pIRa5qSm-zXsF zVc0s4eH5m|`!Dcb0AUaxRj^-xu}uW9d0hrvHKIz1 zQHBX(UNut*xvqrZI3Xm9)*&z}4Df;gy5gjWZaVrDV*TIOs5m~MTXaEy@+I@6yQ!u@ zpvZAhaYbkJxQ~z0+0o$7Rg_8a!~C+&I#^Ot-kx2HJ#0rirG%_m8X_nftw}aI!`5Bz zTNVDm&!OOQ6>`$V$nEO{^z6?=ma5)T<*U2Xc~;+mCXEphl6vv2u^`TBT48XWdYMfC zwbs?`-6I9nzLw97Qn(D!n!AzP5k8aH&SfUtp3yy!Bbbck!68B;d{9&=`IxNo7hOo_ z;3X_CwalV(k#tE}pY%5@dJ6rnwR=j83+iaS2$&c6_$ITl&|%~0}mK9E3yloL= zVJ{O#T8tfIQQf$5TVtW*qG2VWd@zT-SaY*U7HVGO={`C}g8JY}T2$h?HQVab!s_*y z5oTab6{8}l61=;;YEw_`U(nVPsFEen65~U?mU3=;z2%bfE@mr3HE}WEl8snjf|y;q zO0PV@0!mPqpbZApyYqmlQP~}4=e^NM*g?b{XbDa1qsUGsX;5;!`D+dC778= z)oD;{@@1mb;~?y053WmwWQS@_G7_x1j-4#>y_ zPKDiRgakA#r<^&1&XoMp;6qka6_Hdjof3%TG7aV`>3C1d6A(Z-yB7?2U$^ex-*SGP&Q-w%V$o{71r-FH%hlBrxqzvaQi|H zQglPsVyIKjkm1cmMGs~{xy9>kq&tOmf>#&%0Vw`iv;EvFHc`@PKfIj!STu?a3ji)A}KSlWMk&g0IcOfpbk#!|l*u6Pe)w z?WJJixVgLa&**bR$JyWsh;ErY3E`#rw7GSvZL6%5b`ZdlwVL*OU;bl?0dTZoOGSZ& zlT)W_ItI)W*^8O>am&gsW#_mxGIokb4_RvnsHbEDp3m@KG05-AR`Bmvnj82ZxWfM$ z(h+o$0dj!=0G`1C0AT+c(iIGyT$C*g9ZczroE&0Qr|h;E5W1hJ-EE4L)^&U1EVH$v z&}8HBpjQ-?fkRQ>6NvowbSLeK#spgl!=;@|T7{wr#u0)PMZ(pSxbXemXdBv74-7XQoc;FaBLBx7o#hJIxm>T(sc_Z5DIA z%Pf3AAU3_!43wJ(4b|kYTvJsWHwUA1ivl=Aql0m`j4q@XoW?QgjD?MChK4hmX7O?q zQnnj1AVJN-F3(v0EiN7%JbKQLi_Vh;-u87%hWJhp80^0{(%9rDcG>HmBCl5O(hvYnd&cXiwRvs$e| zF=i^ejjGik*5hr4(gs#^Opz%k%%2L*ptkE7AG+$uKLn-(g&5~|Wfdsk0)&PMC`lC# z2OS=ApSmep49VCc+A+>~R!uD7Wuul-J!Z8Oj?J@oZ#Qg(L)4MWr3pq!T~gQ^LX1Jc zD1?k@V6~p}1VSqm-8&=h3L{OQ7(*jsCqjY}W*{*lJ;5R(jpGC$4OThs4Ii6XmBoN5 zg_N)CsI~A3Jf=vvr@4;Hn<`@%R|NlItZhvWN{OzXD=?RIg#rvT?YjpUzR{P$J@r(R zfQ>C?JfqVYuTZAFHp-sq90wJ5V)V}9e1LHB8*k83@(V+2VMHb3PL?iUpouf|7!kK} z86Z0gS}#7|qwO;DU@IU>OVEPRhF=}dG06(EF;3*8EADVVVaO{?jnFt|b7s=vKqD!^ zILRBf?(j-F4~zTE*qDnHAD^*#sKORd_N=e_-|KE+Qorco;`X6mdu>k*Q^91VSiwe`L6U-G~B zxj&8l+K18S!3|9fr48BN@%4GV&;Ps}%p5@fzHeKvT-4V2f$hLs!tiCCd#fm#U)_P@ zew|L7)KuPOs$VdQSvN!OT9qURb=S8y-Mw656mDA4)CDzqHWOZ^H_qsB8n+IDLv$@n z5|rwjmte*y&VrsaK1^P2RohgD&tTF)m!*VaS9k^KUZBQBmT@t#mDv zLJ+wpB}u`RYF4-QTEWhIei6pfnWs3hP<^Eni0UU6&OU1!#xKwah`!gRC) zsT(5J)-x=lGOz#u`StuGD>iWPm!wM+wC+}`vj)hvug7C!iziU&sR4bIELg_|mh9GM1t&ukL2lvdodNgB`syrqE<2J_X<{1V0kE zlHm@#c?!RY5Y)brWf%|@p{Recs)Z~-t*-II+320Cc)0}^8zC*RL!9!uwg6z=S8`~8 zz|s-Kb(eOSY%fPzPwgixfHN`Wp!^=`7w>rt2{k_w8o@=t#D3Dq4KJhfa7rO?0E%vw z1Qx6@4n-!=)l%tITxO@!8KJ{C@sk^Z50F+eP3!)rYw z2jQUwVyT$3<&-Ln%_{k9D$pTGM}aK9yl;W!1XUiy+_-u2-iWN%`_E;8#*?JQ_vGFw z#b6jcj7ymC((^X{byi2Yi6@d(9ztY0!yeg#PFhR}j8rw6io+Vgw9)j=r2q_@r!eW2 zqPs{?K+ri5Nl*w13QvV<{9fYeTwMy%ulKZ8`bbU2fboykXhyU{wS~cCxo(%@JF5Iz z#)y!BH34NfD%6LLwWL4;Ju?RAP;6t7+vnES0KLE6SWE>1lV84vn}$NFE10dx`8L4 zvACt&Fv{<%5J7X5hE}tons3NT;?ZFzGFU`;$hH(s_&tsoP_xw$DvE7YwBfZlgwV-a z#|I4E`$m^8b$Oj_Hh%+-LIsD|na!ZKzNsYA6x@w?f26af=LItgCty-1Xlb-jmiFZX z4Q5!%^Us!M-NC>)kgtmnk1XJN&`#GG@-KKQ;fEXh*3Rw9NEr0z6a*?2ZCqa4Il_^# zDo}&#X&+cD7|j?>L_(yY;ukAN3G4788776EM1~iXh04=QbL-@gSEw&;%bstvvL&uP)$5 z|2SdN)XNY!6TG6#zAjHndT)HdM`b=&B=&>_$^%%Rf{z0qlt%s3pC6WdhM%(3MdGmr z2iuR+T+S=q-mFsIaT*h`m5L}SKA$w3^W@s(0ZzGs`TdQ@r~uV2&4iSeZ)p}U7#l(M zi6K+fJ<5?1@0(4z$_Ei=OOM_M49JXKCfN-V`=$ z-dA-e{vEeXTcoaafB$tCCjIzyfiUfsYb5-0@@=nnL<2F|x5Y={0I^#4slssij4uE8 z_Df?YkLXwxl6N=V3r}rMZi{*t7<~5Gkfkfn)8%a=$|~iNbBQE%J5oi{rL)1mlv;Az zd}?rtlv+4)tFpw{sr1SyNsAr`@)Ay5_&Q~!Nji_(r!5)xrDRr)Y66%-paCQ#JM zjsY{Fkc9w7wDsWb0WdE`L*#b77}>6VUU=D#GcJq%3$EG19W9)tN;I|r1h@i*3e;)o zV48(#2DR+L496RHvU-^KZg4qV!kDmWWfA5A+(i(y%MMU+14xx9d3K1{4ga8-@__?d zY6rYLbEy+QQZCX^dC3KoDEYApdOm_dDp6i}_+E#K5IM*cG0_!kTS^xI%_TJrvO*;@`tU1EtpOm9LR=z$D~#w|P}d5?+Nmq99e$bUiR zt5#FluE-gPO!5&Ev!p{>WDP~R*dXNBBt2YaN8D*_5Jn?Vg570}A`ZMQds!P(&;?x; zQ1(E_)wYA!)$R#0WPfoG@ep4rQyV(Op+1KUPbfm@s}g4aLQ-HMWIJj&qLX%?jzjEf zY1Jmg=CN^dldmCY9o>*3CsE`X@|;#S=B`kk8%H(ia8Ex&nt_)outt zvMjp*&x6DqYX_SE1+Uet654GDUaa&NJX|;Y96wwGfGRQNPP=#iqCKp}!c}x<`{IU| zH&7vb^v)Lk6A@gA4Lr|&-?#OnQB>cdSSM)Bl(~*31L5T(-5jdVl?6eF1+=q6p9f|g zLk`4a-7%s#H-s6J$CUR+!G>utJ262D-UP`4gDfExpHdryI@RS7BW7RtrwSF(0!*gl z#U^j)fHd?cO!%_m;!Sd^Ro(o{l&J}88rfsY62t>v)wXlORG%Dbkb51k?v{Q^F%2UT z$nC*>2Ddyw9%<)Y=x{{db_sU@nip>Po$RJ_8*JpZ$U-k2IHCss{YP+RYKj<5)t*lS zGx6j9Oh*AFMH^~*a(Wo_0s!@v3xKDfee|W?r&6Y5IU+qr-Yt$`l%ork zohVAG62%T{!PL>VTspL6;M8OhvFRRv2nEgKf}1DP^oj{pmQU#W2mikb0V?lG!u~(T zRpR=82!ZK;2;n4aA{J*1G4$>S#iyCIR_Jz05$z-i7Q2)HKc+!M8U!L%K#J-6^_Qrz zvn#dw_B1@y!d>E7W<^ERY!v@tERmDm_is&||NCd8Ys`=L_h_anZIA!={?g(7@F`8- z`}c6_NL`+vr^n;-c5kfi<}SAH7Pl@oCquB@>{{B*qIE(MDS(d!>dR6KQWYI zJLo)x7am-!MgyGo$Fr&_`N*H^H0l?ZY5NKgXP6>-O#Sd$G-aTwm-Lm-iWb*eKmKFJ zWh<$f+2wR-rE6Ns)5@xS1*;u%UKO;W&hjeOJe_=Jzghv56%p@;rLH{v4*Na)CT@qB zKEmkL)y&8!Mi2w|K)nP<_d%^(3S$RCtfRs?PVKBJIz%34DzcPdBx8Yy+%G#%=Ep+p z73s+|MdKtiA{HF1dh77!C1r@E^V6Gv*;%Sf67qA znlGy&<_&Ut4Guo>FGVAa*b@u1*qLb$UnsT~*$1a2~Ly5PGe6S4MO zr>eR;%|0FiWZmX-l?64R`5``CHO9?koYWP7pV4y3&TLz8+^N&_(Gd?$P6*)Z;N+up zbZ#-SVrMagL6n3;%irqQSl=4L0%9)X(PVPdF3J;Y0_c<0&28i9sc0c%Vsj=0$Wiv7 z2g6=8m9ef5s=@T!{yU9y-v*|7LR)R^tT7{5k$cA|HsuTK>f7c6)bT9J-Gen(C6fY@ zdmC*dKzE&3N-q_onT4n=yTS!O1Fb6Vwhn;0LTZM`NQp1KCs@%$2}ip)(d}J^qXZkfv}WCy9&Sv9yqDhuX2~V8l7}hJPPk=D zgB<++;Wa99wB$SZcF4&8R`b`uh@oNFz$llXQjkEvhi=TnE;GGINBz?h0^`rRWF{`9 zI8vadjl#~FhY^@{%z|Naq+i_L;(J5J1krl=i&G!(;`l5vt16@`N-{GmD)P6JM|ex% zC=1cCkdL>Qi3)LISf_TwQiw85TsEf1UBKGuW5O-d)z*{?n1FPXa4Jee7FQ7R$dzam z*27E1wI?6JE@bT$)-oaIa8VL$r=QBJxDzX_T7(ksddP9a-K$xIeOJqE39;(sqi(j1 z=4abcVEZf#L}t^r(AfKiPR3T9v?p-3W^)+9H=#-AGYa@)PAXkrONmA%odNBuwrbsc z$ClIz;92LkJBUD6w&YVdXM)6WxRCuM&92X0`@T^>%xl zeFZ+k#826OAD>V6_IP_<=q)zn`2Rj`)bI58dw*`r*q7MiIJ>_ucKGr82*Ji<<)Z+7 zizhPANi)wkG9n7)ZeA8}A4m=~5MfccI+iL=U^k2lkQHEXRj&e3y6xOfxZ|v4a*#>+ zh<@m#etB_kdFv9y5++$rEhU$POA(DrJgQxX&fA5to9f?0c$jZ`VU%eIla#_(8&_Pd z#O^{^Hc+=bpjnB)UPh8Fz)cj<8yft)$cSicIyatVLo{)Awa>@0nlO|K zM7zfN+wZ+Pic=f$6;ZTDRp3oA^!jkEeHS*7XQ z(1(61W_~K1@@2ZS5@mO~lS^s*9pS#1hW8V6xR<2K)YXCniu|CPFc)Ux@<96|@IK6)^{X1p(o`G!G3FEWC zl{SV3##g%=!sgJFnx|4t!RHmN6rVgck$Td4zh51e8y2$g9ukK5GH0-PAq(8-({9ga z)0XzH1Mu;vCg>qWPn`t1Rqhe7;1?3)3oO!Z^&3VY4qebZ5!6 z8s%6nM7Wu@v|-{T8b~J!Hc?p*7~85=COJm}))&z+%z#uU3g^fg7=*-$w3=;Wy}z#S z+ty%BR-7ppS1A#$}j9TX-`fBc_{xV*(RV^Rq!SrgzDGHFq_IgkOf}6pJ6||1Q>9 zl(yc|A+uiiW^pAZROn;nRvOw*F{IEduTiNC1L;&$_n=_2q7@LibyFd!=+w`FQ3Kub zGd*#V;v+>yDs{Q9mC8DiHU$zR>>4r^kO;Ln@$ix4>l%y>nX41atwT}coQDVNtHf6{ zoKBD961PyxSwz{!%mqrWc#TgW`l75`F}pNK4>|}(c&q29LvFLhFGKEh&XIEmSqMDf zt2sls0?fob;2!TB^@JtOHUXs#rG$!wAED6X>js1fo$HTtNHr3I=$q3n7Rz zOsGE(rISB&^{v{+W!mmp3<@!h5kPmtD7;&sBq>b5Xu19njkYyc#{#`cL3aO)z;Sgar`|usdpOMbL zhp$UtKb936p?0D4{&zY-?rAB38Kv`GBcDl0;Ve% zk+z>S0yp@&DRkyiJdU($LaqG_>;^SXhIlNL^Zb;Syq_W*^wraxk*v@Vj#A0HM=V5v zp1W%Ui{Uh3Fs}^ZeiSk&tr~qUrX1u16#-?oaDL1hJIdO4yNB6)v)yT?OzBl7tXzgQ z_)2IQ!ef6mh-%Iil{U|rOQw-kocC=O1MJyf_L&WI?fAv|`m0r)e>rxc_VgsKB&4DR z9O4j-P#%uec^W}_&vPtk-`y$cFf-zHmM1F}q}kF7CG&xkDTG1jIqx)D}>U)t2AIqhtAz90235|aZTe|A+sK11If7A}dMr`kFF8TB= zl>6`lrqm4B89T)M&!;q8V?Bf9+ZP2Znw=biBM|!&&7c_jDJ7qim>GPD*g%p(j4AWn zV*ZLG0X9!%sx0p6{eeJ&H`E>5RbOuJ+ApaC@GE){}#T< z)akC0%$eIP*19nt2ykfiyG}DNAKdhU=;ai$O z21A9Yq}c2l?F1GN(;BT5GM`ZKK^i<|_2&(u7C) z%+Ai}C?v;52&yR57d5t4H4fqx>4_9Q0G} znB0=E;BueM))=;JXM7q;ylALmer917LMrEV?_)+V;pR9G`BMcX^C%^ z`K3~`Q{G|S0!$7|M=41*jeCmFMI?BpuGdwrg(DKN&KgqF#pp)pnv=GEfvc|?ZC>l? z>U%;>7&&F0cVs6X1edpv)nf&? z1>W*99*c)o=d93CZDra2`JOL-OJ z;L-uX*KQ&S>`Z++5pK^P!2d?GO1;5mWk3Lc@c*31|7G4V{~sGtX~1rf0jB4R+I!oe z#-_}2lelP`%@!*hw+x0WG+1jH2-%On449-7_Z3N0uJG;KsI1+Ovdv!fsPFr$G~4&n z7Lox^cC5%Ku*p-~{&EHJ%sY%dO56LnYg9aB?_;P_cMX+i8M<#NUlb55HivmIQENyf zIT^7meWYS$gmg9GXj_BV#U1w67LqVgBRG+ygalnWl)HwH_A(+Y8t$u%&@|FPG#2Ae z?qQF;JfENvig>_%4@XL~^{ifWb!$95y&5^mijfP01qHcbNh&*F8Fp0=!2`<3x-v}6oB3u zfS`0AIE-inu)pE_C)ock|INSgKT~7?04CM{r~EAcQ~sN5%{XFlr?I^c%6E$_Gs3$g zN8TpiN6@%>UzW|y1~vbDM6pGzubZE!aUxC4lo7MG;~hO?Eg-K;12dECzwqemx4-*4 ze82a(x4gXHvx~moulECZd46vmoZX+(p{~8|znh1u|JI+kOYDAJzq7wT5B9ykTSxr- zKhGZ*-@g}SW&FNhM{Rk%{NGDu|9Me|`22Xf9P2}lAI_~~&KXM8bYbbTtt(@3=2>w= zSwHGC4-DQ@a-3e~x{CwNu;Vnt>8>dP>F=QNVxZl$T`f48H zsgj`I=`=gX*^q=83c4)2y>h8Rn2G^UPeD;MI}hjXTf|>Q3DgTfbhK?RtLTP*eMtX= z8b7G6r&T-kc79i=2M%je*kE*I>po90$n=?f={vP#AkW*yZ&vMVco#lDIOPk}l&$`i zj_P2H@UcgBT%kGUR{p4mYBU6y0abqT+Iz-E?<&;3widU!YzM?#sH|;#p?emh&0QOw z|K-JzTT5y}Ld|tSID%IVkRI084xi`HHomMz{Jsd*DEuyd1zs5t-c5z?HX7%4!;@kEV*MC0gy_rcOqI@bQ@Kp!rLMeARB_2 zx#Wd&Kx#4uP}xj3jI(PhrbBpDh@8>-lXV{A6B4asM4BR)JB>Fk#~0Lu?#qVLX(Gqe zi)p-Of3F@oKPBFlLmR_U?*E2^JX=d~k_Wv}J8+wTkDSLtl*uiKn!nSZS?M+)jfE7I zA8#HbQAOaWJONlTehzA^7UAQ4*Q1R54MeZX6neJdQv|%@$WW~mBT&t&*`Cr(EvfV{ zj|{+ga}*1+FK#Wpdl^Y2)gxz3Q?Bd{`F?GwadIP3CW9f?LQ|zoc$cFe$_a4O*@0NHq zdIOyqh)Gai34|-v8pbuyaobVUKn8d;{gsWs!ss)9^-}W_-w}H>YNvop2cT z$@r-)T#N8ejtD8Ya-uZ3Mq^8Zq)(2i8-};hM3n|!>^-e3b8|%$crA{bk`0Esx-V+~ z*2t>4>)hrBbR71EGaemVXbI;36^J7_MfV&(5Ap3<&@LiE z!$~SgCaZe~akdeyV4lA3SV1a22d+?yxue_s(^%gjUBJ!7j|osrGI}F!bf<7z{NgVQ z-$*L$T1<8rTvFcb)|cib*Z>sx!z^E(C@j)*ZYJ+6?!?VGuD9r;u5pNM&;(7{B{i5H zExJ6nVNzwcy;Qq)K~iyn@PPOy9)H)1Rr#sZ5rrBAQDWjm6F=Z%|75dcM#A)D^ARF) zNa}I469Rd)^8TP=Nz_wDaySvxG%W7sqfxJvRpD#0NQ>0NVqa;KGeLNj7W-oHfmAYZ zlYe%u>3@x>@V$@z>BOU?{{UErS$Hfa1a4>fpjTj!T-A*Z4Ts4cyPUQznD|y60O4E4 zmQ^A4KHUveLbN7e+wC54!|LrG8}LZ2j4{_7Af#%9L8Tg69*}j~!||XRko#T{i6-t5 zX9%sFc;$Kb5Ss9*oJeFRv%F1^^;5~9sS=c(e1l*YOwp^CsKNxjt_D=)kCd({!J%`{ zxGpkWE`-}+=#+#48^Y1;9LUv;f6+~ojsrTF(#caI)zh#1FF+?)$kuW4IGL`2EFqSj z>F%DFO2%ecfgrguC4tL;o&H18v<1$$@!bM80tx3yXwMdx0sa?6Y8sh4FwvLUEhHvl z+iwE>eIHtg*hEc3{$UZQ1?bC(H;q=5U$ZV}9#SvBjfvCIg_Jd@KTaGN9Ka6ALNXip zFy13gYQH3zg8nlj;5>psfvGk@%@7Em({APfv~?&HRZHLn8P|UR za~R?b+)zr&$z8)F8A&eo(Kxj+Ppsm=2avowDxFFg`Og|-0JX#w7QU72dt|&1<74H+ zhw(8gf!~0`&k=gfrvyK4;9?facTQH|QR>^IDwG!PyR^`W8O zW;s2A=x5ZdR#h+U=gk9a;LoP;V;JT-KQPxj`zi8e^|DBq?Yz)ZMO(@Z*g_Ny9~og+ zS<+BbhL`-~IvH`joCa~H#Nqogg>eEV?-g39xKPGsuF|g}f^ixkoo{kNhzf2) zPEah3Dc@X_Y;i3}g(L)hCd2wG#^u=O>=+wU4#g!l-dck#%QcpnIF^ykm+`$wkK+p# zpZVUbWnhVQN~r}SK`;p@1k+jXjjkBvt@#^TJu*`4gT%j+@irLJO<)yR5d@N6glA6M z_ly&_vV*raDLiZnvLt{7_m_}=HHZdJl|uw<#%ddSS>wIXpi?55@}AYaR3_Yr_L94D zWU@>Ulvq=gm6N?JDF+HLB~VysB9txk*9A1^(BiA6*M48mJ9)hy&pm$fZHwP`em}oe zb9;O~e=~D?GciM__XlTle?QNx=ZmM%ogz_8`_xhE#fLPCD8Merv~NZ5^V0EVDB#)!tvxc;D#oa@|<> z$eJn~fCC>W`+5G6kwACDx9?R~!nYjKmHQ=q_9d}eWHk~^u~+_bYcaEX^a-i~Tdz*Q zZ%M_KOwiZmU9W1B#1M5#lcPDr;p(&To`nt=5}LiRX?r@OpV=kyNm=jpvgaHeaYai1 zr{I5YLK1cyu@RC?n6#za(kp?m0RSFu!pjI@u7jIeN6D%{%@>bD0aN6HKB~-OCBmpb zLS{PHg^{yKP9IS7@<<{HYyP?6!@KJx!4nIxgXB9s33Qw~FgV>0tPkzE7D+T|ob=;l zEt{|_NiU4PHUG}q`}uKPE*sGE_LG@!HhWv20u%3$o&;PidDwaCz>#09Es}Lk*5x8y zEGPbRQm43d04XLsv&b#-{TlUO#b&);o8;>cbgA}`p^j43N?PQ?Xz_su!cY;g?9o$% zvU0U3sD1eD{9P>qC%$oCuE$W_pk?1AvDkFic;Dc9KLDGp@{=NTqARyW8_ zDrq$5t@}Mf#_64GC0>QtLQ~?hK9iQfv8xz)z}N0g)2qJO(H)pzNCPvhoLo+^6ad$< zsJI0jNix+zt)pX+mCL}C^V7w9i&C5^@@yiW{;<}_fFTZ>63I4ly}93{QRryEQzxYw zS;viN#Y>)2(3`D^kfCQE6s^2!AZ(RX^{XqEN(z-y_EVMP$CpRFs1uEZK(7>F7bRa< zEv65lq5=&ugF#V69LDWhipeV7=+Vd22uE;xLd-tAtVJFJ6mKjfR}?vU6(J2wP*i1F z2FohmH0^-0q9t!>XEwfzxM*}-1}l`|h?1*MhHRBR`Ink+-e2D(G&6bmCd? zZ$w10(S(q!OqFgzCQLw^&lDC+LYBo*vEOnPnrI?2Xc2O?s3JJ9txB)MB|^A$+_;Ev zy3opQ`$^X6Z7Y|wG(KLq60m~8dsLf2$YA8W;EM>Q;QEJQ* zGfau4;<{3x+3@mAPmNkr)vDdxL5ZXj4xAGRz(PFZsd|IBXYJd%UeiZ)?k(N3G3m4I z{zoAw;wMNJhz&?sctwswoF~e1B~q8~9l6A{pihxExT(Ba)~qyH_D?grdF)W+9NE4j zm=VU)x$I1(z~*4+^!+8i_2>oN2=%(&A-5mHD6-n%hL;s38(E$^x$3JWuBZ3lOY^Ohy#a*YIa+;ro4x^r8yJpiet}lmRq;A)cAn<)ry6!MR!7yw%zv-eK%q=A7xa z()qzPp`Vq`++1?g0!X@du5fVunwg~hCRWtoT}ix*_J#}>DUa23qMRqx>pi(N1lb$8 zl?2|iC43Lv7FIrT6NBb5Fc-s`t(`klsXNzOJn%~A1Vw-@XX}I*TMpH`BHztKflkCu zk!FcTfli#ENO!aI-8>lDOr{$-eca$|vi|^dV6YI1osJ{vjwOJx zuwl`RWdKk#tsJ)Lx&p<@t~Ma@#hv1M2BL$HV7x+kO9djl$D;pOs!)k6;&}#O$e>_| z^r@y2MKr#2hdQ5t_!%S#V|VdxRexD2ywbW-d2>OeP(fxdK@2SX*C$-8D#f*RGnYtI z(Rm(Bv4f>*-VIY$5?iE&*;2^-iesz(u|{(c4n+fBtjoSkR(XrZ8$E4x^e!d{o1h_* zdaVR|&1?v5xsL}4IrHNF8ZPYe<|qYGBytAvbCA9OiBVYG%)DxZwhHQX5ArH&C0`tB zJ&DkCP`{9#*Zyw~nWkV~6su zG{8kG(YlbPhO2XQl`U*ecZS!Ss-B*AOG-EYcfl57Lb&7MJZ7FKvDBh~JCR|aK6#>K zuEVUtV5o|M+&3=xuWTT)|Gri?52ELLvJW5M3#pGjqL*_LKHo+0qcFsZ_FX%vuKUd1 z740Q~&C@si{}$vn4GU_2Kmh=N(ElGnj`jZta_L)k*z5?QcW;#L8=JaD?qu}J+&!0& zuJL+kR)u6>Fx2%)C>~$F!V|G>EmkYV0^0r5Ly6@Z2h;rEzfEWQf6cy6Qy(*zZ!2}` zS5a$K>{o^yUQUj$$KMqmtsYGso86xVxm|VB==8lTdo{be)uT@}W<%y0sBioDkuMps5ItSPVp=D7s*0rK^a$ z`$}>k90@R(SAj9Ija)d(N$WM#Y;8EY_Y=l;lH(rQ61I5{5w-}cKIkV#FepO6N#%vdm$5()VKX^1)es~@_5Ue(T*+q5~y#)T~o zr_`VhF7xNoaJFs>CFpPtq@FA?2O@`YOAO$i=KO>3G|pp#0XH&D3uA+X2_?s9`Do1@ zehYY{U_M^;n`Int{Qo>%tdVXUrYBNyf|j|bBOwQ*sPMq*d-{FG0=IJ%ik^fabb{|5 z_(9J_OlO)9l+@7DIY)GtklE0h&t!CjQk1wGwvk`5lfAgG$1n&fTL!n8K!Ss~?JiEz zt5GmO&3VR9N|)>LIPGu=9edj~LXQ4FuI?#FkZ4&KaNE|jZQHhO+qP}nwrx+_wr%&c zb$g$4U(SB4h@fY%Fc0?Sy@ErF7>Q+B!N}WRsZ&+AgP-&BOciH1x7ygh^)D!{lrt!YT`^MYNg85b zyb|9)!60#d1(egP04l11+rx-+Bg`Ypqn9&JRpTMK3F~M6(a7`p2SH7_FmRv8o^E!UY-y8g;t z*EN`#+lwu&wvZ=EZZhA-v%|=jy}A7uMI>?#B4)Ae5n(n+@z|>foI@!a3d-e%N!BD` zhxy1LX|r60zrAuebePj47A|M4YBg&6Hh%Yb%xbD-$7ofyVg7oYg^JiS>QjjC8UQXq zn3sU|pb>$<`J*Yw&{2kfT{-6ylP^dT1d2Hc>6a)L#7qR+wDAP(sBI%M^1ZKHQN zB->(t1UU%E#gg4z_I60+Udelt*mT?FA%z6pWzFQ1$rAZMafB+kKr;`^GODpnx<06E zSO<>rQg%_w1~eIj)yCm@|9-e|#$0H$>zbASC+oXPcd+8yoiV#X*l&Z@29fC6;|KWv zHi`l*p9ld$008~6|7sMh|I;XPHWP_P9YSyKQQDhXzzS!>q%xB0yrGf^bU0TQGz~$5 zs_;oT{yl$xPYD)Pbym(ZW$R2+q9vmRi59_WcziNdyaG4be~0aUAHMDGe4UTFrPb|zop0;) zew=r~^JRZO4chH~MezA@wjEaR<`k*n_;IVj^O3<8^SN*B1%ctRrOO^D=Fu&>oSm9p zy*FT9c3ki3UEF8)pv&AT=E$vgU0kxa%51~=A|jCf|B zxZYINTC~PkX^$)7FpUcc_UkK zXkV7%X;`~AGfCRLDoLkKL2}mWrM2$fS$(TfkiF|%w^&vsJmsD?)Qu)YF{8UFlo=lK zO~?Es+SPI7VS(-B8m!0id44J6w8N;K712J5P2$D)y$I_5T(#qqJQ4IfWk@hzayK+S zHeN90l^!pC)d8_p+xqpkT-07O7yf*h=2lh+&1foHRFmUsrBAwFpLArNG*q1UW}BDz zE=~AWp(ivE>laAVjN2E`8-zzF4fCMcPK*-^HL*~C4)r!^TtRkC-_-&b zy3~Kt7hxA8H%5LmD99zBbcFr`uTE%IT4=B8&5noDYRUK=O2#&q_f)D%QOGVt*}XoS zzdL3q?6HtaDp6lwYA&4485|nd?o_aRIwe%9vU2lOE35ndJk;A^>-#v@ep!qVt<~9f zL&hrw%i?%epOhtazUgeecsDJt>b)>qgoUvy-*mOTXvn$*%u`skL1$i8JH63_RoRSn z*_{0fHlkP@E`QTuYr*MNTVB2@wujC8Kpbv#i^96Eccw#3Hj5vNb6&2 zHuAK!gg)kiK3X7HCTqjuW&})$uv5d;+_jHkO5Y?rsCdBp6M=d7lgl1$-!_tKazS6c5 z&@N8B7?%^9FN+iT_T&<~hxiI1ibM`o>vU>w2~&Rnt+rwVBUXLPddc&8XXKJu<~3Yp zmzgC;rm--(u#eSV9~63OTiz|ly)S7%P$2arie#EKluP1{X+L&mstSkd$RM8BF8MkK z22yTSDV|_`5@)_cW8y3ruV+;)t5WM*aHcwX$OY=SL_sM z!j=l6UD^7{M&av7$7NXq=7oVjZG4n}?J^lRRbf~wp7#bU)z%==9ck|$%K4rLktd0| ze0)=o!1SQCGFZv#eEiR_w0%mOpc|~P+8a|&<}a;1vOkG|nG2cA72cZ=lZDNe4cu{N*_^aI1Q;SvqMbJL_5Q#7EveJ3da;YVaCxXo6R!< z7H_aPcG+swG<~K%{e7#jtl4g)___d4r$3qg=zaZ2=dyNmyP{*Dj6tN>6H{hL5*F%A zl(l^-&DU~)0v5ve%mL!=nR=vMY><$O7IOHGeWp$eB7&~mGds4oDKR4BFZ7-4gj!= znK?eD8=f`j>=7}s=CXqg-yN8gv;{Z98@n}CBN{|aN_uZh#jGnlV4`w~u2(Wg`886GS7d+9s(Zu(KvCf{=;MU3T?5BjKk||%A7Nb$B z7%@FPaVrl=m~)3c=^kBQh2rOca>}r=0F#}>9@9DUXSLK|co^6?7-Ni*&*8`+3eW4Ex)K6{h)O(@ zHB-go&rjRGm~`AfZ_=u0G117&*inDwz8+M2LmvgyK@3(CqdhH)j$j|LdKrlyc(4q6Dy0U1P+#XnTI zD8KhKbY9Ni@(gv$9LSVf+w!UO@AlyVbDS$FFt9l=A?SJr)jh+OP`}WSQUR6q1F+9A zX=cu;s7x*MLg81j+ep=lTlU!W;^G{6;rf}9hHLW*yCMpJ<0^3b#JGb~)_hXP4CA}n z&9X~+#94U77J0dX$VN5Xc7R2}s#e?0zYwpvrdPs_Z5@}>(k|DDZ(yresY`H0wB7Kq zOjOU}W|JFx-f$@CZCAKT&!ZI}I;EnKsaWswr1LuDtW5U;VMM}O1BB{yso<*zY1kqREN;3~dc?DU6K zyu{krn@&mi>od|#+h9N4H8hLcxnkbRzgu20JHa%BoE!g3(Bk%FPj}a|2MV!#`m<7Z z>NwH0$TvMg(2lUIsQ9PSbZuIk}?w-M!;;SztE`7-ZnCE-P}$Oex85!4CXMDeH{)h#wH>1>A z($YQEZy5BIADCPW*V{4HDDeU7Qf?7lp)z~rzaNAjHt*TKR#qGqBbXkt8+_X~tU2M7 zoj#YiGlqfQu*-^+5u8#(ctYvFLg#>1iECgdU7Lr5`@)zNOb`{~O>2p(3CIVb*Q2PP zSdXu;qE_!X-Tyv;O}_3i8KbEi{6~|!nWa}hWjs!I$hwpvC<#S}4xoSl>H}u3q~aXE z{L&0?8kT`>l{Pp(>OAlF0uRu7>){(zZIb{Xd0ggB03l4Ir<#e2HJ*H@nih#XQ@sG! z^cJozahRZ3pdR;9TQPq!on2YUgynK3YLtyqQB@Y(HbtGB27ZKfy(82+$W#Y>yA+Ht z&L@(0&Mr_8g8n1b1mMC5%ppUVV;p{lLP8yXz`=kbYp5T%C@SL^1p$}!zk3gtEZdZrlKW zK>M(I8gppTY|)Pd%8|Euj@7dgI|Hig>jL`}HsVxD>q-LzJ*2lv&;@q+?Wzy|@qT0% zJwAe|dTDsdk@rhp$sOgoKmef9XJSbgygj-+3K~GrOwT@881rJxX#2w7Ijl|DeEMk! zK$2ycsY9@E^!RA%yK(8I`AgnR5-LpvsK5*Pkx)W`cvYQZfK-DfjM6Tkl(;4R2Ac?I z{Zm)Gw@pYyAT2|*Xb?l7uY!t=-YReevV994m9M1(m~sYrDM zME|rxCUsqt8fvJJbv2W}nE@OYE*lbGrng0$>R8tKkR>7HBgJ|p`5817&@#PsRQ|@~ zE0*3b9{k*AiwztA=Piy*?;{yUC+W0vfHh?w@~zYU2Ne~#XKNa0N*$$0Dvu%tMP}*9 z9x|NZVN$9!hJRTJYmQmgW2qYJWYba!!?Qw`t?YGnP@55y>txF zUmB&EWPaTp&FL*)KaQY z;sRZ|;XW~*+3M;1bE|vaBjJS_?$}`u`*FAbdihDPO_991cs`EX(2~a`r!KkW_IVlP zHMjpe$RSl@_W8L*V?Cxl0xSKJro&F>{Ibq;o^ThJ@bHr4Q`y=bJ7u#-Qk7QZ-Iz@c zWt}dL34beOZAV~3G=EhUOG7(VGIJbFU+APZ1V^3US3)ZAM~D_GN)9rVvt(`N%SHEX z9mLiylyS@(#(A@>iX{MsW2nL~+>SIoem?dJ4UE>k4GLdjK!>OC{>}|@?j=-Fk z3e#&&!V9Jmj9I}5ab-<7Lz*}PI434G3GuOZ6sm7gMzVi$wW+iySsf~`C|P5mX9ljf zMY$55z?edp;aR8Mp;mA!)3I6e$U2SKwz;7k-))1D`rHCk0Ru8ixt-sm|5{-aTh%l* z^}Zq*_*#Ai^~xh;PBmQ6tHK#2Xmp_Mk783E5Dqz+z5*44mjxB0BqoxHu?uXUsMFs& zySnFrdI^}SXgol{>};VMVb^qSUl@~7A2NgOXTdkF9@a0M@+0s{D8FLlyXJYkFc^oKLL+0WHEOw z?f@>nHS)T}Zq&V$%tQV-h~KX|1Qgg?CWWs0)5H;65-xoP5j=RnzsIIXe61>Qp*kgJ z=MITWpXdXn`%pod(_a5J4gNEKM=I7iy@v3U#FM_xpmq8Od!*YYVd6$;V1~|g{ij~C zwA!h$DBvg?8#+Xn0{}Z#JISDxx4Pq^c)Zz3d=x+d2op(k!cb9r zyn-)Sk2ti`-W%@bYff*SY!J6MYtEr}4l(R)t~N7sV2$dHJ)jgn6MF`*DNC(q-G6b9 z(RxEzpuFENoBR_1iG*mYX?tuEfjnkjm-3;CADkExHc>>lIU~;}eS3%&{~0vqH}zz6 zuVCvJlv%Th9SvO@LH{LNDE)cc|LFVv9)!PM%?|qW{T+wb`*q*t_IuJXyBkJiRrSkN zzwiBazf!3MCKK#)N$|a76rjRP6WmXfk#|ii7tm`FGMer)Y8+~wxxqhibt1MZKSQW{ zqw=Vo36%2dP;O0qL+lr#hq8qnAf&e$%Y!+cI<`K6X6){z`4+`ZOgBVB?V`vPw)#2jc=5a3#sLJ|6(6@(I0#~>nwwD-i*j+zjIY1i2Kly+%B=xA{^>;`fp!zBx{7n--3G!Bv zVDZLyRAsoaD8Fl_4nhs^2?IG?O2UbfT*C(xNoy?PiCGu z$T4`i$y$mOPOD7s$3+BGn4lQ*!2|Gas?I%*)LFZfdGG_gYaA4%IeQ=Yt~;saD0`}Gny`kQ8k!h%y}^Y+T5>=DJjGRJ za#*G5s%lbWpVeqt=cuR-07-DAsO%_9^spGymHepdoY3FOkq87MZOXQkli^lPQBJ#v09TAI{>#^%Bln9TP=C`ogzV9oz2%}2W zC-?s@U&yYchK+XFJM*v+KHIwl`PDmD4-5sT!5mB@qZ_=YY|I5uy zpVw&0tq9?+0}G`aK@)^~FV##OoHAich8q?dBr>Z@VJ&s>J>l+OnEAAf4J1h!P8G62 z);>vlQ!o{MVQBJ`-Go&|9?C^C9l~XpE^omw(S+?Y`ibHZ6ASwZxBbo_Ir!TfM(vTP;dx zY+;XY!dEYSzDd^Zthc3b-Fj;^I^|BD_+rNm8UtxzPL9d7l85v*^Sa9`H(iOm`^{qB z(ezuCX;?XoYT1h>)EcPNsA02f*0n{n6&(rh_l?dU@S$PGV#BRyWeE67pwHN_w+38( zV8kf{j)xV4l|JJ&+HpT0JWILvvTsj7*aaW74|435cDP{QDKz8&dyAR)+o$Y5o4AAY zHI>Gn4d}694n%8=S1;D=w;0)3{*f25xCA?aC^Zzs!UpZ<+vCEH`fNNSxMx;PcNOIhh!3$>j@%XzKC_uQS1;rvCtx`50{`=Y^A)~rB&Fdxb!_F+8%j75@ z4L#W4uBPg4SV71>CA1-zEWsQYe8P(9jEhqI^}ap|Cv+Pk1ny~~Id{1;Ct zhX-r~`F%1%#DBjAeSztQ+*R+;@P_D?}Z(5HTQEsBD9HI4hkVIk_g2QRlJcH#kU#@lMj<1 zo6(s`9x~IyyVH|q)Qldy=y$VAtW|&FXnc3Tn!=hf2&b_nXB}{$)Z*Ac$}+ZZF-Y~c zoGTSvzF5i_frs3#3go?^o5D{FIE@MMS6QQHg)@c#fZP%Y)ppz{#)Ih?Vgn;Quor7C zA6k4Ca9S#*lbB08$CzoQ-*#w6uP+8K0YGTIp>x6fWr{6Sz}SeaCjDUGId_$jvoRlA ze59oqJ+rVJnZ>RryEjio`Le_wS0U9$IK6O;)LWB&a$ic+M6$C9#wIp^jxonZqrZjX z^8v+U9;QMMlc0HRb)ZchVPCb6OmCHDEwss1OY^zD2T46G#HL?xC7d~F;LHkpTEm>e zXBD#p`+h8u$Xjc&;nZX(zwCyD4ijfZn*B&#eck?2pcgB>TA}rjoqe|81?zY6zhSx| zHF0ddM>%ZNP*X~fyT@^JW{?dV(O4P|wkbt~FE_*s;(_%l!a*;nG8|lbCC)gN!K63U zx7A{z4;kV(jyKv9;vD#F_y_a)0qi4frjJK$a(C96FZ^s9rLmM8kxS;1EfOa)(LA_4 zCJ8eT2Q07;MNwDYh|AthKGx2FMT`(glTzEb~eH%Q>Rzt%y6 zt9wUrESwzbCI`WQFzZxY#GkCclsSI0KRZqBpqm~qZmnZ-BLq8LJcEI*rW+5=!~zKW1>&W&&U4Wk zahpUj3s}VN)M6D8=7qR}2(xL-AmR!mJxLQyPiySHNWPE8llwU(8L%^y!ftM}M+miG z?ky2`#@axGLy%&wJViFof)K;Ne?9}Y_8fN>8yGSb#`&7ZkP6V<^_F|Q)JY+o&U4L8 zwpsW6P}Ni$^_<<0GS~cFZ~9d&OYlB~c_X2p-7XP5T5*3SV1TMZ1^5k*aR93()#Fps z9GDB}QFtpeBHUW)n!g%c9Hdz}+Siu4v{}dj#1&t4J5z|{8+XG>==G!3$8xW&>>_|v zAUMi0liq5R5ebkjqX2FUntdR=TAGD{hz!Wu6bX{4bN$`$hM01 zx5hUhL`@j(*li(O(HWP{cbC?E&rJVtP5C_-o<+vDwbu>-UDjHl_WrtlQ1;? z1FN7%qxbdjLo>{VV|;4N+Ixt?#Qu2mx~j!db3fwN7KOU=A$_g*b8b=Cn}a{+=13-= zgb9cG7fc2pGicKe7ccb6G+BdF+=MDOOQMglF}AyBXmA*PGRgGS7}6VAIhS0}9pd#C zAdHG=&~I3ej^hPs={C}jyta=JB$y#N;1tGcRuES0F<~u`qAB zSHkmnZg37ZOGuF#=|C_P-Ol88aU_}hymGt_`YG#SxKQ(x3Qx7ya|$ij(tW_nOuuGs zr^|100J0zpSCUv;ErcX2{^1<#4y*%hC=G@R_8T+}#`*d;$F?VzR4pI4!cL9dd=kgN z@v|1QXy%S$TJeeBl;UTtMH(9X4T5 zhaz(jD~t9x8HY$R^jyl+xtg=Sf97`nbx}`bjXnyAP7uf`u>c;*ogk)VYGp`Nf?(6R zD7s7Tjbln{2HsFbrhC0ppE*b3Rk#TM5wEE@;PSv+jVLqIK&q|leRms0a&j}dlfGf0 zztoKI z1Q=#CG?o$xzP1(})2Ayj0@AI%bZ<}{0Xgx;imEDiCCC|YvH~0O)KZ)r)2RESUWois zjdA|~HYW-i;>IE65FO5kMAQHGzJHc6#Rvj@Pw0a!$^f&4VglUgaXx=E%i65VfP`i2elyxF<#)&PBEMKdIkuCHnS+CQ0Aw@Lsr~q?jjFAEj@9$) zfSS8%-eJ&Gk#NXVqgC0;ll`q_22Xl?K!9Nid67&d%(=2vOcg4kD2krhP_9TXX3cVD zBI3Y%$cow#ksNYaRxr{A`Y{ei3u4(>)8{4xq+BrzuVimDSJe(#u^xJV(&cl^rOSO7 z-iM`iiCyXqJxrh@24C?r5MSEdW&Qdoyb=T%K0A`&(<7vSJDF~jHPHkRhJQwS_#V(6 zBfHOkF`Nf-Q^o7w%B=r)W!V2ynHU8bx#0g_nX1$&`Fuxh0XfVVgu2p3R0#+Y@9K3w zJE`cB3@k=EJU`sN-R8=nES-jOKFusBc5 z=CP;ZxaqYuI9%%zGH_92dkk_CA-E)UMnn-&`#?4Uq_ToYLy<_Ob9mI+Ahnu!h5-%g z1`ZP7#Nxu>1?A!DWUVuhRVw!n%`A9?&A@eTY#Dd-1pNS9?#*ZAP1zH_*9xjIQMae9 zZ*&p)sll*X?7tkL|FWWck)=F9e!}Hx@s1*1HXIUS@Q=d))5pEw(g4(S&$0fmPr@jz z+sODW3Ju7Ay)qpCDNKr@jNIY>7KVtKJ@Z}+8*e=ni)yYl@Ngn|u11+fWg+nOg-cc| zRWK5bs}cKSy4%A}`|DMu&QHz8I|6>v^MS0^%K!e@*jqzqzgdHA()2sh%{#!X$>|e= z%|=;eYv@#@&0N)fd+I=x6~|J4Z_BGlP94S?{7 z3&{djYo~wu2%yUqQX0MW-^~Wy(iJZuSWZXG z<%SWJ2o;9aq{(>D=YIe3Ao+XMYK9r!thbaNsN84_@&fI@1msZ>?-4Ps{kw5bHI4;n zJi7a@XzlKirNNzFWJd9e%;5h|v^M?!Dl?rXqEVaB+czrrjMw1mx9@gm;!{dJ)QarM zr4dzQm5OG{ao33--dX5>FlAnzp+Xl|@6}DoJ>1xEUGwGuu-*JG-fwX~_tSAdPseh% z-!I#Kem~P{e(o=aY-Njo`o1rs^!(nk9#?Puynntv?0y`-ZQkHd`#!dJ^L~!E@%%j9 z-X4BU+SglGUZ2;`;CbHe&&@X8+u^CxcHV@N$Mr`iWmRp>WFdK`9j%EQZmkZNs?XxH zh+b?9?epoYiYOkPix)4>`!b1_nh(uIp zZlbkEEysAs7Z=ck6+8;D-@T@N6F1vT`X_3v9SSQCTuKP7=skD_uH{JuzI*g z8(F#*xc49i8Z^}EpdEcKhPak=+CS2L(M;pmDOm_z5 zcNQOLcCF_f+^jM>%r?s@B3jKw>tLz_wbhpmlpm(lT;BFNY>eiWDLRy$g|#1zwxh27 z3Taz{EPYm?oqt~_GaGM?p`Q2ENF23vvjnH_qZ(?u3gam#Z=BWkB5#_d^41d^c-WYe zKR2Fy)by3YI?=Ow1CgU+0(3^Kv|3dD`uXssF3VfiEEw~9RZ8JBPd2sUrLMNtfNxM< zHU-Oq>C$ zDU_err6R892N@})$`Wnd9n&|!ZyTAE%(Q`VOWZTV*T%+B+x~MVL?)w)v5AF+ltCMo zFQlpU5@BAK8QMy8M7fC@bCMQa-huSyETpwORM|50!HanIK%(+%%f!E8XFyZ7SpH+n zq})hYMM|KFd-xx;Dr~(>VQab?FYRj}ZZF>`KZS|oWxVTJAv}4rc-K*3hQbB?ArU^7 z{)XG2L;Mt&^Rw6c_^c*Ri~E`Su^o-47!OKY%uFcvO;6cgYKQ%`-R!Nr=tQpv1{PlQ zal?tKtf3NJf_<7>kq;rhrYNvr``N{*-Hgd$D0T(bq}7T4fH=1J<61NrWAb*Pk*+D+ zSJx5>dxx+MjDi^kH^>FYDAyW&L+&_ZKmYSx-kO?OlVWQ2+423s<(f2JS!GzR-eG^p zU`);EMc8aJ;<%-D+vUWm+fc|useC}Kth2btV~tx|?adR4T?8&cs%|RM2FiZjoA}71 z(NnW-mT_BeXEMAI^RW7~CC2B_v z-9cAtwFm5oy<;!UnCNpv^#veV^VLWxX~;prG;mMKR|_S0_ru(Se}s;LWr57jmQxfFG)_;Vp?f5LxDNA8z)yQyN`uxYH6Pn~A&1m9GU|TUAgYwIC*|Y$E1VcHQ^&si$%wtN zh55B2q~1ku&bJgpufzFP?7qK{eZT86el^BLBVZwcFP|DHhMoPNm3g#iLuyeaYGNed z7;LJ1nka6z5Yt86J1};%SdNH)^NVMiuyD_yfb7rzSXter9N$`SrGOEn3m3ui^q_?u zLQ;|RA+i<_gj0ciP|$4*CtH!H7MERYcvgiA@lk~Is5F6l=$jGQ1oD+Z&Bd9aF1%{< zeF2mQYxhKv>6->hs&?i&yt+B2igGLh0Gk050QPx=V|yKer(>N= zNdKT&wE8x3eW^Td!Y^^oDXCEuYOE{OT&dUemVFDng8ElwW9!*6xjGg#MSrDuxm=49 zavD_K;d>9W$YD39mx}9fNzFA^O-aH&z^b6j-tHjDAeW z#KVFBf@Y6SgC6p~2;6BzX&2bPhZq(SJ`b>(E9mF~QR!o!i_rY?GDk1L+-qs!x9DP4 zk6ffZsha=cWnN@8_Tay~%uoib+|_UVrccupBOakc`1E zLodG@RYSuXuTJ5*{|pf#|6Bqef(FBi7*iCh*@$B?PFBu`Mj}4Cvcyn5zUaxJaI}#F z2HTWg!Y9iANk163{<@PhZl57bpD{2YGY+t%YL0C5f zql>vh&g$7suTZT(DqPmB{|UC(o$Be%{_KH)LLQwN19!3rv9$u5uy@zCtFp_>`mtf_ag9aLm1#s3+LDFJdzd=OFu znCNJ?o<5@a|J#3V-sHGV>#vn^Oyd0IoFw6>vl!Rrv>c+#YZicD!w^xHrsLAzGZ zbfQBa#2)U4F_NOwpziB@750xIB5?w2-xcC z2L9gv?7A9@{qQnk^X2xtwKqdZ$!k=5`7x)@N*z#{J}$XY<+}Q#!fmDt^Fg}E*-W%o zGQcySE6@a9Nf*m5%XAZ3m&qv$WuO|1Jh_V!#dE>VvypZ%j*ZrS$Zo?4%V8!krvxyV z=ZscOXyPipvIK?rg)k$SASTS0-WER-m=6ZIr>dW!CADI;I8ymS-s{%hgt}DqDQvpF zJ@}2nM2UbuS20=(qCc>GPberB1eh1T*Wn&TDURE^6tu5$Cnxr$2q8n!xeu*!<~k6* zp+MdsL3ka^2r*$d9`6KR!YLvpTz(gMrgMq8r~^;*fp+prviL^Xq6Y88lJe599ikFh z^H>;#Mv4h?u|6qj6d8MjbXal(txmesbnO^JNRIGWa84e1P9Y1GtL8T>L<&@=#rV=M zbBs7M9j$>Nk`G}mE(P1fN;!M%B4;t-hMD)-GWd zvwIvo`m8oN8j^x^8IYDqzMs{HL!WE{m%0;t9yIQHfHse%)&AmIj1u5f>{Pobt+f5r_eG|t6yV$vZ`6kSwG^>OMoXJ{6(*8zaipKv%fY#L1!EkYf7FxF+6Kz z;Cx-;7foIT3g8lkW*@A0Sy_A3Sw6^Gv6gV8G>ZdVK759eJeHmu#JPBVU}*lONY#gV zDlu6i%-Cpeqf}HoaP|e^Q+53GO5q9A!?u#*FfB1HK***~u~8UYD=ci$Zvsn%<3AOp zHkoxmd`Mg?1p`T|&Q<{6QDtX&@DU)&N~DUpjAa7QA#P5N@*yU6*ZEU%2);q z*9(FF@Uk_vkM%vsl)w;4&m!Lx1=D6@Lgv?2>i&>@b((kELw}FEvVs-7&qcOyZ^lWzk(-?Z8yXiv8oykBgY48Rkni&;aV+1?7B zm-5+^I6HFNlqe_Z%kS`gff+lBr#;hlbmK#eH}yR9>3x$TMz$?%V6q8lpXf-fL01k6 z?_z1KWN=&r5qYc^GXE>ge*Xa%WDFR?w)(_AeWKC%QlZ%q`QX%;MQw%ZD<&qlqU$kC zRgl?+7mmFqyypZ9)SXRo0w{;PS#A7k;b=dow+N3EiuY`{7?C?>N``V5??}+NL8G)RQNzZsXVZzfX#x z>NysnI1e~ZpAalL88p!A#V7`dH|3FH+O^NoxY5cUAra%A0G@ygVWAPnjh`LZ3i2 z7w+2KKO}5CWf?LO2OBa%;Y zq6IMR)bE{2OSnuC8DYXvU#oRO{(g&^b3!JIwZ<30&A(f*Tld2^0-R?&h!juyO-P2i ze8(!&yI^^H}uLKB?SpC{)>Ab{94!X zWT2dY&jkDt&2;;d4spr?Udgox;jwG&z_8_TRvn*%Ysz@`b8F+CnA)%rQJ2!_+fMr8}^9ymjD&SL$Ru z@1kp{nK*lw0y}F^&FTiHs>N=HO}%%{zHz5^q2vd4Kdzs=uAjMYF_-STicW&>kvACY zPeXtz%;{Nb3%pe=X9S(i^*jg9l6fdf{6nHLpCdK={-26m(rmjRuiX~4NR%~WHVPbY z033&OcpEQ@3hkam17vfk!trwqh%S%iDjY^s+QCX0m|)7gj{r+3d-5)p_ftgI3+*16!otFJ%W0Xp} z$jmw6;-w4y!9KmvcMc$uYno8jwAg!0~Dp+vqOV=F1WV-5&ha*?1NNT?UbBazw zv6u zF+b-fRiajET}55~T3Jz8IPuot^)3@YM}2b{yj7eP6&wa^YqH)CXw9})C&2T(Jdthu zu42(`OH&u8Xk^B;iSAgD9R-22<|jGc%VwE+<3N^+SO_B!`TQVp$bbuGCf3;p5)o=> zc%phOB=OhY8~bI7WA?=cJ46##fx6eS&oKpWJBi9;%46-k8zu@p7z?3Plen!OJsOj} zfIpsVKdd1;PIXlx1jUWb(S6e)ViJecI~-~Ura5tawJOA&%EKU+h=>To8G&0bfc3636%`4A){HKcPOd+uRM2L}g;*6|F5g4H zz6?e79=UA8Q5z22Mc(cT1`hvdN7Onab_5!HZs8e)M;-kd}`g(ou3%3oEkUYpkqrnJL2CFr4%{>BK>3 zpHB`NK$p+?sIm`uMp;n+vC)!yju%mWYYKiNDD=~T)RI$#i&@XCQ7PP2Rft4>oV#|_ z@b5J!LNR+JuaHrR!{cw9k0n7&YlBXQ?kcROrZ^jK4KRWn8byA|iujISnA3>w=TygG zZAlMU8#~S7=-8f4jR9CVT};EsnVsG&Grj$8l^*%~IZ9Tnt#yp<)U%ECyzotGMzlm& z#$ISSdcUg6RVN5V>LrYkb-6|Y(md%)ac9N#mDMdh*vcUJxaK4}&zV6Q1VbK3NHHnX z8ibrD0BY!qqh<@5me<>A)^nd8(ZKihoP~TTHJ?Z8nvQ(BcCLIA`LkBVOkjT%vv_~5 z+ylkBy2kBlu3BpehhFI(47f4;*B`^dDcqy;OuFqLcW zwMyI)`Q7*)(+8eY-+1(?Xag<^5_}wqvk|xTzXf+oEVA@#V_-ZDxB;z9w{8<#kJX zvBlColg3NV%nG9E*e)nv)imm>qH5icm&lW)FXEdby+Al!Pzx^P2<0_qeL{M;9vd^R zHQb$b(w&p}kIk4V+Hli)Hz*4)F=%3EM%2+JQSFRm{e>ph@LA{Td2GSuxv);5&~+J` zP}P$O@Am-$kHP8aClxZ0;*0FbQYudmli zgH0Rl0$on6ZJRhnonJ%xoRx>srbC5V}WGXs_ob=GcQ znDYe-emt`dH@Prer|BqcR-E@b9FtZ!@m6_GhVrd2^f!(L`j8q0hj=QYWz-B_s!e}} z`h5mFWuiY1+bJ7n46-oq(T41HD>IX16|^MbesUtDZ43zqjPos0lbQbib#@j&aRq6+ zMuNL*a0xEKJ-EBOySuv#?(QDk-Q6L$2Z!LU32@o$-J2}+-@mr@Or4pjntr;cdgk=> zbbsIb7V2-nC=YEE;I@yXU67&lri0&rR$~^eE7^$ z@fJ>#)aE1VR1(@|CfsLsE)lzBsuwnX$9 zVT}O%V>J*J5>hd!`$s6Q>g6JkF-3bG=& zBMVB5z0rW`S0Enok{})_#g8D7Xo`w)=?CoJ5n|mx{xviW>vA`yw&b(>0Aclk8ACB>>C$WnT!BScfdwJe=F>a_SEs@L|g~ zJ;*$JanS6_s>23m3@KiSh!ADChAoo#hO-Tt1;PyCP$$33J=C1oi9jSi8vA1|dofW&83$^3ZE%7?J7%YY3*DLU+bc*Y)U6Q^Ypo zCY{3Mt}5WN^)pE6*-5 zh~XSs;<06=h|7;GR!xpNF288=?|A~|E9q|QqH!fEWp z&tI;?2-#1yF)0n)4fj!<%bS>A5hhpG9|B&U<7s;EDAx8!v z;)xp;ff)HCH7fOFdnbJ-C^TSfOalZT+QD2tCOH9}jj%Z}y0G9-xyXdsoEg@od2fqT0BsWfn-fxT+xr<8~YZ75Q`14LQD{$nTIuA-)@+hSHs@!@5eC57&c zD)cvHH=)g4b+V+4* zGT1$$Uo{ZND;oNoXiQNh(}vA3oPr5~14PDS4_=r++%2)|hZ!7s#Jb$sS2=fvMAi!< z4M_kBkStJ19%AttksQ@$eLKg6!T4w-Pnu8Ef%)q9R);c`wdI%vTpMjCA@GuU{^yur z>$G&@Rif@|eehUEUxmq~^;a)*sLllj&N<{W;}EWLy)6fMS`(JM>G4>QZ*gNLQ~5J! zbPu~hB}AoFX~Mp{ETCn6{^HW%ByZcvkL$Gfg}&dGaim3e#=aqgL_!YV&48Cvj{<;@ zDh`9%l<9z%zbUZRLB3Q};gM9kYp@*{CZ%AO+Pb{cI5B;fAfXYtH^;%O0&Z^P?} zcr{Ru*@+vb?9<_ef^?g6jP{kyB!Y#_sy?73AD0;Vxh`q-o_b|hNcK{l%Vg#}3GZRh zmlJ*2Ot>UYl!nL3xg;cZw5h#drjttRVFy;~B4!Zjj6oKYgiU`&sPpF0Pxeab#4uwU zZCs{hKP=ja+YiA^r`ECi&?TRdE%8US$wR&Iwo77EGI)z;x~BHx!StY^KE zoFjy86ZXYI6efr+3HQw#hLB|Y6CbJtqZ{s~d#W@)#UUM9fWFi2K7H-L8qTlO>I?Qd z1NhlrlI4$FwN`^6~6Iykd{aGs7Xj4K-~a2dABE_giVGl%XIQpMYxRV2s)USf6F&? zkl*Sy!US%jkIB$fWway2T+qpKZ!l$>Idwbb0dXZ?c#DMF)A30jAR}+)NwR6$i;C=0 zbzar$cSRQLvB$K2wwKQXHWo8tP&i&b2SLv8P8RaL7WElcV8=CgCe3*rVcVv3q;4HV za_Fy7GzlVy(Jt>PAbsfE1hiyXs4}}DF3>^e({LCmiQyYMZkwqlrCNm3z0CU!u4!Ra z$9uq;WmuH7?xxCjL2i(quylWRFHaFNW`|7lAHZtlehLS|#XTlYqrqX5I3-(xiLph@ zP_}+0_)hIK_zf$~4u3QXl12P&Ia3JaSS%rCRAH9Rc@L~y^|g|w^lPN^nk8l3T)=$3 zT|V8A7-Ms@zU-|dDazTYuUrp%%>xO^b~06|yE^jWQ(_(4%mkR&5*A83&N89+Emf+h zt^fIUp1;QMZga4KK`2sAF=?!JcPuLTk0w0s=2++->P)IBm_}2Jr#Vv8USjtV)c!Av zyw~%IxvS7d&nB8G%T1)%jn+ey0XmYyaZ=EpH8<|3!BsDaR=1b1sFn-qZcJ?R?$E`W zR@~+q19aN{|2G8AF!U`1PTSS=Ed*|QlJv;+Az4-9HErr_&uW)!H+R`nEp{wiNl4Di zxFfAvTN02v#7K!=upPYG#Uk2e&C9Zp4i~P|(RBI4$^BC7#b1Ks!#CQNHj!9dkIk2N z9+IR&=8GywKtRFD??YjJ+svP4tVR(xy_rbfqP9wwi*A;9)zP3Zp4OC@2zXiyHD98Y~Z-e>^q2u#&D)}7m<@%zEwMxh9 zO>^&f{cK>UO55|-Rs3_YO_$ft{nKRLQ{FnCrPs6Tjq}&5i|4kGow1N}eD7aRZB-lI zbw96Hr|>%u`dmCLT%4P-UvN)fQe^Bt(FPHw8iwO*<6Et;!W>kkJy)uYWyxPnwz9dt z`AF7dnAn`%J72O&HH0u!4e6ea3>hlWcEY|nWmx|bHEp{}l9u_rT_ z-tU0>nOwKJa(Mc zr}i`li{Q;p!wmMLjH0SOo=zN#x8q@JJ-TWgW8*Y_RVl`#3l3c&N!bD9bKqz}!$ znj5GpxxD;r8>UE^TM#E%zfkbZFrZ*RvZ8q;vw%l^iltCK7BJzfRU&&I*ooIc zvu~h*9H016=o&@9ELqZzAA9n#);A&;5Suil=m6arpi&QJvjQJ}lVc=6%BL<^cq|JS z^Vv&Oama{yBUEC0GZ)yUOwVDKL|^`tBup$ovi`wdRUB595Ecjm=m0wclMoEgY>(_0 znc&E_i|ijuKesKR2ZYf}`5lg&8NGNI8=_dfqF_UkC^+5lcj!N0{0IS)1`mST^@G9! z?=zPL=W@i9#=|P-ToqSzIb9uHn8ftE4lNwiYr~9ih^R*;i43MFM@Ky@Goq0)V23|* z%sS@S`T9wg3>;Y+R5`^6Dj8p-Pd<}YhAea>*%UYWTK3?p`I&Hdg$UeGt!?y4`BV{R zxGElFu7kk!;V$?brFAixLGSk<1w;A4RA? zMs_p^qC)w^F7-}ea3PL8X%PW+_OZ+9z9aClVZzjsHM^f?*ge|>!$YBPC1D@gGWb5T z3VxSL3JY%H*Jdu_hN*`%0fw-roaQ`$j+Bb<4nk?K@kgm&wKtikMW?Jx@*2@KwGCFP z?VUl>pe2|y%fS1{hNEgiHOFEH1=ibvESka?=fQwPqIf?@@rV=CY_764<WE7ZU z6%?w0EmvIV#_QYikYwP8=%r+m)kK!Vc49NG^nFL!WV%e(n+~23Cdz#tnZ;Fm#BB=W z364c^>8c|NUnQcxT(S-y_ZL%lH|%E%paK4BUlwbkl1;bENkdlH$pk+z)N)9u*KvP! zwpxb;S!$`0=l+-)p9@S3QO1&k24U4y3Ti+;x>`P|Xe#CS!dUW%FyeLRW=C` zoBgNn_z{pt{LZmT+~nwqhGk$*dl*v2HntkTZq-o@(#%k}%t~$^UK;ww#=ReD2O@M- z`B7EWfe+D6M&~;|sI01n+<#xiSn`JL8-*UAc>2`YTV^j*22+OA6O+_n!3IOv*c99a zKk7IvQ(T5#W9$D{UK$)}# z(%C_cOx8-<4hmcIojvx@vC&^RVHUfacFJc(jZSodHXe4e}iys zQh9zIxqL~{(!^wvq%6TB6vyn|t{P(&jU{8%a>2BzZlvV-7;RzMy-BjnmO2g5BI=0= zq4O!=dU5C^X*ajOHZ)bVqwyoRUy0?}i2wtdLh3bKk^PBm;=Mj)@&Ha;mmy{4fTC*V zB;Y}@=xVN$#Hl6_lx}Nbsz(tP?v<`&RGwZ8b%bLP=4Qn(Pe_hLgMMH9tl$$!ipqXn z)`v2)Rvsb3DIOEJ@s-+PXzD7M^UY7`9vZQzYPQM5S~!dBNY_m6D~xNwUNnp&1(-H_ zz?_N?&3VZ2C%Ytvkg23o@xxqkuYP)w%P>+TOsLa_iEv)rse~1)rcMpW&f$4<*t0E|esPV=seyb*E+{2_6;q#sbJlHv6cUEx);8++DviEU7itW!Af2b= z2U(YJ2>*7RX5g9i_;I9FyV#b7vYFAiki>_btdU8DVcorByyi^Pv*{i=06#$RTRVSq z+UFJ>zS4$Tt92Fvw>_>ys-2M>A;zD~*Bz3GZCsNpjPiHKfHbQRCzg$DkV8Cs++W7Y z{&!4R0KPF2pRe&{H;X3_{sl(LIYrO;fM_h06Zn(F z+TzHx*x?9cI6pQiEOD6au3)>}C}Vfzx6f;jt9j&ROkQh|cd)w{9wfDV0SeRti>oK` zR&YetHm8g@#asp_bEiY1cS>X4jFEj4== z6GF|r%4ey#C0zg)SuTy)-Td|+icNx$!x*CYj8sxR86dmWdkA5hfRSKHm!4fZU&Gay)IN-R%wF{L2@hXT}sHCgMb)sEdi`NLR17NNt>dn=mR;--sSm}BN-YmNBe z_#f(Q8&{d+n)nBOo0vzlLjlY&uPd``L`?ThO*Y<7SEsBmq~yngQ$El8vo1Qkp4WQ_ zHiLEb#`i}dF0bAX8T3*Lf+7ooc>%rrBSd3nH1LBzE*0U=u;|OtbdaFj?#}tQO|f`` z1i%ybn`ADSCVeZS(B>TwPrq|alU;uc7YH)4X5?5xEFSSEUkRW@c_=MoRbhBvU4pD>wh7m6~R7P*~rzHEKOR-K!L)A-nzUAwgeVe%oAAejFlPksbA->sXl zK!a$~Ic8SJWeNMMSa(JcoVGv}kG2N!kr* zt}?6VSvz5RcKy~~Ju*t~Wpn9@vt9A+i=d=uSMjU!Md_9{9gnt#J~I{j?)BD5DN20g z5GRQZZ87#2fFzL3aQu9}6$fkNxNsE*L;%J?uRgc=nuV!T)QM)7I=mnDYZYarM9xLk zq^P@`adE3*9nVd-Mhzg4!k=eqX4gkxP6saU`!39bpof!dT;my1o zKpPIl$IflXesNb~6a|@5PIJn!I+TRggCRZjQYY!@=v#gq&SzzTP(h_6j z!pHm+7we)l8kJOu)a$rm7f?NOu?L_JNtqP!hKQA6fwkd+SNy@9B_S7&Lpgrhk~Ugn zR9P@^%$b~;)FUB_?SVkt1hHx(4KeBG-r>FfaFDOnr&tiXb2U2qq@MsQ0&D4D#A3** ztPQI&PrdSDdLLa?762fW``S?_V0IT0XZoU=r~GpkRN3CnPtAcbxM6yNtJE@;B(c!? z=unBWUapjN9A=B|i!cjCW_oO=0Q_|$o#wOG><>Y>F^8%}PDKuNDi=xoDpF%24d`ne zwb@4FBc(+$G};*^OR7sgmLl>4NJnbzp&57iXS+wk1(SiYX(SVLc}lKG=REi^w~)dh z*+X+B2zYqQph77H!U?G}O~#CCqcRS-%~@jRJn1i0kqwk=Uf<-phQG@*-e+;jl+J#a z@48!X{ziR{r?@jzUY*y;aWCVZW!`lP`EY=S#9H#PtM9s>_x2^xwDl|b}{vOiPDhJ1^zlnk>=Lc(FORHy5M!VfAZ^UG;6Dp-9tr;5+ z>NSirmFn2}XmuFHu{H;Q4%%Q^u7&&6kGqu`!PgnY$+7j*9No?7QL$xI#nkX*OnIxU z?vUlGD&4yoAD(vb;ofuhMzWeCCaUl+S{v#?GNv6R)(NqS(}jGM#u&gusBs@oNR%_#cGNWSnbZ1( zt}JYgs|0;CHcy(kVz6i~7thFY%mmqtDou(rmqLFd61v?;c)KPJ&gz&coi$1dfa4kQ z-Sej0;G0n^RwR%E1Uo6wcs7M$_q99T6o?&KP9~0hn}#+Gc@pe?rJqaHsS?Z;gPG&6^Lfy`%I+Mc$air10XiY-DQsMuX zb4Q5VCm~K)=Nb6P=3PaIM%g_rE&K;sm`5#Mi8 z;fCyTV24ISLwfO+Q_?jz96W36rWLDbM!nUDU*N^P8vx0s7|IsKocs-Fx^&^HW7p`< zddwV8-e568yEZB*X>6R#j89=TG)?nC6*8%O8>PcIO5J!)V{qlr3Nc$uaatFc3(9P` z-+_x0HsD?hXZp_xCZpXWJX>IkZ}wPZ_RE5IH`~{l1QHb?%St2s=bGKIR|Q*pRqZ!8U6E1Gdcx^_fp?X~HVMNKwt0rBj0Uw#lP^)zmsG z?@rBJD7QS-13z)nBg`it%iYf{ss-A0qvdOnmr}oPB1<{|yWPAGK52WK3OBw*836Z- zs*3FCD!sBtg-=L!CYxWqNbZQ!Maj1mJ4~Z3m9Nhff4%!fjz@7p;4>Ll!>qDMpsC8x z)U4D|8%@%1w8EyreE_&v`s)yd%*nIsWeL8#V=U0l9U`j~E4*{D={ z6`X4x&)Z=k>jW4O-jJX+n`ZHeQxS~cRIm`5n4>X>v4qKwF|m}po+IhnO121FdU|TQiQ*-a(kKT}|ByS*5JPQ^f!ilPI58n19bH z+vB-E>U=XtxYYaS8jOgOnV^kcP?IBvotjEk8mGg$PL9s1pTjo|elBUZ06YUs=Zz}ncV8ytD^&^D zu00~aiQI+Wau4z^>1`4&M@&?Qiv;}*mSgHQE^iBTf~~Q_eUxXJYn`hlLi)@ED^sQ( zgqQ6`m?QBDi&VbFJlXRtmJYL3YGDWQWNlOfFMql?CLm>%XjF^@%w&z)b*3w-iH8E7k0lnHw-fj|j6b)FQALimX>%8ZUKIi|I-+?0P&T^kB|=Fx5)XH z^9@XEDqy+brw`IrBq>w1QZ|jr82oxF^nT%zfHWdWbgnx^ED@h0Jlyn1gjj;Efl+b; ztLOo_G=v7Xz_O7aXtX8x?zlccfSRFOj|YVSqZBI~Nbm%TXu&bNzF;yA?zFaMtB1=zEf6z;E52Wa>88fYFPbi~nqPcPLSL90MKpn`r5 zLVllzpt?=i%qqYxdrV9%hERndvbVVVr>`d&A7D8JXL?LzDQv~kR)0no1We`BqJ7Sn z6B2-<0}dHL28mPcyE6m=FejuJJ}K9VoR&WdZL<1qTu>9^{sK=-Z}WIM{o?mcB-01R zTVMg~qduI>tuu`!7*_ML45jaeZGm?mX%v796*Xp~i+_R8@Z*{FC?B?6r>n)G2&nsb zJg^|!>LbgfGlyDa3v&DQc(sa)O{%ZRuJ%e~(V_a4sZrGCxVN+gyV)#3tW{HArrUvQ zHbY53+AgxD1lt-EA;o~A-365H9)yFtE70BQYW0S>+5~X*2FqonAx}mvC%ee^4lS_{ zKTjz@zfoPWB=Akfx-(i>X#e9=PcdL33f)USKzz#{iyF z0jVUp@d3Ih0IO;mBlyQTu=xv;6`=i==0d%^YcLI zV1Fk$iW)&p5KV%sbScStRjRKhR;|uy#LAkmsi>{dg5~&1co6N;b^KE_WnAhQ({a(> zoR#6Qht{gCSU#Ft!HNGK&SYxr?j@#CZO;9#G#9F`k~&+L%yA`Z>OM{v9Xhb zk${b*jlF>(kpE|sNud7)fqREA{1*)4f5CkIFBqo(f?@tI7?!^nU=UPL)Zg8UW7oug z(+-*M0Rsf&Z2iy9etY5fQSbMUhrfTCWhMTdMAS?G%6j{JZy^PYvyJ{GlkYfqlzJsX4l z7t8oRwfo+w{!hD9pZ;Qh`_{j2_r1;fAGVa@FZQ?T`g``hBh(+3llw3Bw?EW-_Pt5S zAJ$OdFZQ=($b0s^=EEO$+UPI#w*tg__Pr{?ANJVzFZQ=a!h80;aKIn-gXv%FZyAC2 z?E8H6KkSIvUo6A#?DhBX`yIYN@La^-@c;PDdOtP&1FL2M0lk~3zHj*-h5sJx{=fnS z|No)yeJ$^YzCX2iyw&peK={9r|9&-Az9Sj_b9DP1%J`q7=!O6Oen0=`sQ5dS=|4xk t-=WO^Ia>P;Ws#Kt1OG?=qrcrK!GM7F-wGfC3ELYP349SG_}9qze*mEV+noRa literal 13766 zcmbWeb8u%{_wF0x8{4*R+qP}nwrx8dJL%X?$F`G>JMQTAe$V}#ckf+wZ=E`G{jsXn zTAx|7MvaWukSj;n2jW%Qkz=WCf{SrRhitf&+7@eMFx8iRBqLIeIJuyKQMrl zNUyZ6McFpwggFXgu!k&30FI% zH+b3Ienh*0FFD)?^qWL}(GAn8EEP48&Z_fDXruP)=|PVmZwb8@4Hbl zBuOAq%DA$P!cvkVX4jhrP#;iz$7OiR70|^T@;bCn!waLo*V1u)xRPOOw3E#^<4b>% zt6q@QaG9qh-Q4nNwc_#S7&j9M|3+VOJ9j6O^5DeTN3_zm<$IubCrKoCsrt6K-=UnX ztOu560kK#AHalGY?MXsCXq9}j7sv}}6G^t>uKp!W$QbLO6F8cU&t679_b_lLanA3y zU(+x#X)Rq;KnCA|IljvJQA7+mH$FXeEs%vQ%bwk3565MZLY^NYN0x!zUd+a7#Jql3 z-8Edu13imj)b z*31XoTrE!MTvYaZ_M4HaCgSFEZgo)U&|>#EjsSnB&XK}T3CPMW}2C`X-a@9 z7-9j6F0tAcW-aRfdz!r5w0UhTa85rX)xhlM+Y!l98;m}6$yR(ZIpP)GZ>MoN)j!ShkP*g93*xCyXBAb_7GZ{C%7uReN$SL3B^ z5daxQVxVND#(_npTVL1}Y9q87YwNr^hy!=9)NF^_mWV9qpOwM$@xiAih43_m?neb} z5mn1|-_)2=N&Wp2lTHl20`5Vzq*c3|RmGdw zmgI(-Y9>S@6gC02XpMMb6<3WbFg9sr$)W{6SqHgQhCjZJe1$lL>GCo8H)0xtWi@?#i#cA z^Fkbdk{s519s_@}LWezQ$nz}5ukxsBSp!EQQLDyB9&RD&jury4bD1) z3=0!gFSVh0Fc$;eFmh(sJIMZRx_(AG#W3)+=xPC-^-Dcg@}w)d^Jb*;nYx-qO+{s_ zyvz#ylB8#qkbI-!tw&#-i?(~)b;Um$hvEpOqS<)f0z0NDI8(j5KvVa~?JknTD!T?V zx=DE}HyOZY3H`m5R)ona^(F)k0q=tUz_@GuMaV1K6a>kGjl9D%VQi zgddz`s4Y38cTV375+vKo%`J>DHY<4B=!V9Sb2I`Cf z)d#NXx1dJt3X)#&pH}?a^C!X%CiI?@URh@vbXZsDrs?u}RoeA@9T_O19Jb0q0f$Pz z1cL|l4|js+w=BmrwW{7`6?kUtAig#-!d>qn-Wpf!4eOQrh-ZSn2I5`cAv(k3Y>^xE zj`kJRCCd46$E4mvN}-7lDc2TcQ^+n)wWW2>Jua!&0N$G(hX>)wwO1X$oxw8JgI7Ta zYfkNnb`F!}_E_29tZz9co|ag~vg@5rpIWk-SarD+nx`eh5DUI{uEk8BWG6?OCv`!dShqD zva|vFO-9)88(#q4swY5ny=l<|#^@?`DcQFI?zx!Hy2mU-u($bhfc)(?oLN9779KV zuUo1SZolumu=M1nf`g&?GU8IB#JjPQ`^@ z2t}z(LQ%xG3@Dw(2%Y90fJeDaQroe3_kt@mm512o^g|6p*XD04w zfEkA;r^EGJWYWmEZIePz3VqPn*pA`tY`uKYIdpYoeL>4FLTZ5B%abEzmnZjWD-L z7K##;>y;~&=u7Gor8{l6p9 z;NC63%b8v>LK@5ubr9TZ4AW+d5_BFkhiX~Xf9%yhkAh1@CQ9lRBeMN+;RZ z5DJ9NW!B(8;OR0mS>@oX^&7Pvd0XCiv!#14p6gPzWO8Ra6&YN0#*mPdRg|f|h3du* zWQEdMS?D#b#hz z%lB^u9x=>7XgRbz$k+pq;~7P6P&4$0Hu1m^09x0D*(SRt6oKApy#FDfHHqagMXmy#-;P zu^SKJ9mx-ds8Np;FLAVqaq6)=*C^{MN_~wFcim`j2Dpx=Eph@dw1B~4wKfHCmKk-lC4(EmdFIRn`JaOr)&VT=l~;Bg6NAvrxHIk z3kLPFZtBg;jUEAYg(066)lw1I?3w+XC@7PL zqh7QT^4GqzBiEOgNPE|Stp>V4vHvSf8QKmLvf*8s(h|bYWr`9$6ka{>fcuG5bc)p5 zwD$pl0{-{U>+=#nK}d_=Zv+IpynO<`zR!&8w1*Jbdb?aFVp>a}-+PRy#phXG3auVzOC8 z9d|g%he4+J+LG@iPi$FNjzF^;sp+m%TINFp3m1ez;Fj8?Y#{F=<}TVUdD)28T_@kM zhEM3VN;zL_m_1?j#aDA!2fZ(%yzvwmaFLI&@iAi&w zOz3mvgE{UZ)dgB0Lphc6_2_h(42NiExOddX&damsXcCU1M+C45vY)xzC^0GZxT<@| zcFM1&u+J^it9f|NEwIgR#|!s`x!PSCn0xK?Mo1E;GXq|7GO5HzPUiC?G*{6n;ZTtN zZ1wRaU`}vBoMXe-wae%&YK^3&^NcUF^Zc zDRrP>Ej-wBnMHz6tb3?Al?~uxjfD`@_q6QNq)Or794oA>DD;^0?(&h9p_$w0R35%5 zurNuk9gB&9C&Z6?n{BUo4Z5f1u z(FN96y4I4ONVzzn$j~X;Vzd<$`>>eM3oegW6dNI{BGFu!r<{qt)FKZ4Fxbc5n}TC& zKf5E=s$m)zFI%~=nXg=m<4D?-G*Urpemq{`a480*p+QzjAt4RJ#JY&2(V5wnc`xOr zkTJtmWsU1F*xC>c4?2w)#RHw{9xv5dZr4axau$F$Fyiv#A!zOn?1lNzFyOV^N;>=p z%&!@AQ+c77CmR-0%gcDWc4Ta4*yE98?YU{FdnWHlJ~Lb%mLOt2M#@PQe(R~++E6p` zao#dqo|GVE@*rVv^*Px>#{<_?3y;bo8OsJ^h`5p=WXlsBt~diL&4gXdKu!A?r)uOC z-72PiQ68ifmV_pgcpQ0{o?=>I`lsQn)u?&4KvrbU5dz$8Ra5yB^J_&;ER)Jy0}uyj2@+5! ziRNj|mvy*EO&X}dCMgD{9&|xuomwEUaN1lS>{(clArLnpuz8xg@Rn5QFgEBL^dhJ? z5JjrgLLxbuKrrkVz8)VCsH8HGNa{)yEeTp`;EmkUQXU^NK?-v@pU^UfNs`PKdks-Z z>lQ;w;dW0A!YuivYr)@PNT` zS>nLNQkpN z^HA9V?A$Usi0jo3h%0U7Q<%3y7U=^u|HT@Y@T3`i9G%BQEyf`BM1zM$DsuMx zE#9R_o%%(5#yA(;4TYPWek>*kdY*?~#3}~U6fE1=K&ybhI{7A^=>wuU;B@vs24^)d1C{F;c16dXr?>;Zn_Th%uex1S3+5dvTLclUh+`5s@JAE$?hIR)+o z1QGj>9uE2e&$k~hPv`fGV-?SRu>zF>aRHvsV|NZ+46{6U4R1|vuR~K26$(QJ1v^*0 zdl?x@>q2mcml87!5?p=g%WV7wF#Q-y>|iBnPd_NB%KT6#HI%jK(y&^w-GWq`#1cxd z!?2HUt_IW(R1a77LODV=ys?ZGm8uip{S3KjT!klqC~}fO%+WPY9NpgI8fp38A@n&h zKI2ks(eCgx3X-Ez_Zay&3HR66p}%>r`O$jpFz`Vlm?72o@qfKn2KZuy;5+6a=c2UZ#@xde7oGp@vD`3#~_re?(#*4%!A*k!m-s%A(=Oc?BW4 zQ(l9NsZᦼtE8*hggt3Jh9hHn$wfCOYY8^9hq8CUpQvfhHn5p>3uOuH3{M5!Iv zqNf>9_392pBAoE)!Z?yqb!js~*k;{$DzygZOQZ?mpA)`_cp#_IN zbg@_V-d;YjTGgtHHDtj)s``t;|>m(XB&1se414TB;UtBt!r{u3P! za+)-HHsi74!glT|)H!OUR=Ejfjg2g}TSvdrUo{PDcXaJ|4Mq5t^3?lQ=Vq+=OUtOk zbQtAe+UBV&O{wGwitCd&ayPRfndG%b#vGNoRn~q_<2>Jz!kbN42ifgip7+o|>94{H z3IYG~wcT?J@R_mO7@_4((qFA3O=ynCS|NmzwdE}EhT&@Wyerx`%l8pL%)^;5jfYlvnoMSsDMcZ?1H%lws@5ResBhlj3##aBC=m#!OGl&RE! z7wOkgfqeeYU!UhGUj0utzdvpYcK8F<{Jg&&4_gk?hjQv?zqWfoR~I{df-WeMC$d(; zIpRJH7xa%52%Ll}aikD`4eWu}nb;p{tJujSl$lpWa;#>Hfv*SKz!r8jgd}NBdmV~_gl_DYE#Tgk1+wz4<5siy4$|}<@bB@^Oak8Il9)!n*dz# z6`@6Hysiac+6<+M2yHK%fR16Ng?(pc@R{ufDP)4k%v#F#suW?^@)eopo^dM@LJq4i>#TmXwL}A_mxU2(%+ct|;uy6Zr43m5K*d4p&R7)n zj$9)#N@ys3$ttVy{7_O!(}rKI;{J`_(&l23u{MI)28JKxeNvnb@2;?EG4%tFC-lfP zS$*rlW6JNnrB;O6B{p4()xo)sz~FWtq2^E?p>NXXf*s;R%iv1!sT4Q)A(<6Hk~8+G zwbW2J!C|a-D+Xdwv^Iibf(E51d$7Y{cI)8GQ&FDE&Z z%II{lC?(3FBpe-Zl{Ce|93_D>N_+qvE2}ltH0Y95fuorq*v?R&mLv#!qNyw?Q6OO| zF`8FI7Jb~2eCl+~4h&UQBb3k*>sw?Rtq3^jSZ4|`@n%z(Jh9r8A)@JRnsStPlr|_v zVc&ZO0NOA$v|O|%t-BLc{FLxpGj+uyy@4@YO)hVZi(+P!L1y6$KH`Gjq|57|$a(;q zjKt;Fwm%}&4~1yfmbdUyX%PrD&2}(4%5KC-JAI{NLsPOkP`XWR zw}glv!8-Cg`)E;;7sF|4@a?*=d%o;Kz|_DXHq%x3pM<7W8gBH&4_5Kz_I)`VlxC!B zro$bCO3d=BZ*5>1YM4Mwk@}M2scpiP6~vo4Wya7sNY!P`s-`wEnxlXt!TNZ_sRtDz z@suqmNg$Ku$XYsAywXWD3IHL(#ZKTdPzAS^n3=(FiADGZ>6=+=HxjHeJ_TQZa zb3P*tt=|T|zy*)2=e`;}vb5xUDHDrjnjiA@u$W3kxXO*B&*QCP(*(Wg3BzX-T(I%f zW+B*Gg0_X|M8w+KBIPudG69HOM57hvYVk7^Y;|2O!;$O=OImccoo7ov2QbfUXZ_Kk z!f!kdbn~{49_*Gjma~1`zbU(1txs*ge`sn3Fe-u+|H;Z{0{lks-`w_sjKXdjgjf{( z9S-V*y6E@7#CemT^nf4;`ZGG@SgFds+pH%Pueq_M3@dOPj?Ph9PBE)x;X4$Vnt}9u zpW*>2SSKC(>2eNuC+(>joUm@ts&s+Ztb0JD`Ha(ImeT2Pvc%E{AWGRcq%~=nKG@Q3 z$YvBy7^r9R+Ed?JWdE02*~P> z>iiGAkmavdGfip0evlEi=Z(g9%kbM}DEoPml6?+4+;F@K1Xi_bYb7}Or@uU8N+8Ot z(h;TCEQ9;q3pzW2*hRp*1)BM;KMD}};kv1=tkaHdc9j-^;{bwZd-s?{pIs02`^wE! zovpQ}b-F)|R0K9AXXA?Hik5X|q_~h%_-WyN$w70ov2aIN;7{dS<-KAM;-Z6L)AZUY zx%>sm3!4IB80@5DI%HY*EB-Sz4{09L?`or@soHkTuQmuF;mE{o>Gvq5`mpJVlONGp zay9NGZNtI5&ik$3;4jMA!&13U7#_Rn{CalO#^_O|-LEnX!q1L>!k>Hq@vt^P^$R71 zttq=Tl_^z3&Hree$_o_g21bm5Gsf(91z)@Wgbj(M=p>s)zJl#qN@S&1aCxaff`uEk zA7>AIMkchLcsHsH;{?JKuQm8*unms~3z`2!*M)YZpYqwlz4hJF$6lhx2k`2R@dEmaRK!fz9H7kk0Pkk zlx>+*__0m;rUS(J;&vFRjb3;4UTF{Ow4maf;wJOuc&9d>V0)`981 zLYQvbW&9=sg4c8W8Tqlxj1^a^2Z()jv?bA&=pf;-%CX7dnQ}tRb$l>McuLf8b>~8q zGP97wODZ@EZ@RE1MIEyd_Iu&@;l~BkH-#Y42zYK7QQ=x16syqpD9N`y?2}%jVOy&N zU$n!6C7-QscYd0d+_^`F_+JX^B1QTh(U$JJJ+QxuGB=ipPO8?TO!ev{LDicGy;Qq| z=~oYA8Aj}(@kX6uKW)#^6r{rF>o^3@W8WG&(O_Gy;Xs>Pr8O#ObD_1kxjW92MaGi% z%3fi}Tc6e~m+=!n8s{;(I`F2`(&#b8Z0X$j?$<(xZwt2m1hppkjR{QhZJ_^(&`y#B z#ls}Ns4;auXT$usP^muFjmo;x{r05M<#THqj>F+c_w_zeKaFq81eF;CTSJwGNmK!Y z!%TK3&6Q@gpGi5(BscKbVQUYuHpypQ2S>!tvET}>gIK3Uc#asObU01psWeyij%Xgp zduA*xnZ!IS%JLmbbNebWmyJ{$Mb!4l=1TB1pKhFsG&8rA4D_sxSgb!^aDcEx7h}2p znYRYmuj+1lJG9l8{k&Ay?|u4}@i2TZ&TjqRuaC-UXm~^%yTHS{(!*>LqS&}}irk$X zdi5-a7Hhf$MdDoJ9mmJws|%4HL**Q@YtslXIXKIe5oUidvr z{DxhifT+nywTzEso|SSR21Fs{Ywl7Q6Swt1;#K5!xch-xkgGs|7{8!N{7UvO#6UWN z7!M2w#)YwqIr^qM+kv`_XU;6Ap+`XOb!wrUdF)H0RnXe?jqFx~p8P-rB%&BU`+s1! zwOe{)=S%f`K5=i78g$@z6I(evE3y-Rj4MrWe~6Pz~e9ZX966oq<-A6szU-p(^W$0 z#N&WY2&g0&x(_9!GUzh9Iul%FzOidR26W78eSX z=~a0Um&TegTqHr0$m5>ot<-xNbb|LS${n0J>Ca0_k&_fKxnzq7lS^PWP*E4T@@N8E zQ!pXrQJ3+riY=70G zL=kTnA=DL#9vjo5#m>;-Pje9{i}SlfM^^1Qx)8$p4Y&5lMO2PHc$^pJVJV3h#Rhy`T}^q^6YTgu z-_3YN%U|jL5%O;$G%DF2{Ho%_E8K{$Q6_8`8=M@fwGd-T^&{_jB@=45)ZgugD%sJ?9*v&l=;C81q>{I*ga!<_TRG{*1INoc-mIr%HO58}POus#R%GH>R z^1CyaFW3&U&G-;5Sblou$Y>|KP#11~Uii%W#7d+&Kcs|P*n){l=<1{T zQ(OM9;o*DS#E^Kl`Fjg4`m;pM%g4xd&gw`hE6B+aCvZqVC#37h6VTnrwE}|Thtl#$ zWwiINw5votJ#(GMe5S`u4o#f2cL}_*>FzU9cKD4}xANhw)Jz=_i(j~xdErHiOQkJ$ z3$ofI9^>GVN@6zeU0n9#W38^zIidXUm*hP&5cviEx=`Zo zX$OJb{W95g-E>c!p}|kQ@^%M=QRMLwqb))xO)Q6^rfbF)NpTqxB4ch=Nw#~A8cAzZ z=4^SMDDdm7xD?`O^u+k}33W`MAm8St3_BKrrDS#BOblhTcnhDk9P`_(Y&5fDHyt^1 zyT&9e5k(xJ#X(!kjLO+;iOsZSTC#POk1922;`02M1w}kPvy2l*4dqJqPqk6(+@OhR z(!wn`#4pr$63=L&nKfGkvFh=P=Peb%QAg*dSht0fKfrpb{R7ph0oDUE{q zy_}A9!nuRKP|`OR(Xxn^*D+*WvJ(B;6fkgvc$5eSs(y9wGVU7WuwB zUI6ji)dT9?i7+oC7p&JQ*$M-~usZlC7sXzh0_rl$l`7K$37K1X5L3ky37#{-6?naZ zw55eknP7K&v>GW-Aw1rMlLV2;*8-8CLNo&u2@Ef9h&E6c!Gw5%m(FRImYbWoH7W|7 z(bGS-mvg`}V$7zMl*tDbV!o5sYcCFko0@SU5I24A{5|tA;QQNlnj}B@;9t$ zxB09gp_(NsSRMiN4tJuQ878s@c~Z%Cbf{x+&xXcKq41PT5)C%=gh?rG{1fN) z?ZW{jhV62dnQWabpj=>7{uf`}1f_MdE`sM{#OKufk_+pjFM&hoe88)Uqg8a?JM)QA zAzMZxN_z6hkDz|Gn2bB#9nB4sLKQc$U)Z3DswQFgC>P{TGn9;`vaRIQnD4@>5+hMY z7T^>o6UgMKVl}>~c{a;-D`*v!z>(Zvia({{pYnjtfJaZ(1G7^L39Q1@d$v|!;6p|IsH$GnI zve@DBV<5FjC93m;O1xX!Bq!LY*269_z|Pqq`wT-5=;GVj1z>#A2G06@7o1|Wa)_8e zkwfv$O5!gT+PvUoi-WpI)FRY_3Ci|?{fQ;D;gYbQjiei8E#ASm96LVfR)&ydN*>h$ zI}0hHDa^%|Qc6Q6wmYAIsNS^EUPVXxZPpM3c_K{wT=0C4lT~_Ka*!2ETBaGj6t4b? zD&osea@dMGmo`1aO+nsu6o(q2d-zMc(JW^_@x2gNF$qpRoFN6!9;X{AExT}VwvjA7 z!FbV5kbT3SI2nZxIQo?rdJM_DI=fqMDWE85F^xAFmBoRl*xfI$M1_a3Oc+%m&oVkb zotkNn^aZ-=N%t(wL|fxv-%c6^e+>B@V=H9~M$Gg|pR{Jn`Mcu2;$}QZMYqV{=$V)e zRuqD54Roq@@G!ta5E!6*6uVUba@!(5wLMo!e7VOI87MT3;w9?^E1 zmGX_S=qf8pdTs((o?(lQv{zWzIFE2vCVqtJ$`^!)j|3j-%w-+Ip!}BsV!@j;aE6n+ zrSyzSiji`d_(rf&ap-h6q?)^V2v}s4{34}QMF@3hmXb3?Wl7PvPbtET+{h&L6hG@m z>@9v>bI#6?*F|QW;UyM52zT;>7kZd%S#Tz38XvrK1iUrz&A=hc&A{(_|L=^aCU)X! zP^$y z--f)>nqdry(e71;+1(8@DxY;C?cGt643AVF`p1>Vreks2qqo`c9oEN>zvPM@e+XMx zGF4jypqck`;9Po1e}WSnBQwa9K(gNjm!b1`iJf~Of;uD;;0Jok!y=?9GK1Z?wj+s9 zxKQ3Y1<#uL?15B6se$)4{X#LmJ$N%liTRz3So46A<*s~CA&s0~a2sQMJD_CA?KsV& zxv&Qe9b0Am0CeU>|E-bmeTGX-zF@*vftTQ8@4^?xPxkD%@1K8{WaBqVPGCSl2XsI{ z2!E_U5^h%iFluXWyBx41288z+Uu1Nn9y-WEIE(CEm*<&I;#&P)Q;LmbV@sAmKe9ai zeAdB{B@7!rftt~~!ieovuTInG)BE7Q;a4EZRLNo-=&~rc&jmgX!esH^<;(ddH6-BU zp>*@UWVy5-QrfbM(=Q0tOm+OzLXt8}@!L!Hdaj`v384ue5)0N`RN}MhsVZ>qfT|=Q z_V6N=GPU%=yJx=N>AuJiHPltwUIS%b_NrL_VvG4VW2*6wQC0Xz;yDbKy3XvB6?+X( z3YCpz@c<>XP%XFG5IqxWv=XVEdF?0P8l9TokLJ=~!4%TSqiV%L+QXc>4DqwG8bh@7 zVUge4?dS9IaFrgLu4U8Ar|V|=LiGfmj1=49CKzU6^3zN zVtR=5=F?87s)d9RUTWYcq098S5O1JE z^(?$zH~XA#(wf({%A7kGE-j{yB1T3sFaNQU_Ub+heu^eo?g5JsV@s?zFeOuxcN~4~ zsSq!l`V$hT`qpvQ9FLUqex2c^)kKFY<+YF1rTkTYSK|!G1)ljnQk+%s$UebG0I-4? zM*7JfVZ_t6X}_LthxT}xHN9wC7B`Xhh^Zhrro=l+iHdMubRTW8A?Ll2nxO;==k7y_{_IVVhypKY^ z($Kf|{>jkS$@b%lv-ehC%TLgTDK|vGQWajOw{vn&MbafDo-#FVJ#eutX-96 z*{W%WwAbwuGIajs&zP9EtDN^#K<+}wo8)U6nAA9R*)9>kHAVJ8MD+$KY{4+Nm; zBuQMDDBKFp(egQ*_up@4C$s)HzdtJQSH_5qsH{-1+p0IquU-saJI}T14h5%{`ReU7 z(b-X%kDJWE6f6mwYwU>fYR%gE=k%J*uJ{<%8=$_t18_!9q|DEWWSkXV_UySbQ&IM_Nko0tLxvsnE2<9Gds8}{$WUv5~@ zzadQj7Yy_N1;g?;1{eet^#A)%%%27RXS4+Ub^H6yt0?nN^4~7s|HT0TwFFuH@%{e8 z^ZRe~-}cV`qSb$b`@hlum_7f^{@YdXU)B-jZ|r|O2LERNEffEj-NgGF`ybKx-|W9t z&;PQL1b<`yqk;aL{dZ0KFI)bn%KfXt{Tu#!{`_@p>3>E`kSOy%v+4hj{44YRXS4)) z{EKAzKS!(og);x2qr3k?Srlc!A^utv%%3ank93dn$0>pcB<^fxCL$zC_&>?_{{S(} B3F80& diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index f9d0573bb090..bee08c236b16 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -65,7 +65,8 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) PartDesignGui::ActivePartObject = Item; PartDesignGui::ActiveAppDoc = Item->getDocument(); PartDesignGui::ActiveGuiDoc = Gui::Application::Instance->getDocument(PartDesignGui::ActiveAppDoc); - PartDesignGui::ActiveVp = dynamic_cast (PartDesignGui::ActiveGuiDoc->getViewProvider(Item)) ; + PartDesignGui::ActiveVp = dynamic_cast (PartDesignGui::ActiveGuiDoc->getViewProvider(Item)); + PartDesignGui::ActiveVp->show(); Item->IsActive.setValue(true); } else { // This handles the case of deactivating the workbench diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 87d2609e0360..df36ff97cda5 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -176,20 +176,25 @@ void CmdPartDesignMoveTip::activated(int iMsg) if(!pcActiveBody) return; std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); - if (features.empty()) return; - App::DocumentObject* selFeature = features.front(); + App::DocumentObject* selFeature; - if (selFeature->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { + if (features.empty()) { // Insert at the beginning of this body selFeature = NULL; - } else if (!pcActiveBody->hasFeature(selFeature)) { - // Switch to other body - pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); - if (pcActiveBody != NULL) - Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", - pcActiveBody->getNameInDocument()); - else - return; + } else { + selFeature = features.front(); + if (selFeature->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { + // Insert at the beginning of this body + selFeature = NULL; + } else if (!pcActiveBody->hasFeature(selFeature)) { + // Switch to other body + pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); + if (pcActiveBody != NULL) + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", + pcActiveBody->getNameInDocument()); + else + return; + } } openCommand("Move insert point to selected feature"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 73a47eb72adb..e28d867d3fd6 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -174,12 +174,10 @@ void ViewProviderBody::updateData(const App::Property* prop) // PartDesign workbench not active return PartGui::ViewProviderPart::updateData(prop); - if (prop->getTypeId() == App::PropertyBool::getClassTypeId() && strcmp(prop->getName(),"IsActive") == 0) { + if ((prop->getTypeId() == App::PropertyBool::getClassTypeId() && strcmp(prop->getName(),"IsActive") == 0) || + (prop->getTypeId() == App::PropertyLink::getClassTypeId() && strcmp(prop->getName(),"Tip") == 0) || + (prop->getTypeId() == App::PropertyLinkList::getClassTypeId() && strcmp(prop->getName(),"Model") == 0)) updateTree(); - } else if (prop->getTypeId() == App::PropertyLink::getClassTypeId() && strcmp(prop->getName(),"Tip") == 0) { - updateTree(); - } - // Note: The Model property only changes by itself (without the Tip also changing) if a feature is deleted somewhere // Update the visual size of datum lines and planes PartDesign::Body* body = static_cast(getObject()); From 3058d86b23e61cef867da94c1c808824b2e43a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sat, 8 Jun 2013 16:17:05 +0200 Subject: [PATCH 132/664] enable scaling --- src/Mod/Assembly/App/CMakeLists.txt | 10 +- src/Mod/Assembly/App/ItemAssembly.h | 1 - .../App/opendcm/core/clustergraph.hpp | 15 +- .../Assembly/App/opendcm/core/constraint.hpp | 172 +++++++- .../Assembly/App/opendcm/core/geometry.hpp | 13 + src/Mod/Assembly/App/opendcm/module3d.hpp | 4 + .../App/opendcm/module3d/distance.hpp | 39 +- .../Assembly/App/opendcm/module3d/module.hpp | 27 ++ .../Assembly/App/opendcm/module3d/solver.hpp | 12 +- .../Assembly/App/opendcm/module3d/state.hpp | 413 ++++++++++++++++-- .../moduleState/edge_vertex_generator.hpp | 5 +- .../moduleState/edge_vertex_generator_imp.hpp | 7 +- .../moduleState/edge_vertex_parser.hpp | 4 + .../moduleState/edge_vertex_parser_imp.hpp | 11 +- .../App/opendcm/moduleState/extractor.hpp | 14 +- .../App/opendcm/moduleState/generator.hpp | 4 + .../App/opendcm/moduleState/generator_imp.hpp | 11 +- .../App/opendcm/moduleState/module.hpp | 3 - .../opendcm/moduleState/object_generator.hpp | 4 + .../moduleState/object_generator_imp.hpp | 2 + .../App/opendcm/moduleState/object_parser.hpp | 53 +-- .../opendcm/moduleState/object_parser_imp.hpp | 53 ++- .../App/opendcm/moduleState/parser.hpp | 8 +- .../App/opendcm/moduleState/parser_imp.hpp | 7 +- .../moduleState/property_generator.hpp | 6 +- .../opendcm/moduleState/property_parser.hpp | 55 +-- .../moduleState/property_parser_imp.hpp | 37 +- .../App/opendcm/moduleState/traits.hpp | 4 + .../App/opendcm/moduleState/traits_impl.hpp | 2 +- src/Mod/Assembly/App/opendcm/modulestate.hpp | 3 + 30 files changed, 806 insertions(+), 193 deletions(-) diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index c8cfb101374c..7ca68244048e 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -4,6 +4,8 @@ else(MSVC) add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H) endif(MSVC) +add_definitions( -DUSE_LOGGING ) + include_directories( ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src @@ -86,9 +88,15 @@ SET(Assembly_SRCS ${Module_SRCS} ) +set(log_LIB boost_log + rt + ${Boost_SYSTEM_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} +) add_library(Assembly SHARED ${Assembly_SRCS}) -target_link_libraries(Assembly ${Assembly_LIBS}) +target_link_libraries(Assembly ${Assembly_LIBS} ${log_LIB}) fc_target_copy_resource(Assembly diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 4014a5ea72c9..f9050c55d02f 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -57,7 +57,6 @@ class AssemblyExport ItemAssembly : public Assembly::Item virtual TopoDS_Shape getShape(void) const; - //the toplevel assembly is the direct parent of the part bool isParentAssembly(ItemPart* part); ItemAssembly* getParentAssembly(ItemPart* part); diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index 4fed639dd04d..7e2e69837c7c 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -328,9 +328,14 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, bool operator!=(const T& other) const { return !(this == &other); }; + + void setCopyMode(bool on) { + copy_mode = on; + }; void setChanged() { - setClusterProperty(true); + if(!copy_mode) + setClusterProperty(true); }; /* ******************************************************* @@ -345,7 +350,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, }; template typename P::type& getSubclusterProperty(LocalVertex v) { - return getVertexCluster(v)->getClusterProperty

(); + return getVertexCluster(v)->template getClusterProperty

(); }; template @@ -804,6 +809,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, void simpleRemoveEdge(LocalEdge e) { boost::remove_edge(e, *this); }; + public: /** @@ -1041,7 +1047,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, cluster_iterator cit; for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { f((*cit).second); - (*cit).second->for_each(f, recursive); + (*cit).second->template for_each(f, recursive); } } }; @@ -1383,6 +1389,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, protected: boost::weak_ptr m_parent; details::IDpointer m_id; + bool copy_mode; //no changing itself when copying /* Searches the global vertex in all local vertices of this graph, and returns the local @@ -1485,7 +1492,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //TODO: Throw (propeties return reference, but cant init a reference temporarily) } - return fusion::at_c<1>(res)->apply_to_bundle(k, f); + return fusion::at_c<1>(res)->template apply_to_bundle(k, f); }; template diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index 6cb91602df55..db1fc39d19e2 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -33,7 +33,9 @@ #include #include #include +#include +#include #include #include @@ -69,12 +71,15 @@ class Constraint : public Object { ~Constraint(); virtual boost::shared_ptr clone(Sys& newSys); - -protected: - + std::vector getGenericEquations(); + std::vector getGenericConstraints(); + std::vector getEquationTypes(); + std::vector getConstraintTypes(); + template void initialize(ConstraintVector& obj); - + +protected: int equationCount(); template< typename creator_type> @@ -91,7 +96,7 @@ class Constraint : public Object { }; void collectPseudoPoints(Vec& vec1, Vec& vec2); - + //Equation is the constraint with types, the EquationSet hold all needed Maps for calculation template struct EquationSet { @@ -114,6 +119,12 @@ class Constraint : public Object { virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; virtual placeholder* clone() = 0; + + //some runtime type infos are needed, as we cant access the contents with arbitrary functors + virtual std::vector getGenericEquations() = 0; + virtual std::vector getGenericConstraints() = 0; + virtual std::vector getEquationTypes() = 0; + virtual std::vector getConstraintTypes() = 0; }; public: @@ -187,18 +198,49 @@ class Constraint : public Object { void operator()(T& val) const; }; - holder(Objects& obj); + struct GenericEquations { + std::vector& vec; + GenericEquations(std::vector& v); + + template + void operator()(T& val) const; + }; + + struct GenericConstraints { + std::vector& vec; + GenericConstraints(std::vector& v); + + template + void operator()(T& val) const; + }; + struct Types { + std::vector& vec; + Types(std::vector& v); + + template + void operator()(T& val) const; + }; + + + holder(Objects& obj); + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale); virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); virtual placeholder* clone(); - virtual int equationCount() { + virtual int equationCount() { return mpl::size::value; }; + + virtual std::vector getGenericEquations(); + virtual std::vector getGenericConstraints(); + virtual std::vector getEquationTypes(); + virtual std::vector getConstraintTypes(); EquationSets m_sets; + Objects m_objects; }; protected: @@ -217,14 +259,15 @@ class Constraint : public Object { template void operator()(const T1&, const T2&); - + placeholder* p; bool need_swap; }; placeholder* content; - geom_ptr first, second; Connection cf, cs; +public: + geom_ptr first, second; }; @@ -252,7 +295,7 @@ Constraint::~Constraint() { template boost::shared_ptr Constraint::clone(Sys& newSys) { - + //copy the standart stuff boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); np->m_system = &newSys; @@ -313,6 +356,26 @@ void Constraint::collectPseudoPoints(Vec& content->collectPseudoPoints(first, second, vec1, vec2); }; +template +std::vector Constraint::getGenericEquations() { + return content->getGenericEquations(); +}; + +template +std::vector Constraint::getGenericConstraints() { + return content->getGenericConstraints(); +}; + +template +std::vector Constraint::getEquationTypes() { + return content->getEquationTypes(); +}; + +template +std::vector Constraint::getConstraintTypes() { + return content->getConstraintTypes(); +}; + template template Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; @@ -440,9 +503,52 @@ void Constraint::holder +template +Constraint::holder::GenericEquations::GenericEquations(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::GenericEquations::operator()(T& val) const { + vec.push_back(val.m_eq); +}; + +template +template +Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::GenericConstraints::operator()(T& val) const { + vec.push_back(val); +}; + +template +template +Constraint::holder::Types::Types(std::vector& v) + : vec(v) { + +}; + template template -Constraint::holder::holder(Objects& obj) { +template< typename T > +void Constraint::holder::Types::operator()(T& val) const { + vec.push_back(&typeid(T)); +}; + +template +template +Constraint::holder::holder(Objects& obj) : m_objects(obj) { //set the initial values in the equations fusion::for_each(m_sets, OptionSetter(obj)); }; @@ -455,7 +561,7 @@ void Constraint::holder template -typename Constraint::placeholder* +typename Constraint::placeholder* Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); //if(creator.need_swap) first.swap(second); @@ -476,22 +582,58 @@ void Constraint::holder template -typename Constraint::placeholder* +typename Constraint::placeholder* Constraint::holder::clone() { return new holder(*this); }; +template +template +std::vector +Constraint::holder::getGenericEquations() { + std::vector vec; + fusion::for_each( m_sets, GenericEquations(vec) ); + return vec; +}; + +template +template +std::vector +Constraint::holder::getGenericConstraints() { + std::vector vec; + fusion::for_each( m_objects, GenericConstraints(vec) ); + return vec; +}; + +template +template +std::vector +Constraint::holder::getEquationTypes() { + std::vector vec; + mpl::for_each< EquationVector >( Types(vec) ); + return vec; +}; + +template +template +std::vector +Constraint::holder::getConstraintTypes() { + std::vector vec; + mpl::for_each< ConstraintVector >( Types(vec) ); + return vec; +}; + template template< typename ConstraintVector > Constraint::creator::creator(Objects& obj) : objects(obj) { - + }; template template< typename ConstraintVector > template void Constraint::creator::operator()(const T1&, const T2&) { - + typedef tag_order< typename geometry_traits::tag, typename geometry_traits::tag > order; //transform the constraints into eqautions with the now known types diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index cca0852335e6..131a2d24e432 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -167,6 +167,8 @@ class Geometry : public Object Dimension; + Geometry(Sys& system); + template Geometry(const T& geometry, Sys& system); @@ -277,6 +279,17 @@ class Geometry : public Object +Geometry::Geometry(Sys& system) + : m_isInCluster(false), m_parameter(NULL,0,DS(0,0)), + m_clusterFixed(false), m_init(false) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif + + this->m_system = &system; +}; template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> template diff --git a/src/Mod/Assembly/App/opendcm/module3d.hpp b/src/Mod/Assembly/App/opendcm/module3d.hpp index db10e08cd4fb..a0c4392fcb99 100644 --- a/src/Mod/Assembly/App/opendcm/module3d.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d.hpp @@ -34,5 +34,9 @@ #include "module3d/coincident.hpp" #include "module3d/module.hpp" +#ifdef DCM_USE_MODULESTATE +#include "module3d/state.hpp" +#endif + #endif //DCM_MODULE3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp index 88fe8ab3ef3e..273efc7aaa21 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -273,7 +273,7 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { typedef typename Kernel::Vector3 Vector3; typedef std::vector > Vec; - Scalar value, sc_value, cdn; + Scalar value, sc_value, cdn, nxn_n; Vector3 c, n1, n2, nxn; #ifdef USE_LOGGING @@ -314,6 +314,7 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { n1 = line1.template segment<3>(3); n2 = line2.template segment<3>(3); nxn = n1.cross(n2); + nxn_n = nxn.norm(); c = line2.template head<3>() - line1.template head<3>(); cdn = c.dot(nxn); const Scalar res = std::abs(cdn) / nxn.norm(); @@ -325,17 +326,17 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { }; Scalar calculateGradientFirst(Vector& line1, Vector& line2, Vector& dline1) { - if(nxn.norm() == 0) + if(nxn_n == 0) return 1.; const Vector3 nxn_diff = dline1.template segment<3>(3).cross(n2); - Scalar diff = (-dline1.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn.norm(); - diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn.norm(); + Scalar diff = (-dline1.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn_n; + diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn_n; //absoulute value requires diffrent differentation for diffrent results if(cdn <= 0) diff *= -1; - diff /= std::pow(nxn.norm(),2); + diff /= std::pow(nxn_n,2); #ifdef USE_LOGGING if(!boost::math::isfinite(diff)) @@ -347,17 +348,17 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { }; Scalar calculateGradientSecond(Vector& line1, Vector& line2, Vector& dline2) { - if(nxn.norm() == 0) + if(nxn_n == 0) return 1.; const Vector3 nxn_diff = n1.cross(dline2.template segment<3>(3)); - Scalar diff = (dline2.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn.norm(); - diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn.norm(); + Scalar diff = (dline2.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn_n; + diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn_n; //absoulute value requires diffrent differentation for diffrent results if(cdn <= 0) diff *= -1; - diff /= std::pow(nxn.norm(),2); + diff /= std::pow(nxn_n,2); #ifdef USE_LOGGING if(!boost::math::isfinite(diff)) @@ -369,32 +370,32 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { }; void calculateGradientFirstComplete(Vector& line1, Vector& line2, Vector& gradient) { - if(nxn.norm() == 0) { + if(nxn_n == 0) { gradient.head(3).setOnes(); return; } if(cdn >= 0) { - gradient.template head<3>() = -nxn/nxn.norm(); - gradient.template segment<3>(3) = (c.cross(-n2)*nxn.norm()-c.dot(nxn)*n2.cross(nxn)/nxn.norm())/std::pow(nxn.norm(),2); + gradient.template head<3>() = -nxn/nxn_n; + gradient.template segment<3>(3) = (c.cross(-n2)*nxn_n-c.dot(nxn)*n2.cross(nxn)/nxn_n)/std::pow(nxn_n,2); } else { - gradient.template head<3>() = nxn/nxn.norm(); - gradient.template segment<3>(3) = (-c.cross(-n2)*nxn.norm()+c.dot(nxn)*n2.cross(nxn)/nxn.norm())/std::pow(nxn.norm(),2); + gradient.template head<3>() = nxn/nxn_n; + gradient.template segment<3>(3) = (-c.cross(-n2)*nxn_n+c.dot(nxn)*n2.cross(nxn)/nxn_n)/std::pow(nxn_n,2); } }; void calculateGradientSecondComplete(Vector& line1, Vector& line2, Vector& gradient) { - if(nxn.norm() == 0) { + if(nxn_n == 0) { gradient.head(3).setOnes(); return; } if(cdn >= 0) { - gradient.template head<3>() = nxn/nxn.norm(); - gradient.template segment<3>(3) = (c.cross(n1)*nxn.norm()-c.dot(nxn)*((-n1).cross(nxn))/nxn.norm())/std::pow(nxn.norm(),2); + gradient.template head<3>() = nxn/nxn_n; + gradient.template segment<3>(3) = (c.cross(n1)*nxn_n-c.dot(nxn)*((-n1).cross(nxn))/nxn_n)/std::pow(nxn_n,2); } else { - gradient.template head<3>() = -nxn/nxn.norm(); - gradient.template segment<3>(3) = (-c.cross(n1)*nxn.norm()+c.dot(nxn)*((-n1).cross(nxn))/nxn.norm())/std::pow(nxn.norm(),2); + gradient.template head<3>() = -nxn/nxn_n; + gradient.template segment<3>(3) = (-c.cross(n1)*nxn_n+c.dot(nxn)*((-n1).cross(nxn))/nxn_n)/std::pow(nxn_n,2); } }; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index ea6a9c9a1030..b21c84ff80b2 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -85,6 +85,7 @@ struct Module3D { typedef mpl::map1< mpl::pair > > ConsSignal; typedef ID Identifier; + typedef Typelist geometry_types; typedef details::MES MES; typedef details::SystemSolver SystemSolver; @@ -98,6 +99,8 @@ struct Module3D { attrs::mutable_constant< std::string > log_id; #endif public: + Geometry3D_id(Sys& system); + template Geometry3D_id(const T& geometry, Sys& system); @@ -116,6 +119,8 @@ struct Module3D { typedef vertex_prop vertex_propertie; + Geometry3D(Sys& system); + template Geometry3D(const T& geometry, Sys& system); @@ -288,7 +293,20 @@ typename boost::add_reference::type get(G geom) { /*****************************************************************************************************************/ /*****************************************************************************************************************/ +template +template +template +Module3D::type::Geometry3D_id::Geometry3D_id(Sys& system) + : detail::Geometry(system) +#ifdef USE_LOGGING + , log_id("No ID") +#endif +{ +#ifdef USE_LOGGING + Base::log.add_attribute("ID", log_id); +#endif +}; template template @@ -344,6 +362,15 @@ void Module3D::type::Geometry3D_id::setIdentifier(Id #endif }; +template +template +Module3D::type::Geometry3D::Geometry3D(Sys& system) + : mpl::if_, + detail::Geometry, + Geometry3D_id >::type(system) { + +}; + template template template diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index 9502154b3c1e..ac9910c4557a 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -158,8 +158,8 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() //get the biggest scale factor details::ClusterMath& math = (*cit.first).second->template getClusterProperty(); - //math.m_pseudo.clear(); - //collectPseudoPoints(cluster, (*cit.first).first, math.m_pseudo); + math.m_pseudo.clear(); + collectPseudoPoints(cluster, (*cit.first).first, math.m_pseudo); const Scalar s = math.calculateClusterScale(); sc = (s>sc) ? s : sc; @@ -272,9 +272,15 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy constraints += (*it.first)->equationCount(); }; + if(params <= 0 || constraints <= 0) { + //TODO:throw +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Error in system counting: params = " << params << " and constraints = "< +#include + +#include #include #include +#include +#include +#include + +#include namespace karma = boost::spirit::karma; -namespace ascii = boost::spirit::karma::ascii; +namespace qi = boost::spirit::qi; +namespace karma_ascii = boost::spirit::karma::ascii; +namespace qi_ascii = boost::spirit::qi::ascii; namespace phx = boost::phoenix; namespace dcm { namespace details { - -struct geom_visitor : public boost::static_visitor { + +template +struct getModule3D { + typedef typename system_traits::template getModule::type type; +}; + +struct geom_visitor : public boost::static_visitor { + template - int operator()(T& i) const { - return geometry_traits::tag::weight::value; + std::string operator()(T& i) const { + + //we use stings in case new geometry gets added and the weights shift, meaning: backwards + //compatible + std::string type; + switch( geometry_traits::tag::weight::value ) { + case tag::weight::direction::value : + return "direction"; + case tag::weight::point::value : + return "point"; + case tag::weight::line::value : + return "line"; + case tag::weight::plane::value : + return "plane"; + case tag::weight::cylinder::value : + return "cylinder"; + default: + return "unknown"; + }; }; }; template -int getWeight(boost::shared_ptr ptr) { - return boost::apply_visitor(geom_visitor(), ptr->m_geometry); +std::string getWeight(boost::shared_ptr ptr) { + geom_visitor v; + return ptr->apply(v); }; -template -void getStdVector(typename Kernel::Vector& eigen, std::vector& vec) { - vec.resize(eigen.size()); - for(int i=0; i +struct get_weight { + typedef typename geometry_traits::tag::weight type; }; -} +//search the first type in the typevector with the given weight +template +struct getWeightType { + typedef typename mpl::find_if, Weight > >::type iter; + typedef typename mpl::deref::type type; +}; + +typedef std::vector< fusion::vector2 > string_vec; +typedef std::vector< fusion::vector2, std::vector > > char_vec; + +template +string_vec getConstraints(boost::shared_ptr con) { + + string_vec vec; + std::vector cvec = con->getGenericConstraints(); + + typename std::vector::iterator it; + for(it = cvec.begin(); it != cvec.end(); it++) { + + if((*it).type() == typeid(dcm::Distance)) { + std::string value = boost::lexical_cast(boost::any_cast(*it).value); + vec.push_back(fusion::make_vector(std::string("Distance"), value)); + } + else if((*it).type() == typeid(dcm::Angle)) { + std::string value = boost::lexical_cast(boost::any_cast(*it).value); + vec.push_back(fusion::make_vector(std::string("Angle"), value)); + } + else if((*it).type() == typeid(dcm::Orientation)) { + std::string value = boost::lexical_cast(boost::any_cast(*it).value); + vec.push_back(fusion::make_vector(std::string("Orientation"), value)); + }; + }; + return vec; +}; + +template +struct push_seq { + typedef typename fusion::result_of::as_vector::type>::type type; +}; + +template +typename push_seq::type append(State& s, const typename Add::option_type& val) { + + typedef typename push_seq::type Sequence; + typedef typename fusion::result_of::begin::type Begin; + typedef typename fusion::result_of::end::type End; + typedef typename fusion::result_of::prior::type EndOld; + + //create the new sequence + Sequence vec; + + //copy the old values into the new sequence + Begin b(vec); + EndOld eo(vec); + + fusion::iterator_range range(b, eo); + fusion::copy(s, range); + + //insert this object at the end of the sequence + fusion::back(vec) = val; + + //and return our new extendet sequence + return vec; +}; + +template +typename boost::enable_if >::type, void>::type +recursiveCreation(typename char_vec::iterator it, + typename char_vec::iterator end, + boost::shared_ptr con, + State s ) {}; + +template +typename boost::enable_if >::type, void>::type +recursiveCreation(typename char_vec::iterator it, + typename char_vec::iterator end, + boost::shared_ptr con, + State s ) { + + if(it == end) { + con->template initialize(s); + return; + }; + + std::string first( fusion::at_c<0>(*it).begin(), fusion::at_c<0>(*it).end() ); + std::string second( fusion::at_c<1>(*it).begin(), fusion::at_c<1>(*it).end() ); + + if( first.compare("Distance") == 0 ) { + typedef typename push_seq::type Vec; + Vec vec = append(s, boost::lexical_cast(second)); + recursiveCreation::type >(++it, end, con, vec); + return; + }; +}; + +template +void setConstraints(char_vec& vec, boost::shared_ptr con ) { + recursiveCreation, C, mpl::int_<0> >(vec.begin(), vec.end(), con, fusion::vector<>()); +}; + +template +bool VectorOutput(Geom &v, Row& r, Value& val) { + + if (r < v->m_global.rows()) { + + val = v->m_global(r++); + return true; // output continues + } + return false; // fail the output +}; + +template +bool VectorInput(Geom &v, Row& r, Value& val) { + + v.conservativeResize(r+1); + v(r++) = val; + return true; // output continues +}; + +template +struct inject_set { + + template + static void apply(Vec& v, Obj g) { + Geom gt; + (typename geometry_traits::modell()).template inject::accessor >(gt, v); + g->set(gt); + }; +}; +//spezialisation if no type in the typelist has the right weight +template<> +struct inject_set { + + template + static void apply(Vec& v, Obj g) { + //TODO:throw + }; +}; + +template +bool Create(System* sys, std::string& type, + boost::shared_ptr::type::Geometry3D> geom, + typename System::Kernel::Vector& v) { + + typedef typename details::getModule3D::type::geometry_types Typelist; + + if(type.compare("direction") == 0 ) { + inject_set::type>::apply(v, geom); + } + else if(type.compare("point") == 0) { + inject_set::type>::apply(v, geom); + } + else if(type.compare("line") == 0) { + inject_set::type>::apply(v, geom); + } + else if(type.compare("plane") == 0 ) { + inject_set::type>::apply(v, geom); + } + else if(type.compare("cylinder") == 0 ) { + inject_set::type>::apply(v, geom); + }; + return true; +}; + +// define a new real number formatting policy +template +struct scientific_policy : karma::real_policies +{ + // we want the numbers always to be in scientific format + static int floatfield(Num n) { return std::ios::scientific; } + static unsigned precision(Num n) {return 16;}; +}; + +// define a new generator type based on the new policy +typedef karma::real_generator > science_type; +static science_type const scientific = science_type(); +} //details +} //dcm +BOOST_PHOENIX_ADAPT_FUNCTION( bool, vector_out, dcm::details::VectorOutput, 3) +BOOST_PHOENIX_ADAPT_FUNCTION( bool, vector_in, dcm::details::VectorInput, 3) +BOOST_PHOENIX_ADAPT_FUNCTION( bool, create, dcm::details::Create, 4) + +BOOST_FUSION_ADAPT_STRUCT( + dcm::GlobalEdge, + (int, ID) + (int, source) + (int, target) +) + +namespace dcm { + +template +struct parser_generate< typename details::getModule3D::type::Geometry3D , System> + : public mpl::true_{}; + +template +struct parser_generator< typename details::getModule3D::type::Geometry3D , System, iterator > { + + typedef typename details::getModule3D::type::Geometry3D Geometry; + typedef karma::rule(), karma::locals > generator; + static void init(generator& r) { + r = karma::lit("Geometry3D\n") + << karma_ascii::string[karma::_1 = phx::bind(&details::getWeight, karma::_val)] + << "" << karma::eol << "" + << (details::scientific[ boost::spirit::_pass = vector_out(karma::_val, karma::_a, karma::_1) ] % ' ') + << ""; + }; +}; + + template -struct parser_generate< typename Module3D::type::Geometry3D, System> +struct parser_generate< typename details::getModule3D::type::vertex_prop , System> : public mpl::true_{}; template -struct parser_generator< typename Module3D::type::Geometry3D, System, iterator > { +struct parser_generator< typename details::getModule3D::type::vertex_prop , System, iterator > { - typedef typename Sys::Kernel Kernel; - typedef typename typename Module3D::type::Geometry3D Geometry; - typedef karma::rule() > generator; + typedef karma::rule generator; static void init(generator& r) { - r = karma::lit("Geometry3D\n") - << ascii::string[karma::_1 = phx::bind(&details::getWeight, karma::_val)] - << "\n" - << (karma::double_ % " ")[phx::bind(&details::getStdVector, )] + r = karma::lit("Vertex") + << karma::eol << "" << karma::int_ << ""; }; }; template -struct parser_parse< typename Module3D::type::Geometry3D, System> +struct parser_generate< typename details::getModule3D::type::Constraint3D , System> : public mpl::true_{}; template -struct parser_parser< typename Module3D::type::Geometry3D, System, iterator > { +struct parser_generator< typename details::getModule3D::type::Constraint3D , System, iterator > { - typedef typename Module3D::type::Geometry3D object_type; + typedef typename details::getModule3D::type::Geometry3D Geometry3D; + typedef typename details::getModule3D::type::Constraint3D Constraint3D; + typedef typename details::getModule3D::type::vertex_prop vertex_prop; + typedef karma::rule()> generator; + static void init(generator& r) { + r = karma::lit("Constraint3D") << karma::eol + << "" + << (*(karma::eol<<""<"))[karma::_1 = phx::bind(&details::getConstraints, karma::_val)]; + }; +}; + +template +struct parser_generate< typename details::getModule3D::type::edge_prop , System> + : public mpl::true_{}; + +template +struct parser_generator< typename details::getModule3D::type::edge_prop , System, iterator > { + + typedef karma::rule generator; + static void init(generator& r) { + r %= karma::lit("Edge") + << karma::eol << "" << karma::int_ << " " + << karma::int_ << " " << karma::int_ << ""; + }; +}; + +template +struct parser_generate::type::fix_prop, System> : public mpl::true_ {}; + +template +struct parser_generator::type::fix_prop, System, iterator> { + typedef karma::rule generator; + + static void init(generator& r) { + r = karma::lit("Fix\n") << karma::bool_ <<""; + }; +}; + +/****************************************************************************************************/ +/****************************************************************************************************/ + +template +struct parser_parse< typename details::getModule3D::type::Geometry3D , System> + : public mpl::true_{}; + +template +struct parser_parser< typename details::getModule3D::type::Geometry3D, System, iterator > { + + typedef typename details::getModule3D::type::Geometry3D object_type; + typedef typename System::Kernel Kernel; + + typedef qi::rule(System*), qi::space_type, qi::locals > parser; + static void init(parser& r) { + r = qi::lit("Geometry3D")[ qi::_val = phx::construct >( phx::new_(*qi::_r1))] + >> "" >> (+qi::char_("a-zA-Z"))[qi::_a = phx::construct(phx::begin(qi::_1), phx::end(qi::_1))] >> "" + >> "" >> *qi::double_[ vector_in(qi::_b, qi::_c, qi::_1) ] >> "" + >> qi::eps[ create(qi::_r1, qi::_a, qi::_val, qi::_b) ]; + }; +}; + +template +struct parser_parse< typename details::getModule3D::type::vertex_prop, System> + : public mpl::true_{}; + +template +struct parser_parser< typename details::getModule3D::type::vertex_prop, System, iterator > { + + typedef qi::rule parser; + static void init(parser& r) { + r %= qi::lit("Vertex") >> "" >> qi::int_ >> ""; + }; +}; + + +template +struct parser_parse< typename details::getModule3D::type::Constraint3D , System> + : public mpl::true_{}; + +template +struct parser_parser< typename details::getModule3D::type::Constraint3D, System, iterator > { + + typedef typename details::getModule3D::type::Geometry3D Geometry3D; + typedef typename details::getModule3D::type::Constraint3D Constraint3D; + typedef typename System::Kernel Kernel; - typedef qi::rule(System*), qi::space_type> parser; + typedef qi::rule(System*), qi::space_type > parser; + static void init(parser& r) { + r = qi::lit("Constraint3D") + >> ("")[ + qi::_val = phx::construct >( + phx::new_(*qi::_r1, + phx::bind(&System::Cluster::template getObject, phx::bind(&System::m_cluster, qi::_r1), qi::_1), + phx::bind(&System::Cluster::template getObject, phx::bind(&System::m_cluster, qi::_r1), qi::_2) ) ) + ] + >> (*("" >> *qi_ascii::alnum >>""))[phx::bind(&details::setConstraints, qi::_1, qi::_val)]; + }; +}; + +template +struct parser_parse< typename details::getModule3D::type::edge_prop, System> + : public mpl::true_{}; + +template +struct parser_parser< typename details::getModule3D::type::edge_prop, System, iterator > { + + typedef qi::rule parser; static void init(parser& r) { - r = qi::lexeme[qi::lit("object 1 prop")[ qi::_val = - phx::construct >( phx::new_(*qi::_r1))]] >> ("HaHAHAHAHA"); + r %= qi::lit("Edge") + >> "" >> qi::int_ >> qi::int_ >> qi::int_ >> ""; }; }; + +template +struct parser_parse< typename details::getModule3D::type::fix_prop, System> + : public mpl::true_{}; + +template +struct parser_parser< typename details::getModule3D::type::fix_prop, System, iterator > { + typedef qi::rule parser; + static void init(parser& r) { + r = qi::lit("Fix") >> "" >> qi::bool_ >> ""; + }; +}; + } diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp index 7182c5c4ca1a..af446fa9118f 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator.hpp @@ -20,6 +20,10 @@ #ifndef DCM_EDGE_GENERATOR_H #define DCM_EDGE_GENERATOR_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include "property_generator.hpp" #include "object_generator.hpp" #include "extractor.hpp" @@ -27,7 +31,6 @@ #include #include #include - #include namespace karma = boost::spirit::karma; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp index 40d6fa78edd7..9c99a32c7569 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_generator_imp.hpp @@ -21,6 +21,7 @@ #define DCM_EDGE_GENERATOR_IMP_H #include "edge_vertex_generator.hpp" +#include "boost/phoenix/fusion/at.hpp" namespace dcm { namespace details { @@ -28,9 +29,9 @@ namespace details { template edge_generator::edge_generator() : edge_generator::base_type(edge_range) { - globaledge = karma::int_[phx::bind(&Extractor::getGlobalEdgeID, ex, karma::_val, karma::_1)] - << " source=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeSource, ex, karma::_val, karma::_1)] - << " target=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeTarget, ex, karma::_val, karma::_1)] << '>' + globaledge = karma::int_[phx::bind(&Extractor::getGlobalEdgeID, &ex, karma::_val, karma::_1)] + << " source=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeSource, &ex, karma::_val, karma::_1)] + << " target=" << karma::int_[phx::bind(&Extractor::getGlobalEdgeTarget, &ex, karma::_val, karma::_1)] << '>' << "+" << objects[karma::_1 = phx::at_c<0>(karma::_val)] << "-\n" ; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp index d4172fb3afca..fe60473f2c31 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser.hpp @@ -20,6 +20,10 @@ #ifndef DCM_EDGE_VERTEX_PARSER_H #define DCM_EDGE_VERTEX_PARSER_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include #include "opendcm/core/clustergraph.hpp" #include "extractor.hpp" diff --git a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp index 8b43333a099d..c295b162f594 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/edge_vertex_parser_imp.hpp @@ -21,6 +21,7 @@ #define DCM_EDGE_PARSER_IMP_H #include "edge_vertex_parser.hpp" +#include "boost/phoenix/fusion/at.hpp" namespace dcm { namespace details { @@ -34,18 +35,18 @@ edge_parser::edge_parser() : edge_parser::base_type(edge) { >> objects(qi::_r1)[phx::at_c<0>(qi::_val) = qi::_1] >> ""; edge = (qi::lit("> "source=" >> qi::int_ >> "target=" >> qi::int_ >> '>')[qi::_val = phx::bind((&Sys::Cluster::addEdgeGlobal), qi::_r1, qi::_1, qi::_2)] - >> edge_prop[phx::bind(&Injector::setEdgeProperties, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] - >> *global_edge(qi::_r2) + >> edge_prop[phx::bind(&Injector::setEdgeProperties, &in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> (*global_edge(qi::_r2))[phx::bind(&Injector::setEdgeBundles, &in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] >> (""); }; template vertex_parser::vertex_parser() : vertex_parser::base_type(vertex) { - vertex = qi::lit("::addVertex, in, qi::_r1, qi::_val)] >> qi::lit("id=") + vertex = qi::lit("::addVertex, &in, qi::_r1, qi::_val)] >> qi::lit("id=") >> qi::int_[phx::at_c<1>(qi::_val) = phx::bind(&Sys::Cluster::setGlobalVertex, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] - >> '>' >> prop[phx::bind(&Injector::setVertexProperties, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] - >> objects(qi::_r2)[phx::bind(&Injector::setVertexObjects, in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> '>' >> prop[phx::bind(&Injector::setVertexProperties, &in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] + >> objects(qi::_r2)[phx::bind(&Injector::setVertexObjects, &in, qi::_r1, phx::at_c<0>(qi::_val), qi::_1)] >> (""); }; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp index 7d2e4ed7c781..ad740c7b7f74 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp @@ -96,12 +96,20 @@ struct Injector { typename details::pts::type& prop) { fusion::at_c<0>(cluster->operator[](e)) = prop; }; + void setEdgeBundles(typename Sys::Cluster* cluster, LocalEdge e, + std::vector& bundles) { + fusion::at_c<1>(cluster->operator[](e)) = bundles; + }; void setVertexProperty(typename Sys::Cluster* cluster, int value) { cluster->template setClusterProperty(value); }; - void addCluster(typename Sys::Cluster* cluster, typename Sys::Cluster* addcl) { - LocalVertex v = cluster->getLocalVertex(addcl->template getClusterProperty()).first; - cluster->m_clusters[v] = boost::shared_ptr(addcl); + void addClusters(std::vector& clusters, typename Sys::Cluster* cluster) { + + typename std::vector::iterator it; + for(it = clusters.begin(); it != clusters.end(); it++) { + LocalVertex v = cluster->getLocalVertex((*it)->template getClusterProperty()).first; + cluster->m_clusters[v] = boost::shared_ptr(*it); + }; }; void addVertex(typename Sys::Cluster* cluster, fusion::vector& vec) { vec = cluster->addVertex(); diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp index ab77c556c951..d55d2c83d7a7 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp @@ -20,6 +20,10 @@ #ifndef DCM_GENERATOR_H #define DCM_GENERATOR_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include "property_generator.hpp" #include "edge_vertex_generator.hpp" #include "extractor.hpp" diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp index f258c065b640..f7bb6bc6bbcf 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp @@ -22,7 +22,6 @@ #include "generator.hpp" #include "opendcm/core/clustergraph.hpp" -//#include "karma_trans.hpp" #include #include @@ -53,10 +52,12 @@ namespace dcm { template generator::generator() : generator::base_type(start) { - cluster %= karma::omit[karma::int_] << cluster_prop << -vertex_range[phx::bind(&Extractor::getVertexRange, ex, karma::_val, karma::_1)] - << -karma::buffer["\n" << edge_range[phx::bind(&Extractor::getEdgeRange, ex, karma::_val, karma::_1)]] - << -karma::buffer["\n" << (cluster_pair % karma::eol)[phx::bind(&Extractor::getClusterRange, ex, karma::_val, karma::_1)]] << "-\n" - << ""; + cluster %= karma::omit[karma::int_] << cluster_prop + << -karma::buffer[karma::eol << (cluster_pair % karma::eol)[phx::bind(&Extractor::getClusterRange, &ex, karma::_val, karma::_1)]] + << -vertex_range[phx::bind(&Extractor::getVertexRange, &ex, karma::_val, karma::_1)] + << -karma::buffer[karma::eol << edge_range[phx::bind(&Extractor::getEdgeRange, &ex, karma::_val, karma::_1)]] + << "-" << karma::eol + << karma::lit(""); cluster_pair %= karma::lit("+" << karma::attr_cast(cluster); diff --git a/src/Mod/Assembly/App/opendcm/moduleState/module.hpp b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp index c3a3a4d13685..c6760c371c44 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/module.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp @@ -27,9 +27,6 @@ #include "parser.hpp" #include "defines.hpp" -#include -#include - namespace qi = boost::spirit::qi; namespace dcm { diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp index 85a50bb99ad6..9c42fd515733 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp @@ -1,6 +1,10 @@ #ifndef DCM_OBJECT_GENERATOR_H #define DCM_OBJECT_GENERATOR_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include "property_generator.hpp" namespace fusion = boost::fusion; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp index 1114f19e88b8..df6491e46492 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp @@ -6,6 +6,8 @@ #include "object_generator.hpp" #include "property_generator_imp.hpp" +#include "boost/phoenix/fusion/at.hpp" + using namespace boost::spirit::karma; namespace karma = boost::spirit::karma; namespace phx = boost::phoenix; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp index ab4525865b09..a2d669c3473a 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp @@ -20,24 +20,20 @@ #ifndef DCM_OBJECT_PARSER_H #define DCM_OBJECT_PARSER_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include "property_parser.hpp" namespace dcm { namespace details { -template -struct empty_obj_parser : public qi::grammar(Sys*), qi::space_type> { - qi::rule(Sys*), qi::space_type> start; - empty_obj_parser(): empty_obj_parser::base_type(start) { - //start = qi::eps(false); -}; -}; - //grammar for a single object -template -struct obj_parser : public qi::grammar(Sys*), qi::space_type> { +template +struct obj_parser : public qi::grammar::type*, Sys*), qi::space_type> { typename Par::parser subrule; - qi::rule(Sys*), qi::space_type> start; + qi::rule::type*, Sys*), qi::space_type> start; prop_par prop; obj_parser(); @@ -52,8 +48,8 @@ template struct obj_parser_fold : mpl::fold< seq, state, mpl::if_< parser_parse, mpl::push_back > >, - mpl::push_back > > > {}; + obj_parser > >, + mpl::_1 > > {}; //currently max. 10 objects are supported template @@ -61,28 +57,19 @@ struct obj_par : public qi::grammar::type(Sys*), qi::space_type> { - typedef typename Sys::objects ObjectList; - - //create a vector with the appropriate rules for all objects. Do this with the rule init struct, as it gives - //automatic initialisation of the rules when the objects are created - typedef typename obj_parser_fold >::type init_rules_vector; - //push back a empty rule so that we know where to go when nothing is to do - typedef typename mpl::push_back::type, Sys> >::type rules_vector; - - //create the fusion sequence of our rules - typedef typename fusion::result_of::as_vector::type rules_sequnce; + typedef typename Sys::objects ObjectList; - //this struct returns the right accessvalue for the sequences. If we access a value bigger than the property vector size - //we use the last rule, as we made sure this is an empty one - template - struct index : public mpl::if_< mpl::less, mpl::size >, - mpl::int_, typename mpl::size::prior >::type {}; - //this struct tells us if we should execute the generator - template - struct valid : public mpl::less< mpl::int_, mpl::size > {}; + //create a vector with the appropriate rules for all needed objects. + typedef typename obj_parser_fold >::type sub_rules_sequence; + //the type of the objectlist rule + typedef qi::rule::type*, Sys*), qi::space_type> parent_rule; + //we need to store all recursive created rules + typedef typename mpl::fold< sub_rules_sequence, mpl::vector0<>, + mpl::push_back >::type parent_rules_sequence; - rules_sequnce rules; + typename fusion::result_of::as_vector::type sub_rules; + typename fusion::result_of::as_vector::type parent_rules; + qi::rule::type(Sys*), qi::space_type> obj; obj_par(); diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp index 4ee6027612d7..268979c5fd74 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp @@ -22,38 +22,53 @@ #include "object_parser.hpp" #include "property_parser_imp.hpp" +#include "boost/phoenix/fusion/at.hpp" namespace dcm { namespace details { + +template +typename boost::enable_if >, void >::type recursive_obj_init( srs& sseq, prs& pseq ) { + + if(dist::value == 0) { + fusion::at(pseq) %= fusion::at(sseq)(qi::_r1, qi::_r2); + } + else { + fusion::at(pseq) %= fusion::at >::type >::type>(pseq)(qi::_r1, qi::_r2) | fusion::at(sseq)(qi::_r1, qi::_r2); + } + + recursive_obj_init::type>(sseq, pseq); +}; + +template +typename boost::disable_if >, void >::type recursive_obj_init( srs& sseq, prs& pseq ){}; -template -obj_parser::obj_parser(): obj_parser::base_type(start) { + +template +obj_parser::obj_parser(): obj_parser::base_type(start) { + + typedef typename mpl::find::type::pos pos; + Par::init(subrule); - start = qi::lit("") >> subrule(qi::_r1)[qi::_val = qi::_1] - >> qi::eps(qi::_val)[ phx::bind(&Sys::template push_back, qi::_r1, qi::_val)] - >> prop[phx::bind(&obj_parser::setProperties, qi::_val, qi::_1)] + start = qi::lit("") >> subrule(qi::_r2)[phx::at_c(*qi::_r1) = qi::_1] + >> qi::eps(phx::at_c(*qi::_r1))[ phx::bind(&Sys::template push_back, qi::_r2, phx::at_c(*qi::_r1))] + >> prop[phx::bind(&obj_parser::setProperties, phx::at_c(*qi::_r1), qi::_1)] >> qi::lit(""); }; -template -void obj_parser::setProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { +template +void obj_parser::setProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { if(ptr) ptr->m_properties = seq; }; template obj_par::obj_par(): obj_par::base_type(obj) { - - obj = -(qi::eps(valid<0>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<1>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<2>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<3>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<4>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<5>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<6>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<7>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<8>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]) - >> -(qi::eps(valid<9>::value) >> fusion::at >(rules)(qi::_r1)[phx::at_c::value>(qi::_val) = qi::_1]); - + + recursive_obj_init::type, + typename fusion::result_of::as_vector::type, + mpl::int_<0> >(sub_rules, parent_rules); + + obj = *(fusion::back(parent_rules)(&qi::_val, qi::_r1)); }; }//details diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp index 1ff58c444e55..291e8c5828ca 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser.hpp @@ -20,6 +20,10 @@ #ifndef DCM_PARSER_H #define DCM_PARSER_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include #include @@ -55,13 +59,13 @@ static void print(std::string s) { }; template -struct parser : qi::grammar, qi::space_type> { +struct parser : qi::grammar >, qi::space_type> { typedef typename Sys::Cluster graph; parser(); - qi::rule, qi::space_type> cluster; + qi::rule >, qi::space_type> cluster; details::cluster_prop_par cluster_prop; details::obj_par objects; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp index 6b9f42b81298..605c506643ff 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp @@ -59,11 +59,14 @@ parser::parser() : parser::base_type(cluster) { cluster %= qi::lit("" >> -(qi::eps( qi::_a > 0 )[qi::_val = phx::new_()]) - >> qi::eps[phx::bind(&Injector::setVertexProperty, in, qi::_val, qi::_a)] + >> qi::eps[phx::bind(&Sys::Cluster::setCopyMode, qi::_val, true)] + >> qi::eps[phx::bind(&Injector::setVertexProperty, &in, qi::_val, qi::_a)] >> qi::attr_cast(cluster_prop >> qi::eps) + >> qi::omit[(*cluster(qi::_r1))[qi::_b = qi::_1]] >> qi::omit[*vertex(qi::_val, qi::_r1)] >> qi::omit[*edge(qi::_val, qi::_r1)] - >> qi::omit[*(cluster(qi::_r1)[phx::bind(&Injector::addCluster, in, qi::_val, qi::_1)])] + >> qi::eps[phx::bind(&Injector::addClusters, &in, qi::_b, qi::_val)] + >> qi::eps[phx::bind(&Sys::Cluster::setCopyMode, qi::_val, false)] >> "";// >> str[&sp::print]; }; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp index 5637679a6d15..005aefc3f49a 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_generator.hpp @@ -1,6 +1,10 @@ #ifndef DCM_PROPERTY_GENERATOR_H #define DCM_PROPERTY_GENERATOR_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include #include @@ -21,7 +25,7 @@ typedef std::ostream_iterator Iterator; namespace details { -//a grammar that does nothing exept failing +//a grammar that does nothing returns true struct empty_grammar : public karma::grammar { karma::rule start; empty_grammar(): empty_grammar::base_type(start) { diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp index 6e404bfa87e1..be8956505222 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp @@ -20,6 +20,10 @@ #ifndef DCM_PROPERTY_PARSER_H #define DCM_PROPERTY_PARSER_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include #include #include @@ -40,28 +44,11 @@ typedef boost::spirit::istream_iterator IIterator; namespace details { -struct empty_parser : public qi::grammar { - qi::rule start; - empty_parser(): empty_parser::base_type(start) { - start = qi::eps(true); - }; - empty_parser(const empty_parser& other) : empty_parser::base_type(start) {}; -}; - -template -struct skip_parser : public qi::grammar { - qi::rule start; - skip_parser() : skip_parser::base_type(start) { - start = qi::eps(true); - }; - skip_parser(const skip_parser& other) : skip_parser::base_type(start) {}; -}; - -template -struct prop_parser : qi::grammar { +template +struct prop_parser : qi::grammar::type*), qi::space_type> { typename Par::parser subrule; - qi::rule start; + qi::rule::type*), qi::space_type> start; prop_parser(); prop_parser(const prop_parser& other) : prop_parser::base_type(start) {}; }; @@ -69,26 +56,24 @@ struct prop_parser : qi::grammar struct prop_parser_fold : mpl::fold< seq, state, mpl::if_< dcm::parser_parse, - mpl::push_back > >, - mpl::push_back > > > {}; + mpl::push_back > >, + mpl::_1 > > {}; //grammar for a fusion sequence of properties. currently max. 10 properties are supported template struct prop_par : qi::grammar::type(), qi::space_type> { - //create a vector with the appropriate rules for all properties. - typedef typename prop_parser_fold >::type init_rules_sequence; - //allow max 10 types as the following code expect this - BOOST_MPL_ASSERT((mpl::less_equal< mpl::size, mpl::int_<10> >)); - //we want to process 10 elements, so create a vector with (10-prop.size()) empty rules - //and append it to our rules vector - typedef mpl::range_c, mpl::size >::value > range; - typedef typename mpl::fold< range, - init_rules_sequence, - mpl::push_back >::type rules_sequence; - - typename fusion::result_of::as_vector::type rules; + //create a vector with the appropriate rules for all needed properties. + typedef typename prop_parser_fold >::type sub_rules_sequence; + //the type of the propertylist rule + typedef qi::rule::type*), qi::space_type> parent_rule; + //we need to store all recursive created rules + typedef typename mpl::fold< sub_rules_sequence, mpl::vector0<>, + mpl::push_back >::type parent_rules_sequence; + + typename fusion::result_of::as_vector::type sub_rules; + typename fusion::result_of::as_vector::type parent_rules; + qi::rule::type(), qi::space_type> prop; prop_par(); diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp index 4fa920c8d64c..d1ecc14f6cf4 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser_imp.hpp @@ -21,6 +21,8 @@ #define DCM_PROPERTY_PARSER_IMP_H #include "property_parser.hpp" +#include +#include namespace dcm { @@ -28,21 +30,40 @@ namespace dcm { typedef boost::spirit::istream_iterator IIterator; namespace details { + +template +typename boost::enable_if >, void >::type recursive_init( srs& sseq, prs& pseq ) { + + if(dist::value == 0) { + fusion::at(pseq) %= fusion::at(sseq)(qi::_r1); + } + else { + fusion::at(pseq) %= fusion::at >::type >::type>(pseq)(qi::_r1) | fusion::at(sseq)(qi::_r1); + } + + recursive_init::type>(sseq, pseq); +}; + +template +typename boost::disable_if >, void >::type recursive_init( srs& sseq, prs& pseq ){}; -template -prop_parser::prop_parser() : prop_parser::base_type(start) { +template +prop_parser::prop_parser() : prop_parser::base_type(start) { + + typedef typename mpl::find::type::pos pos; + Par::init(subrule); - start %= qi::lit("") >> subrule >> qi::lit(""); + start = qi::lit("") >> subrule[phx::at_c(*qi::_r1) = qi::_1] >> qi::lit(""); }; - template prop_par::prop_par() : prop_par::base_type(prop) { - prop %= fusion::at_c<0>(rules) >> fusion::at_c<1>(rules) >> fusion::at_c<2>(rules) - >> fusion::at_c<3>(rules) >> fusion::at_c<4>(rules) >> fusion::at_c<5>(rules) - >> fusion::at_c<6>(rules) >> fusion::at_c<7>(rules) >> fusion::at_c<8>(rules) - >> fusion::at_c<9>(rules); + recursive_init::type, + typename fusion::result_of::as_vector::type, + mpl::int_<0> >(sub_rules, parent_rules); + + prop = *(fusion::back(parent_rules)(&qi::_val)); }; template diff --git a/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp b/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp index 94c4a9b4afd8..c14efd4a6a85 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/traits.hpp @@ -20,6 +20,10 @@ #ifndef DCM_PARSER_TRAITS_H #define DCM_PARSER_TRAITS_H +#ifndef BOOST_SPIRIT_USE_PHOENIX_V3 +#define BOOST_SPIRIT_USE_PHOENIX_V3 +#endif + #include #include diff --git a/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp b/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp index bb49a7eb9439..03c8ff8e7f0e 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/traits_impl.hpp @@ -113,7 +113,7 @@ struct parser_parser { typedef qi::rule parser; static void init(parser& r) { - r = qi::lit("clusterchanged") >> ("") >> qi::bool_ >>""; + r = qi::lit("clusterchanged") >> ("") >> qi::bool_ >>"" ; }; }; diff --git a/src/Mod/Assembly/App/opendcm/modulestate.hpp b/src/Mod/Assembly/App/opendcm/modulestate.hpp index ace674acac62..295eb29686c9 100644 --- a/src/Mod/Assembly/App/opendcm/modulestate.hpp +++ b/src/Mod/Assembly/App/opendcm/modulestate.hpp @@ -27,6 +27,9 @@ #pragma warning( disable : 4503 ) #endif +//use phoenix v3 to allow normal boost phoenix use outside of spirit and not the spirit phoenix v2 version +#define BOOST_SPIRIT_USE_PHOENIX_V3 + #include "moduleState/module.hpp" #include "moduleState/traits.hpp" From 661e3bba8d68f174cd05c933a9d37c10c9255aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sat, 8 Jun 2013 19:19:03 +0200 Subject: [PATCH 133/664] update and bug corection --- src/Mod/Assembly/App/ItemAssembly.cpp | 5 ++ src/Mod/Assembly/App/Solver.h | 4 + .../Assembly/App/opendcm/core/geometry.hpp | 4 +- .../App/opendcm/module3d/clustermath.hpp | 6 +- .../App/opendcm/module3d/coincident.hpp | 73 ++++++++++++++++++- .../Assembly/App/opendcm/module3d/solver.hpp | 2 +- 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index dd576924c870..ec82238906dc 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -58,6 +58,7 @@ App::DocumentObjectExecReturn *ItemAssembly::execute(void) { Base::Console().Message("Execute ItemAssembly\n"); + try{ //create a solver and init all child assemblys with subsolvers m_solver = boost::shared_ptr(new Solver); init(boost::shared_ptr()); @@ -74,6 +75,10 @@ App::DocumentObjectExecReturn *ItemAssembly::execute(void) //solve the system m_solver->solve(); + } + catch(std::exception& e) { + Base::Console().Message("Solver exeption: %s", e.what()); + } this->touch(); return App::DocumentObject::StdReturn; diff --git a/src/Mod/Assembly/App/Solver.h b/src/Mod/Assembly/App/Solver.h index 5ddc4c51ee98..8867f5eee3c9 100644 --- a/src/Mod/Assembly/App/Solver.h +++ b/src/Mod/Assembly/App/Solver.h @@ -99,6 +99,7 @@ struct gp_lin_accessor { break; case 2: p.SetZ(value); + break; case 3: d.SetX(value); break; @@ -148,6 +149,7 @@ struct gp_pln_accessor { break; case 2: p.SetZ(value); + break; case 3: d.SetX(value); break; @@ -198,6 +200,7 @@ struct gp_cylinder_accessor { break; case 2: p.SetZ(value); + break; case 3: d.SetX(value); break; @@ -209,6 +212,7 @@ struct gp_cylinder_accessor { break; case 6: t.SetRadius(value); + break; }; t.SetAxis(gp_Ax1(p,d)); }; diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index 131a2d24e432..38f30fcd0be4 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -439,7 +439,7 @@ void Geometry::finishCalculation() { //recalculate(1.); //remove scaling to get right global value m_global = m_rotated; #ifdef USE_LOGGING - BOOST_LOG(log) << "Finish cluster calculation"; + BOOST_LOG(log) << "Finish cluster calculation: "<::finishCalculation() { m_global = m_parameter; normalize(); #ifdef USE_LOGGING - BOOST_LOG(log) << "Finish calculation"; + BOOST_LOG(log) << "Finish calculation: "<::transformToMaps(typename ClusterMath::Kernel::Transf template void ClusterMath::finishCalculation() { - mapsToTransform(m_transform); - init=false; - #ifdef USE_LOGGING BOOST_LOG(log) << "Finish calculation"; #endif + + mapsToTransform(m_transform); + init=false; m_transform = m_ssrTransform*m_transform; diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index 0bbe62b85676..e211a99c6840 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -114,9 +114,78 @@ struct ci_orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public dc template< typename Kernel > struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; + + +//we need a custom distance type to use point-distance functions instead of real geometry distance +struct ci_distance : public Equation { + + using Equation::operator=; + ci_distance() : Equation(0) {}; + + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + option_type value; + Scalar calculate(Vector& param1, Vector& param2) { + assert(false); + return 0; + }; + Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + assert(false); + return 0; + }; + Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + assert(false); + return 0; + }; + void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + assert(false); + }; + }; +}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::point3D, tag::point3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::point3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::point3D, tag::line3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::point3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::plane3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::point3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::line3D, tag::line3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::plane3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::plane3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::plane3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct ci_distance::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; + + }//details -struct Coincidence : public dcm::constraint_sequence< fusion::vector2< Distance, details::ci_orientation > > { +struct Coincidence : public dcm::constraint_sequence< fusion::vector2< details::ci_distance, details::ci_orientation > > { //allow to set the distance Coincidence& operator()(Direction val) { fusion::at_c<1>(*this) = val; @@ -128,7 +197,7 @@ struct Coincidence : public dcm::constraint_sequence< fusion::vector2< Distance, }; }; -struct Alignment : public dcm::constraint_sequence< fusion::vector2< Distance, details::ci_orientation > > { +struct Alignment : public dcm::constraint_sequence< fusion::vector2< details::ci_distance, details::ci_orientation > > { //allow to set the distance Alignment& operator()(Direction val) { fusion::at_c<1>(*this) = val; diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index ac9910c4557a..b767b4dae343 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -275,7 +275,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy if(params <= 0 || constraints <= 0) { //TODO:throw #ifdef USE_LOGGING - BOOST_LOG(log)<< "Error in system counting: params = " << params << " and constraints = "<::finishCalculation() { m_global = m_parameter; normalize(); #ifdef USE_LOGGING - BOOST_LOG(log) << "Finish calculation: "< struct getWeightType { typedef typename mpl::find_if, Weight > >::type iter; - typedef typename mpl::deref::type type; + typedef typename mpl::if_< boost::is_same::type >, mpl::void_, typename mpl::deref::type>::type type; }; typedef std::vector< fusion::vector2 > string_vec; @@ -217,7 +217,7 @@ struct inject_set { }; //spezialisation if no type in the typelist has the right weight template<> -struct inject_set { +struct inject_set { template static void apply(Vec& v, Obj g) { From d7ea6f890554536b147fb37cd364b0a129eb2866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sat, 8 Jun 2013 22:47:03 +0200 Subject: [PATCH 135/664] remove logging for sure --- src/Mod/Assembly/App/CMakeLists.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 54e58fa809ed..549de815729a 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -21,12 +21,12 @@ include_directories( ) -#set(Assembly_LIBS -# ${ODE_LIBRARIES} -# ${OCC_LIBRARIES} -# Part -# FreeCADApp -#) +set(Assembly_LIBS + ${ODE_LIBRARIES} + ${OCC_LIBRARIES} + Part + FreeCADApp +) generate_from_xml(ItemPy) generate_from_xml(ItemAssemblyPy) @@ -88,12 +88,12 @@ SET(Assembly_SRCS ${Module_SRCS} ) -set(log_LIB boost_log - rt - ${Boost_SYSTEM_LIBRARY} - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} -) +#set(log_LIB boost_log +# rt +# ${Boost_SYSTEM_LIBRARY} +# ${Boost_FILESYSTEM_LIBRARY} +# ${Boost_THREAD_LIBRARY} +#) add_library(Assembly SHARED ${Assembly_SRCS}) target_link_libraries(Assembly ${Assembly_LIBS} ${log_LIB}) From 9ce0d041758a60dfe531b6ad87f6d7f94f789373 Mon Sep 17 00:00:00 2001 From: jriegel Date: Tue, 18 Jun 2013 19:34:23 +0200 Subject: [PATCH 136/664] fix on unclear types --- src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp | 4 ++-- src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index efabfaa03940..2cfb7f030c91 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -55,7 +55,7 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskSketchBasedParameters */ -TaskSketchBasedParameters::TaskSketchBasedParameters(ViewProvider *vp, QWidget *parent, +TaskSketchBasedParameters::TaskSketchBasedParameters(PartDesignGui::ViewProvider *vp, QWidget *parent, const std::string& pixmapname, const QString& parname) : TaskBox(Gui::BitmapFactory().pixmap(pixmapname.c_str()),parname,true, parent), vp(vp), blockUpdate(false) @@ -198,7 +198,7 @@ TaskSketchBasedParameters::~TaskSketchBasedParameters() // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgSketchBasedParameters::TaskDlgSketchBasedParameters(ViewProvider *vp) +TaskDlgSketchBasedParameters::TaskDlgSketchBasedParameters(PartDesignGui::ViewProvider *vp) : TaskDialog(),vp(vp) { } diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h index 9724fb713031..803b39b3768f 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h @@ -42,7 +42,7 @@ class TaskSketchBasedParameters : public Gui::TaskView::TaskBox, public Gui::Sel Q_OBJECT public: - TaskSketchBasedParameters(ViewProvider* vp, QWidget *parent, + TaskSketchBasedParameters(PartDesignGui::ViewProvider* vp, QWidget *parent, const std::string& pixmapname, const QString& parname); ~TaskSketchBasedParameters(); @@ -59,7 +59,7 @@ protected Q_SLOTS: void onUpdateView(bool on); protected: - ViewProvider *vp; + PartDesignGui::ViewProvider *vp; /// Lock updateUI(), applying changes to the underlying feature and calling recomputeFeature() bool blockUpdate; }; @@ -69,7 +69,7 @@ class TaskDlgSketchBasedParameters : public Gui::TaskView::TaskDialog Q_OBJECT public: - TaskDlgSketchBasedParameters(ViewProvider *vp); + TaskDlgSketchBasedParameters(PartDesignGui::ViewProvider *vp); ~TaskDlgSketchBasedParameters(); public: @@ -90,7 +90,7 @@ class TaskDlgSketchBasedParameters : public Gui::TaskView::TaskDialog { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } protected: - ViewProvider *vp; + PartDesignGui::ViewProvider *vp; }; } //namespace PartDesignGui From a0ec4752d910cf9cff1bdaaf90c3b02185781f2b Mon Sep 17 00:00:00 2001 From: jriegel Date: Tue, 18 Jun 2013 19:49:13 +0200 Subject: [PATCH 137/664] fix icons --- .../PartDesign/Gui/Resources/PartDesign.qrc | 10 +- .../Gui/Resources/icons/PartDesign_Body.svg | 556 ++++++++++++++++++ .../Gui/Resources/icons/PartDesign_Plane.svg | 218 +++++++ 3 files changed, 779 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc index 340e89dda532..cda65f8f2875 100644 --- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc +++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc @@ -13,11 +13,11 @@ icons/PartDesign_Scaled.svg icons/PartDesign_MultiTransform.svg icons/PartDesign_Hole.svg - icons/PartDesign_Body.svg - icons/PartDesign_Boolean.svg - icons/PartDesign_Plane.svg - icons/PartDesign_Line.svg - icons/PartDesign_Point.svg + icons/PartDesign_Body.svg + icons/PartDesign_Boolean.svg + icons/PartDesign_Plane.svg + icons/PartDesign_Line.svg + icons/PartDesign_Point.svg icons/Tree_PartDesign_Pad.svg icons/Tree_PartDesign_Revolution.svg icons/PartDesign_InternalExternalGear.svg diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg index e69de29bb2d1..5e190f947689 100644 --- a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Body.svg @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg index e69de29bb2d1..84dff5e0ce60 100644 --- a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Plane.svg @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + From 34acc5f8b4a4216ee03697010abd345d1447ceaf Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 19 Jun 2013 12:23:18 +0200 Subject: [PATCH 138/664] Allow creating a datum plane tangential to a cylinder and parallel to another plane --- src/Mod/PartDesign/App/DatumPlane.cpp | 79 +++++++++++++------ src/Mod/PartDesign/App/DatumPoint.cpp | 26 ++++-- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 2 + .../PartDesign/Gui/TaskDatumParameters.cpp | 2 + 4 files changed, 80 insertions(+), 29 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index 676588bbf0b9..fec4ff5bc0bf 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -34,8 +34,10 @@ # include # include # include +# include # include # include +# include # include # include # include @@ -74,6 +76,7 @@ using namespace PartDesign; // Note: We don't distinguish between e.g. datum lines and edges here #define PLANE QObject::tr("DPLANE") +#define CYLINDER QObject::tr("DCYLINDER") #define LINE QObject::tr("DLINE") #define POINT QObject::tr("DPOINT") #define ANGLE QObject::tr("Angle") @@ -132,6 +135,15 @@ void Plane::initHints() key.insert(LINE); key.insert(PLANE); key.insert(ANGLE); hints[key] = DONE; // {LINE, PLANE, ANGLE} -> DONE. Plane through line with angle to other plane + key.clear(); value.clear(); + key.insert(CYLINDER); + value.insert(PLANE); + hints[key] = value; // CYLINDER -> PLANE + + key.clear(); value.clear(); + key.insert(CYLINDER); key.insert(PLANE); + hints[key] = DONE; // {CYLINDER, PLANE} -> DONE. Plane tangential to cylinder and normal to other plane + key.clear(); value.clear(); value.insert(POINT); value.insert(LINE); value.insert(PLANE); value.insert(ANGLE); hints[key] = value; @@ -188,6 +200,7 @@ void Plane::onChanged(const App::Property *prop) Base::Vector3d* p3 = NULL; Base::Vector3d* normal = NULL; gp_Lin* line = NULL; + gp_Cylinder* cyl = NULL; for (int i = 0; i < refs.size(); i++) { if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { @@ -246,30 +259,33 @@ void Plane::onChanged(const App::Property *prop) } else if (subshape.ShapeType() == TopAbs_FACE) { TopoDS_Face f = TopoDS::Face(subshape); BRepAdaptor_Surface adapt(f); - if (adapt.GetType() != GeomAbs_Plane) - return; // Non-planar face - - // Ensure that the front and back of the plane corresponds with the face's idea of front and back - bool reverse = (f.Orientation() == TopAbs_REVERSED); - gp_Pln plane = adapt.Plane(); - if (!plane.Direct()) { - // toggle if plane has a left-handed coordinate system - plane.UReverse(); - reverse = !reverse; + if (adapt.GetType() == GeomAbs_Plane) { + // Ensure that the front and back of the plane corresponds with the face's idea of front and back + bool reverse = (f.Orientation() == TopAbs_REVERSED); + gp_Pln plane = adapt.Plane(); + if (!plane.Direct()) { + // toggle if plane has a left-handed coordinate system + plane.UReverse(); + reverse = !reverse; + } + gp_Dir d = adapt.Plane().Axis().Direction(); + if (reverse) d.Reverse(); + + // Ensure that the position of the placement corresponds to what the face would yield in + // Part2DObject::positionBySupport() + Base::Vector3d pos = feature->Placement.getValue().getPosition(); + gp_Pnt gp_pos(pos.x,pos.y,pos.z); + Handle (Geom_Plane) gPlane = new Geom_Plane(plane); + GeomAPI_ProjectPointOnSurf projector(gp_pos,gPlane); + gp_Pnt b = projector.NearestPoint(); + + p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); + normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); + } else if (adapt.GetType() == GeomAbs_Cylinder) { + cyl = new gp_Cylinder(adapt.Cylinder()); + } else { + return; // invalid surface type } - gp_Dir d = adapt.Plane().Axis().Direction(); - if (reverse) d.Reverse(); - - // Ensure that the position of the placement corresponds to what the face would yield in - // Part2DObject::positionBySupport() - Base::Vector3d pos = feature->Placement.getValue().getPosition(); - gp_Pnt gp_pos(pos.x,pos.y,pos.z); - Handle (Geom_Plane) gPlane = new Geom_Plane(plane); - GeomAPI_ProjectPointOnSurf projector(gp_pos,gPlane); - gp_Pnt b = projector.NearestPoint(); - - p1 = new Base::Vector3d(b.X(), b.Y(), b.Z()); - normal = new Base::Vector3d(d.X(), d.Y(), d.Z()); } } else { return; //"PartDesign::Plane: Invalid reference type" @@ -284,6 +300,22 @@ void Plane::onChanged(const App::Property *prop) gp_Dir dir = line->Direction(); Base::Rotation rot(Base::Vector3d(dir.X(), dir.Y(), dir.Z()), Angle.getValue() / 180.0 * M_PI); rot.multVec(*normal, *normal); + } else if ((cyl != NULL) && (normal != NULL)) { + // Plane tangential to cylinder and parallel to other plane + gp_Dir dir(normal->x, normal->y, normal->z); + Handle_Geom_Curve normalLine = new Geom_Line(cyl->Location(), dir); + Handle_Geom_Surface cylinder = new Geom_CylindricalSurface(*cyl); + + // Intersect a line through the base point of the cylinder and normal to the plane with the cylinder itself + GeomAPI_IntCS intersector(normalLine, cylinder); + if (!intersector.IsDone() || (intersector.NbPoints() == 0)) + return; + if (intersector.NbPoints() > 1) + Base::Console().Warning("More than one intersection point for datum plane from cylinder and plane"); + + gp_Pnt inter = intersector.Point(1); + p1 = new Base::Vector3d(inter.X(), inter.Y(), inter.Z()); + // TODO: Allow to control which side of the cylinder the plane is create on - there are always two possibilities } else if ((p1 != NULL) && (normal != NULL)) { // plane from other plane. Nothing to be done } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { @@ -315,6 +347,7 @@ void Plane::onChanged(const App::Property *prop) if (p2 != NULL) delete p2; if (p3 != NULL) delete p3; if (line != NULL) delete line; + if (cyl != NULL) delete cyl; } Part::Datum::onChanged(prop); diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp index b54d98d2c4d3..b61d81633aa8 100644 --- a/src/Mod/PartDesign/App/DatumPoint.cpp +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -36,6 +36,7 @@ # include # include # include +# include # include # include # include @@ -73,6 +74,7 @@ using namespace PartDesign; // Note: We don't distinguish between e.g. datum lines and edges here #define PLANE QObject::tr("DPLANE") +#define CYLINDER QObject::tr("DCYLINDER") #define LINE QObject::tr("DLINE") #define POINT QObject::tr("DPOINT") #define ANGLE QObject::tr("Angle") @@ -317,14 +319,26 @@ const QString getRefType(const App::DocumentObject* obj, const std::string& subn return LINE; else if (type == PartDesign::Point::getClassTypeId()) return POINT; - else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { - // Note: For now, only planar references are possible - if (subname.size() > 4 && subname.substr(0,4) == "Face") - return PLANE; - else if (subname.size() > 4 && subname.substr(0,4) == "Edge") + else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { + if (subname.size() > 4 && subname.substr(0,4) == "Face") { + const Part::Feature* feature = static_cast(obj); + Part::TopoShape topShape = feature->Shape.getShape(); + TopoDS_Shape shape = topShape.getSubShape(subname.c_str()); + if (shape.IsNull() || (shape.ShapeType() != TopAbs_FACE)) + throw Base::Exception("Part::Datum::getRefType(): No valid subshape could be extracted"); + BRepAdaptor_Surface adapt(TopoDS::Face(shape)); + if (adapt.GetType() == GeomAbs_Plane) + return PLANE; + else if (adapt.GetType() == GeomAbs_Cylinder) + return CYLINDER; + else + throw Base::Exception("Part::Datum::getRefType(): Only planar and cylindrical faces are allowed"); + } else if (subname.size() > 4 && subname.substr(0,4) == "Edge") { + // Note: For now, only linear references are possible return LINE; - else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") + } else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") { return POINT; + } } throw Base::Exception("Part::Datum::getRefType(): Illegal object type"); diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 2a8df942b3a2..46f97f293397 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -58,6 +58,8 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c if (pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { // Allow selecting Part::Datum features from the active Body + if (ActivePartObject == NULL) + return false; if (!ActivePartObject->hasFeature(pObj)) return false; diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index bdb55c015acb..6e75ea845544 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -184,6 +184,8 @@ const QString makeRefText(std::set hint) tText = QObject::tr("Line"); else if (((*t) == QObject::tr("DPOINT")) || ((*t) == QObject::tr("Point"))) tText = QObject::tr("Point"); + else if (((*t) == QObject::tr("DCYLINDER")) || ((*t) == QObject::tr("Cylinder"))) + tText = QObject::tr("Cylinder"); else if ((*t) == QObject::tr("Done")) tText = QObject::tr("Done"); result += QString::fromAscii(result.size() == 0 ? "" : "/") + tText; From 02311333b9807fccd873c397739e33f6620ada54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 23 Jun 2013 09:44:35 +0200 Subject: [PATCH 139/664] userfriendly part movement --- src/Mod/Assembly/App/ItemAssembly.cpp | 159 +++++---- .../App/opendcm/core/clustergraph.hpp | 60 +++- .../Assembly/App/opendcm/core/constraint.hpp | 186 ++++++---- .../Assembly/App/opendcm/core/equations.hpp | 37 +- .../Assembly/App/opendcm/core/geometry.hpp | 2 +- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 156 ++++++--- src/Mod/Assembly/App/opendcm/core/object.hpp | 2 +- .../Assembly/App/opendcm/core/property.hpp | 104 ++++-- src/Mod/Assembly/App/opendcm/core/system.hpp | 8 +- src/Mod/Assembly/App/opendcm/module3d.hpp | 1 + .../App/opendcm/module3d/clustermath.hpp | 30 +- .../App/opendcm/module3d/coincident.hpp | 12 +- .../Assembly/App/opendcm/module3d/defines.hpp | 7 + .../Assembly/App/opendcm/module3d/module.hpp | 2 + .../Assembly/App/opendcm/module3d/solver.hpp | 321 +++++++++++------- 15 files changed, 706 insertions(+), 381 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index ec82238906dc..cf932865de5d 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -25,6 +25,7 @@ #ifndef _PreComp_ # include # include +#include #endif #include @@ -43,67 +44,68 @@ namespace Assembly { PROPERTY_SOURCE(Assembly::ItemAssembly, Assembly::Item) -ItemAssembly::ItemAssembly() -{ +ItemAssembly::ItemAssembly() { ADD_PROPERTY(Items,(0)); ADD_PROPERTY(Annotations,(0)); } -short ItemAssembly::mustExecute() const -{ +short ItemAssembly::mustExecute() const { return 0; } -App::DocumentObjectExecReturn *ItemAssembly::execute(void) -{ +App::DocumentObjectExecReturn* ItemAssembly::execute(void) { Base::Console().Message("Execute ItemAssembly\n"); - - try{ - //create a solver and init all child assemblys with subsolvers - m_solver = boost::shared_ptr(new Solver); - init(boost::shared_ptr()); - - //get the constraint group and init the constraints - typedef std::vector::const_iterator iter; - - const std::vector& vector = Annotations.getValues(); - for(iter it=vector.begin(); it != vector.end(); it++) { - - if( (*it)->getTypeId() == Assembly::ConstraintGroup::getClassTypeId() ) - static_cast(*it)->init(this); - }; - - //solve the system - m_solver->solve(); - } - catch(std::exception& e) { - Base::Console().Message("Solver exeption: %s", e.what()); + + try { + //create a solver and init all child assemblys with subsolvers + m_solver = boost::shared_ptr(new Solver); + init(boost::shared_ptr()); + + //get the constraint group and init the constraints + typedef std::vector::const_iterator iter; + + const std::vector& vector = Annotations.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if((*it)->getTypeId() == Assembly::ConstraintGroup::getClassTypeId()) + static_cast(*it)->init(this); + }; + + //solve the system + m_solver->solve(); + } catch(dcm::solving_error& e) { + Base::Console().Error("Solver failed with error %i: %s", + *boost::get_error_info(e), + boost::get_error_info(e)->c_str()); + } catch(dcm::creation_error& e) { + Base::Console().Error("Creation failed with error %i: %s", + *boost::get_error_info(e), + boost::get_error_info(e)->c_str()); } - + this->touch(); return App::DocumentObject::StdReturn; } -TopoDS_Shape ItemAssembly::getShape(void) const -{ +TopoDS_Shape ItemAssembly::getShape(void) const { std::vector s; std::vector obj = Items.getValues(); std::vector::iterator it; - for (it = obj.begin(); it != obj.end(); ++it) { - if ((*it)->getTypeId().isDerivedFrom(Assembly::Item::getClassTypeId())) { + for(it = obj.begin(); it != obj.end(); ++it) { + if((*it)->getTypeId().isDerivedFrom(Assembly::Item::getClassTypeId())) { TopoDS_Shape aShape = static_cast(*it)->getShape(); - if (!aShape.IsNull()) + if(!aShape.IsNull()) s.push_back(aShape); } } - if (s.size() > 0) { + if(s.size() > 0) { TopoDS_Compound aRes = TopoDS_Compound(); BRep_Builder aBuilder = BRep_Builder(); aBuilder.MakeCompound(aRes); - for (std::vector::iterator it = s.begin(); it != s.end(); ++it) { + for(std::vector::iterator it = s.begin(); it != s.end(); ++it) { aBuilder.Add(aRes, *it); } @@ -113,51 +115,49 @@ TopoDS_Shape ItemAssembly::getShape(void) const } // set empty shape return TopoDS_Compound(); - + } -PyObject *ItemAssembly::getPyObject(void) -{ - if (PythonObject.is(Py::_None())){ +PyObject* ItemAssembly::getPyObject(void) { + if(PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new ItemAssemblyPy(this),true); } - return Py::new_reference_to(PythonObject); + return Py::new_reference_to(PythonObject); } bool ItemAssembly::isParentAssembly(ItemPart* part) { typedef std::vector::const_iterator iter; - + const std::vector& vector = Items.getValues(); for(iter it=vector.begin(); it != vector.end(); it++) { - - if( (*it)->getTypeId() == Assembly::ItemPart::getClassTypeId() ) - if(*it == part) return true; + + if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) + if(*it == part) return true; }; - + return false; } ItemAssembly* ItemAssembly::getParentAssembly(ItemPart* part) { typedef std::vector::const_iterator iter; - + const std::vector& vector = Items.getValues(); for(iter it=vector.begin(); it != vector.end(); it++) { - - if( (*it)->getTypeId() == Assembly::ItemPart::getClassTypeId() ) { - if(*it == part) - return this; - } - else if ( (*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId() ) { - - Assembly::ItemAssembly* assembly = static_cast(*it)->getParentAssembly(part); - if(assembly) - return assembly; - } + + if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) { + if(*it == part) + return this; + } else if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + Assembly::ItemAssembly* assembly = static_cast(*it)->getParentAssembly(part); + if(assembly) + return assembly; + } }; - + return (ItemAssembly*)NULL; } @@ -166,41 +166,40 @@ ItemAssembly* ItemAssembly::getParentAssembly(ItemPart* part) { ItemPart* ItemAssembly::getContainingPart(App::DocumentObject* obj) { typedef std::vector::const_iterator iter; - + const std::vector& vector = Items.getValues(); for(iter it=vector.begin(); it != vector.end(); it++) { - - if( (*it)->getTypeId() == Assembly::ItemPart::getClassTypeId() ) { - if(static_cast(*it)->holdsObject(obj)) - return static_cast(*it); - } - else if ( (*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId() ) { - - Assembly::ItemPart* part = static_cast(*it)->getContainingPart(obj); - if(part) - return part; - } + + if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) { + if(static_cast(*it)->holdsObject(obj)) + return static_cast(*it); + } else if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + Assembly::ItemPart* part = static_cast(*it)->getContainingPart(obj); + if(part) + return part; + } }; - + return NULL; } void ItemAssembly::init(boost::shared_ptr parent) { if(parent) - m_solver = boost::shared_ptr(parent->createSubsystem()); - + m_solver = boost::shared_ptr(parent->createSubsystem()); + typedef std::vector::const_iterator iter; - + const std::vector& vector = Items.getValues(); for(iter it=vector.begin(); it != vector.end(); it++) { - - if ( (*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId() ) { - - static_cast(*it)->init(m_solver); - } + + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + static_cast(*it)->init(m_solver); + } }; } -} \ No newline at end of file +} diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index 7e2e69837c7c..9ac0cb3fe408 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -61,6 +61,15 @@ namespace dcm { namespace details { +template +struct vector_fold : mpl::fold< seq, state, + mpl::push_back > {}; + +//also add basic properties for graph algorithms like index and color +typedef mpl::vector2 bgl_v_props; +typedef mpl::vector2 bgl_e_props; + + typedef boost::adjacency_list_traits list_traits; typedef int universalID; @@ -127,18 +136,22 @@ struct GlobalEdge { template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, boost::undirectedS, - fusion::vector< GlobalVertex, typename details::pts::type, + fusion::vector< GlobalVertex, + typename details::pts::type>::type, typename details::sps::type>, - fusion::vector< typename details::pts::type, + fusion::vector< typename details::pts::type>::type, std::vector< fusion::vector< typename details::sps::type, GlobalEdge > > > >, public boost::noncopyable, public boost::enable_shared_from_this > { public: + typedef typename details::vector_fold::type edge_properties; + typedef typename details::vector_fold::type vertex_properties; + typedef fusion::vector< typename details::sps::type, GlobalEdge > edge_bundle_single; - typedef fusion::vector< typename details::pts::type, std::vector< edge_bundle_single > > edge_bundle; + typedef fusion::vector< typename details::pts::type, std::vector< edge_bundle_single > > edge_bundle; typedef typename std::vector< edge_bundle_single >::iterator edge_single_iterator; - typedef fusion::vector< GlobalVertex, typename details::pts::type, + typedef fusion::vector< GlobalVertex, typename details::pts::type, typename details::sps::type > vertex_bundle; @@ -154,7 +167,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, typename mpl::end::type >, typename mpl::push_back::type, cluster_prop >::type cluster_properties; - + typedef typename details::pts::type cluster_bundle; typedef typename boost::graph_traits::vertex_iterator local_vertex_iterator; @@ -165,9 +178,6 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, cluster_bundle m_cluster_bundle; - typedef edge_prop edge_properties; - typedef vertex_prop vertex_properties; - private: struct global_extractor { typedef GlobalEdge& result_type; @@ -277,7 +287,8 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, template void copyInto(boost::shared_ptr into, Functor& functor) const { - //lists does not provide vertex index, so we have to build our own + //lists does not provide vertex index, so we have to build our own (cant use the internal + //vertex_index_property as we would need to reset the indices and that's not possible in const graph) typedef std::map IndexMap; IndexMap mapIndex; boost::associative_property_map propmapIndex(mapIndex); @@ -1106,11 +1117,11 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, typedef typename prop::type base_type; typedef base_type& result_type; - typedef typename mpl::find::type vertex_iterator; - typedef typename mpl::find::type edge_iterator; - typedef typename mpl::if_::type >, + typedef typename mpl::find::type vertex_iterator; + typedef typename mpl::find::type edge_iterator; + typedef typename mpl::if_::type >, edge_iterator, vertex_iterator>::type iterator; - BOOST_MPL_ASSERT((mpl::not_::type > >)); + BOOST_MPL_ASSERT((mpl::not_::type > >)); //used with vertex bundle type template @@ -1162,6 +1173,29 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, setChanged(); }; + + /** + * @brief recreate the internal index maps for edges and vertices + * + * Quite many boost graph algorithms need the indices for vertices and edges which are provided by property + * maps. As we use list, and not vector, as underlaying storage we don't get that property for free and + * need to create it ourself. To ease that procedure the internal property vertex_index_prop and edge_index_prop + * can be used as property maps and can be initialized by calling this function. + * + * @return void + **/ + void initIndexMaps() { + + //just iterate over all edges and vertices and give them all a unique index + std::pair vit = boost::vertices(*this); + for(int c=0; vit.first != vit.second; vit.first++, c++) + setProperty(*vit.first, c); + + std::pair eit = boost::edges(*this); + for(int c=0; eit.first != eit.second; eit.first++, c++) + setProperty(*eit.first, c); + }; + /******************************************************** diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index db1fc39d19e2..a54685bac36b 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -75,17 +75,17 @@ class Constraint : public Object { std::vector getGenericConstraints(); std::vector getEquationTypes(); std::vector getConstraintTypes(); - + template void initialize(ConstraintVector& obj); - + protected: int equationCount(); template< typename creator_type> void resetType(creator_type& c); - void calculate(Scalar scale); + void calculate(Scalar scale, bool rotation_only = false); void setMaps(MES& mes); @@ -96,35 +96,38 @@ class Constraint : public Object { }; void collectPseudoPoints(Vec& vec1, Vec& vec2); - + //Equation is the constraint with types, the EquationSet hold all needed Maps for calculation template struct EquationSet { - EquationSet() : m_diff_first(NULL,0,DS(0,0)), m_diff_second(NULL,0,DS(0,0)), + EquationSet() : m_diff_first(NULL,0,DS(0,0)), m_diff_first_rot(NULL,0,DS(0,0)), + m_diff_second(NULL,0,DS(0,0)), m_diff_second_rot(NULL,0,DS(0,0)), m_residual(NULL,0,DS(0,0)) {}; Equation m_eq; - typename Kernel::VectorMap m_diff_first; //first geometry diff - typename Kernel::VectorMap m_diff_second; //second geometry diff + typename Kernel::VectorMap m_diff_first, m_diff_first_rot; //first geometry diff + typename Kernel::VectorMap m_diff_second, m_diff_second_rot; //second geometry diff typename Kernel::VectorMap m_residual; + bool pure_rotation; + typedef Equation eq_type; }; struct placeholder { virtual ~placeholder() {} virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const = 0; - virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale) = 0; + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false) = 0; virtual int equationCount() = 0; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; virtual placeholder* clone() = 0; - - //some runtime type infos are needed, as we cant access the contents with arbitrary functors + + //some runtime type infos are needed, as we cant access the contents with arbitrary functors virtual std::vector getGenericEquations() = 0; - virtual std::vector getGenericConstraints() = 0; - virtual std::vector getEquationTypes() = 0; - virtual std::vector getConstraintTypes() = 0; + virtual std::vector getGenericConstraints() = 0; + virtual std::vector getEquationTypes() = 0; + virtual std::vector getConstraintTypes() = 0; }; public: @@ -170,8 +173,9 @@ class Constraint : public Object { geom_ptr first, second; Scalar scale; + bool rot_only; - Calculater(geom_ptr f, geom_ptr s, Scalar sc); + Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only = false); template< typename T > void operator()(T& val) const; @@ -205,16 +209,16 @@ class Constraint : public Object { template void operator()(T& val) const; }; - - struct GenericConstraints { + + struct GenericConstraints { std::vector& vec; GenericConstraints(std::vector& v); template void operator()(T& val) const; }; - - struct Types { + + struct Types { std::vector& vec; Types(std::vector& v); @@ -222,10 +226,10 @@ class Constraint : public Object { void operator()(T& val) const; }; - + holder(Objects& obj); - virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale); + virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false); virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); @@ -233,14 +237,14 @@ class Constraint : public Object { virtual int equationCount() { return mpl::size::value; }; - + virtual std::vector getGenericEquations(); - virtual std::vector getGenericConstraints(); - virtual std::vector getEquationTypes(); - virtual std::vector getConstraintTypes(); + virtual std::vector getGenericConstraints(); + virtual std::vector getEquationTypes(); + virtual std::vector getConstraintTypes(); EquationSets m_sets; - Objects m_objects; + Objects m_objects; }; protected: @@ -282,15 +286,15 @@ Constraint::Constraint(Sys& system, geom_p : first(f), second(s), content(0) { this->m_system = &system; - cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); - cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); + //cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); + //cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); }; template Constraint::~Constraint() { delete content; - first->template disconnectSignal(cf); - second->template disconnectSignal(cs); + //first->template disconnectSignal(cf); + //second->template disconnectSignal(cs); }; template @@ -342,8 +346,8 @@ void Constraint::resetType(creator_type& c }; template -void Constraint::calculate(Scalar scale) { - content->calculate(first, second, scale); +void Constraint::calculate(Scalar scale, bool rotation_only) { + content->calculate(first, second, scale, rotation_only); }; template @@ -391,6 +395,7 @@ Constraint::holder::type, iterator>::type distance; BOOST_MPL_ASSERT((mpl::not_::type > >)); val.m_eq.value = fusion::at(objects).value; + val.pure_rotation = fusion::at(objects).pure_rotation; }; template @@ -403,7 +408,8 @@ Constraint::holder template -Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc) : first(f), second(s), scale(sc) { +Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) + : first(f), second(s), scale(sc), rot_only(rotation_only) { }; @@ -412,42 +418,79 @@ template template< typename T > void Constraint::holder::Calculater::operator()(T& val) const { - val.m_eq.setScale(scale); + //if we only need pure rotational functions and we are not such a nice thing, everything becomes 0 + if(rot_only && !val.pure_rotation) { - val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); - - //now see which way we should calculate the gradient (may be diffrent for both geometries) - if(first->m_parameterCount) { + val.m_residual(0) = 0; if(first->getClusterMode()) { - //when the cluster is fixed no maps are set as no parameters exist. if(!first->isClusterFixed()) { - - //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors - for(int i=0; i<6; i++) { - typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); - val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); - } + val.m_diff_first_rot.setZero(); + val.m_diff_first.setZero(); } - } else { - //not in cluster, so allow the constraint to optimize the gradient calculation - val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); - } - } - if(second->m_parameterCount) { + } else + val.m_diff_first.setZero(); + if(second->getClusterMode()) { if(!second->isClusterFixed()) { + val.m_diff_second_rot.setZero(); + val.m_diff_second.setZero(); + } + } else + val.m_diff_second.setZero(); - //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors - for(int i=0; i<6; i++) { - typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); - val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, block); + } + //we need to calculate, so lets go for it! + else { + + val.m_eq.setScale(scale); + + val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); + + //now see which way we should calculate the gradient (may be diffrent for both geometries) + if(first->m_parameterCount) { + if(first->getClusterMode()) { + //when the cluster is fixed no maps are set as no parameters exist. + if(!first->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<3; i++) { + typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); + val.m_diff_first_rot(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + } + //and now with the translations + for(int i=0; i<3; i++) { + typename Kernel::VectorMap block(&first->m_diffparam(0,i+3),first->m_parameterCount,1, DS(1,1)); + val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + } } + } else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); + } + } + if(second->m_parameterCount) { + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<3; i++) { + typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); + val.m_diff_second_rot(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, block); + } + //and the translation seperated + for(int i=0; i<3; i++) { + typename Kernel::VectorMap block(&second->m_diffparam(0,i+3),second->m_parameterCount,1, DS(1,1)); + val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, block); + } + } + } else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); } - } else { - //not in cluster, so allow the constraint to optimize the gradient calculation - val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); } } }; @@ -469,14 +512,16 @@ void Constraint::holdergetClusterMode()) { if(!first->isClusterFixed()) { - mes.setJacobiMap(equation, first->m_offset, 6, val.m_diff_first); + mes.setJacobiMap(equation, first->m_offset_rot, 3, val.m_diff_first_rot); + mes.setJacobiMap(equation, first->m_offset, 3, val.m_diff_first); } } else mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); if(second->getClusterMode()) { if(!second->isClusterFixed()) { - mes.setJacobiMap(equation, second->m_offset, 6, val.m_diff_second); + mes.setJacobiMap(equation, second->m_offset_rot, 3, val.m_diff_second_rot); + mes.setJacobiMap(equation, second->m_offset, 3, val.m_diff_second); } } else mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); }; @@ -544,7 +589,7 @@ template template< typename T > void Constraint::holder::Types::operator()(T& val) const { vec.push_back(&typeid(T)); -}; +}; template template @@ -555,8 +600,9 @@ Constraint::holder template -void Constraint::holder::calculate(geom_ptr first, geom_ptr second, Scalar scale) { - fusion::for_each(m_sets, Calculater(first, second, scale)); +void Constraint::holder::calculate(geom_ptr first, geom_ptr second, + Scalar scale, bool rotation_only) { + fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only)); }; template @@ -589,19 +635,19 @@ Constraint::holder template -std::vector +std::vector Constraint::holder::getGenericEquations() { std::vector vec; - fusion::for_each( m_sets, GenericEquations(vec) ); + fusion::for_each(m_sets, GenericEquations(vec)); return vec; }; template template -std::vector +std::vector Constraint::holder::getGenericConstraints() { std::vector vec; - fusion::for_each( m_objects, GenericConstraints(vec) ); + fusion::for_each(m_objects, GenericConstraints(vec)); return vec; }; @@ -610,7 +656,7 @@ template std::vector Constraint::holder::getEquationTypes() { std::vector vec; - mpl::for_each< EquationVector >( Types(vec) ); + mpl::for_each< EquationVector >(Types(vec)); return vec; }; @@ -619,7 +665,7 @@ template std::vector Constraint::holder::getConstraintTypes() { std::vector vec; - mpl::for_each< ConstraintVector >( Types(vec) ); + mpl::for_each< ConstraintVector >(Types(vec)); return vec; }; diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 8f3caae4503f..09c12d0b7e5a 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -35,6 +35,8 @@ #include #include +#include + namespace fusion = boost::fusion; namespace mpl = boost::mpl; @@ -42,6 +44,11 @@ namespace mpl = boost::mpl; namespace dcm { +//a few exceptions to handle unsupported combinations +struct constraint_error : virtual boost::exception { }; +typedef boost::error_info error_type_first_geometry; +typedef boost::error_info error_type_second_geometry; + struct no_option {}; template @@ -143,13 +150,14 @@ struct pushed_seq { typedef constraint_sequence type; }; -template +template struct Equation : public EQ { typedef Option option_type; option_type value; + bool pure_rotation; - Equation(option_type val = option_type()) : value(val) {}; + Equation(option_type val = option_type()) : value(val), pure_rotation(rotation_only) {}; Derived& operator()(const option_type val) { value = val; @@ -204,6 +212,11 @@ struct Distance : public Equation { template< typename Kernel, typename Tag1, typename Tag2 > struct type { + type() { + throw constraint_error() << boost::errinfo_errno(100) << error_message("unsupported geometry in distance constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; typedef std::vector > Vec; @@ -240,7 +253,7 @@ struct Distance : public Equation { //the possible directions enum Direction { parallel, equal, opposite, perpendicular }; -struct Orientation : public Equation { +struct Orientation : public Equation { using Equation::operator=; Orientation() : Equation(parallel) {}; @@ -248,6 +261,11 @@ struct Orientation : public Equation { template< typename Kernel, typename Tag1, typename Tag2 > struct type : public PseudoScale { + type() { + throw constraint_error() << boost::errinfo_errno(101) << error_message("unsupported geometry in orientation constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; @@ -275,7 +293,7 @@ struct Orientation : public Equation { }; }; -struct Angle : public Equation { +struct Angle : public Equation { using Equation::operator=; Angle() : Equation(0) {}; @@ -283,6 +301,11 @@ struct Angle : public Equation { template< typename Kernel, typename Tag1, typename Tag2 > struct type : public PseudoScale { + type() { + throw constraint_error() << boost::errinfo_errno(102) << error_message("unsupported geometry in angle constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; @@ -291,15 +314,15 @@ struct Angle : public Equation { //template definition Scalar calculate(Vector& param1, Vector& param2) { assert(false); - return 0; + return 0; }; Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { assert(false); - return 0; + return 0; }; Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { assert(false); - return 0; + return 0; }; void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { assert(false); diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index 131a2d24e432..a8c5d6746992 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -220,7 +220,7 @@ class Geometry : public Object #include +#include +#include +#include + #include #include "transformation.hpp" @@ -41,6 +45,17 @@ struct nothing { void operator()() {}; }; +//the parameter types +enum ParameterType { + general, + rotation, + complete +}; + +//all solving related errors +typedef boost::error_info error_message; +struct solving_error : virtual boost::exception { }; + template struct Dogleg { @@ -51,7 +66,7 @@ struct Dogleg { typedef typename Kernel::number_type number_type; number_type tolg, tolx, tolf; - Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-5) { + Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-6) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); @@ -59,9 +74,9 @@ struct Dogleg { }; template - int calculateStep(const Eigen::MatrixBase& g, const Eigen::MatrixBase& jacobi, - const Eigen::MatrixBase& residual, Eigen::MatrixBase& h_dl, - const double delta) { + void calculateStep(const Eigen::MatrixBase& g, const Eigen::MatrixBase& jacobi, + const Eigen::MatrixBase& residual, Eigen::MatrixBase& h_dl, + const double delta) { // get the steepest descent stepsize and direction const double alpha(g.squaredNorm()/(jacobi*g).squaredNorm()); @@ -122,8 +137,6 @@ struct Dogleg { } #endif } - - return 0; }; int solve(typename Kernel::MappedEquationSystem& sys) { @@ -137,15 +150,16 @@ struct Dogleg { clock_t start = clock(); clock_t inc_rec = clock(); - if(!sys.isValid()) return 5; + if(!sys.isValid()) + throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system"); + bool translate = true; - typename Kernel::Vector h_dl, F_old(sys.m_eqns), g(sys.m_eqns); - typename Kernel::Matrix J_old(sys.m_eqns, sys.m_params); + typename Kernel::Vector h_dl, F_old(sys.equationCount()), g(sys.equationCount()); + typename Kernel::Matrix J_old(sys.equationCount(), sys.parameterCount()); sys.recalculate(); - #ifdef USE_LOGGING BOOST_LOG(log)<< "initial jacobi: "<= maxIterNumber) - stop = 4; + throw solving_error() << boost::errinfo_errno(4) << error_message("maximal iterations reached"); else if(!boost::math::isfinite(err)) - stop = 5; + throw solving_error() << boost::errinfo_errno(5) << error_message("error is inf or nan"); else if(err > diverging_lim) - stop = 6; + throw solving_error() << boost::errinfo_errno(6) << error_message("error diverged"); // see if we are already finished @@ -243,7 +257,7 @@ struct Dogleg { #endif rescale(); sys.recalculate(); - } + } //it can also happen that the differentials get too small, however, we cant check for that else if(iter>1 && (counter>50)) { rescale(); @@ -339,48 +353,81 @@ struct Kernel { typedef E::Matrix type; }; - struct MappedEquationSystem { - Matrix Jacobi; - Vector Parameter; - Vector Residual; - number_type Scaling; + protected: + Matrix m_jacobi; + Vector m_parameter; + + bool rot_only; //calculate only rotations? int m_params, m_eqns; //total amount - int m_param_offset, m_eqn_offset; //current positions while creation + int m_param_rot_offset, m_param_trans_offset, m_eqn_offset; //current positions while creation - MappedEquationSystem(int params, int equations) - : Jacobi(equations, params), - Parameter(params), Residual(equations), - m_params(params), m_eqns(equations), Scaling(1.) { + public: + MatrixMap Jacobi; + VectorMap Parameter; + Vector Residual; + + number_type Scaling; - m_param_offset = 0; + int parameterCount() { + return m_params; + }; + int equationCount() { + return m_eqns; + }; + + bool rotationOnly() { + return rot_only; + }; + + MappedEquationSystem(int params, int equations) + : rot_only(false), m_jacobi(equations, params), + m_parameter(params), Residual(equations), + m_params(params), m_eqns(equations), Scaling(1.), + Jacobi(&m_jacobi(0,0),equations,params,DynStride(equations,1)), + Parameter(&m_parameter(0),params,DynStride(1,1)) { + + m_param_rot_offset = 0; + m_param_trans_offset = params; m_eqn_offset = 0; - Jacobi.setZero(); //important as some places are never written + m_jacobi.setZero(); //important as some places are never written }; - int setParameterMap(int number, VectorMap& map) { + int setParameterMap(int number, VectorMap& map, ParameterType t = general) { - new(&map) VectorMap(&Parameter(m_param_offset), number, DynStride(1,1)); - m_param_offset += number; - return m_param_offset-number; + if(t == rotation) { + new(&map) VectorMap(&m_parameter(m_param_rot_offset), number, DynStride(1,1)); + m_param_rot_offset += number; + return m_param_rot_offset-number; + } else { + m_param_trans_offset -= number; + new(&map) VectorMap(&m_parameter(m_param_trans_offset), number, DynStride(1,1)); + return m_param_trans_offset; + } }; - int setParameterMap(Vector3Map& map) { + int setParameterMap(Vector3Map& map, ParameterType t = general) { - new(&map) Vector3Map(&Parameter(m_param_offset)); - m_param_offset += 3; - return m_param_offset-3; + if(t == rotation) { + new(&map) Vector3Map(&m_parameter(m_param_rot_offset)); + m_param_rot_offset += 3; + return m_param_rot_offset-3; + } else { + m_param_trans_offset -= 3; + new(&map) Vector3Map(&m_parameter(m_param_trans_offset)); + return m_param_trans_offset; + } }; int setResidualMap(VectorMap& map) { new(&map) VectorMap(&Residual(m_eqn_offset), 1, DynStride(1,1)); return m_eqn_offset++; }; void setJacobiMap(int eqn, int offset, int number, CVectorMap& map) { - new(&map) CVectorMap(&Jacobi(eqn, offset), number, DynStride(0,m_eqns)); + new(&map) CVectorMap(&m_jacobi(eqn, offset), number, DynStride(0,m_eqns)); }; void setJacobiMap(int eqn, int offset, int number, VectorMap& map) { - new(&map) VectorMap(&Jacobi(eqn, offset), number, DynStride(0,m_eqns)); + new(&map) VectorMap(&m_jacobi(eqn, offset), number, DynStride(0,m_eqns)); }; bool isValid() { @@ -388,6 +435,36 @@ struct Kernel { return true; }; + void setAccess(ParameterType t) { + + if(t==complete) { + new(&Jacobi) VectorMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),m_params,DynStride(1,1)); + } else if(t==rotation) { + int num = m_param_trans_offset; + new(&Jacobi) VectorMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1)); + } else if(t==general) { + int num = m_params - m_param_trans_offset; + new(&Jacobi) VectorMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1)); + } + }; + + void setGeneralEquationAccess(bool general) { + rot_only = !general; + }; + + bool hasParameterType(ParameterType t) { + + if(t==rotation) + return (m_param_rot_offset>0); + else if(t==general) + return (m_param_trans_offset0); + }; + virtual void recalculate() = 0; }; @@ -423,3 +500,6 @@ struct Kernel { #endif //GCM_KERNEL_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/object.hpp b/src/Mod/Assembly/App/opendcm/core/object.hpp index 09a1d1ac3e76..3218602d8040 100644 --- a/src/Mod/Assembly/App/opendcm/core/object.hpp +++ b/src/Mod/Assembly/App/opendcm/core/object.hpp @@ -105,7 +105,7 @@ typedef boost::any Connection; template struct Object : public boost::enable_shared_from_this { - Object() {}; + Object() {}; Object(Sys& system); /** diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp index dd7b68bbaa03..b42b1f018f48 100644 --- a/src/Mod/Assembly/App/opendcm/core/property.hpp +++ b/src/Mod/Assembly/App/opendcm/core/property.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -45,12 +46,14 @@ template struct vertex_selector { typedef typename boost::graph_traits::vertex_descriptor key_type; typedef typename Graph::vertex_properties sequence_type; + typedef mpl::int_<1> property_distance; }; template struct edge_selector { typedef typename boost::graph_traits::edge_descriptor key_type; typedef typename Graph::edge_properties sequence_type; + typedef mpl::int_<0> property_distance; }; template< typename Kind, typename Graph> @@ -97,44 +100,14 @@ class property_map { typedef Property property; typedef typename dcm::details::property_selector::sequence_type sequence; + typedef typename dcm::details::property_selector::property_distance distance; - property_map(Graph& g) + property_map(boost::shared_ptr g) : m_graph(g) { } - Graph& m_graph; + boost::shared_ptr m_graph; }; -template -typename property_map::value_type get(const property_map& map, - typename property_map::key_type key) { - - typedef property_map map_t; - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - return fusion::at(fusion::at_c<0>(map.m_graph[key])); -}; - -template -void put(const property_map& map, - typename property_map::key_type key, - const typename property_map::value_type& value) { - - typedef property_map map_t; - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - fusion::at(fusion::at_c<0>(map.m_graph[key])) = value; -}; - - -template -typename property_map::reference at(const property_map& map, - typename property_map::key_type key) { - typedef property_map map_t; - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - return fusion::at(fusion::at_c<0>(map.m_graph[key])); -} - //now create some standart properties //*********************************** @@ -143,18 +116,40 @@ struct empty_prop { typedef int kind; typedef int type; }; - +//type of a graph cluster struct type_prop { //states the type of a cluster typedef cluster_property kind; typedef int type; }; - +//cluster in graph changed? struct changed_prop { typedef cluster_property kind; typedef bool type; }; +//vertex index for bgl algorithms +struct vertex_index_prop { + typedef vertex_property kind; + typedef int type; +}; +//edge index for bgl algorithms +struct edge_index_prop { + typedef edge_property kind; + typedef int type; +}; +//vertex color for bgl algorithms +struct vertex_color_prop { + typedef vertex_property kind; + typedef boost::default_color_type type; +}; +//edge color for bgl algorithms +struct edge_color_prop { + typedef edge_property kind; + typedef boost::default_color_type type; +}; + +//object id's template struct id_prop { typedef object_property kind; @@ -163,5 +158,44 @@ struct id_prop { } +template +void pretty(T t) { + std::cout<<__PRETTY_FUNCTION__< +typename dcm::property_map::value_type get(const dcm::property_map& map, + typename dcm::property_map::key_type key) { + + typedef dcm::property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + + return fusion::at(fusion::at::distance>(map.m_graph->operator[](key))); +}; + +template +void put(const dcm::property_map& map, + typename dcm::property_map::key_type key, + const typename dcm::property_map::value_type& value) { + + typedef dcm::property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + fusion::at(fusion::at::distance>(map.m_graph->operator[](key))) = value; +}; + + +template +typename dcm::property_map::reference at(const dcm::property_map& map, + typename dcm::property_map::key_type key) { + typedef dcm::property_map map_t; + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + return fusion::at(fusion::at::distance>(map.m_graph->operator[](key))); +} +} #endif //GCM_PROPERTY_H diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp index c5c9a55233a5..2b0ac11be6f1 100644 --- a/src/Mod/Assembly/App/opendcm/core/system.hpp +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -55,10 +55,6 @@ namespace details { enum { subcluster = 10}; -template -struct vector_fold : mpl::fold< seq, state, - mpl::push_back > {}; - template struct edge_fold : mpl::fold< seq, state, mpl::if_< is_edge_property, @@ -81,7 +77,7 @@ struct obj_fold : mpl::fold< seq, state, mpl::push_back, mpl::_1 > > {}; template -struct property_map { +struct property_map_fold { typedef typename mpl::fold< objects, mpl::map<>, mpl::insert< mpl::_1, mpl::pair< mpl::_2, details::obj_fold, mpl::_2 > > > >::type type; @@ -164,7 +160,7 @@ class System : public T1::template type< System >::inherit typedef typename details::cluster_fold< properties, mpl::vector >::type cluster_properties; - typedef typename details::property_map::type object_properties; + typedef typename details::property_map_fold::type object_properties; protected: //object storage diff --git a/src/Mod/Assembly/App/opendcm/module3d.hpp b/src/Mod/Assembly/App/opendcm/module3d.hpp index a0c4392fcb99..92206745f3dd 100644 --- a/src/Mod/Assembly/App/opendcm/module3d.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d.hpp @@ -27,6 +27,7 @@ #pragma warning( disable : 4503 ) #endif +#include "module3d/defines.hpp" #include "module3d/geometry.hpp" #include "module3d/distance.hpp" #include "module3d/parallel.hpp" diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp index ef2a2604f8b6..2d44b1995a68 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "defines.hpp" #define MAXFAKTOR 1.2 //the maximal distance allowd by a point normed to the cluster size @@ -64,7 +65,7 @@ struct ClusterMath { typename Kernel::Vector3Map m_normQ; typename Kernel::Quaternion m_resetQuaternion; - int m_offset; + int m_offset, m_offset_rot; bool init, fix; std::vector m_geometry; @@ -84,8 +85,8 @@ struct ClusterMath { public: ClusterMath(); - void setParameterOffset(int offset); - int getParameterOffset(); + void setParameterOffset(int offset, ParameterType t); + int getParameterOffset(ParameterType t); typename Kernel::Vector3Map& getNormQuaternionMap(); typename Kernel::Vector3Map& getTranslationMap(); @@ -137,7 +138,7 @@ struct ClusterMath { const typename Kernel::Vector3& p2, const typename Kernel::Vector3& p3); public: - EIGEN_MAKE_ALIGNED_OPERATOR_NEW + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; @@ -160,13 +161,19 @@ ClusterMath::ClusterMath() : m_normQ(NULL), m_translation(NULL), init(false }; template -void ClusterMath::setParameterOffset(int offset) { - m_offset = offset; +void ClusterMath::setParameterOffset(int offset, dcm::ParameterType t) { + if(t == general) + m_offset = offset; + else + m_offset_rot = offset; }; template -int ClusterMath::getParameterOffset() { - return m_offset; +int ClusterMath::getParameterOffset(ParameterType t) { + if(t == general) + return m_offset; + else + return m_offset_rot; }; template @@ -243,7 +250,7 @@ void ClusterMath::finishCalculation() { #ifdef USE_LOGGING BOOST_LOG(log) << "Finish calculation"; #endif - + mapsToTransform(m_transform); init=false; @@ -419,7 +426,8 @@ void ClusterMath::map_downstream::operator()(Geom g) { //allow iteration over all maped geometries m_clusterMath.addGeometry(g); //set the offsets so that geometry knows where it is in the parameter map - g->m_offset = m_clusterMath.getParameterOffset(); + g->m_offset = m_clusterMath.getParameterOffset(general); + g->m_offset_rot = m_clusterMath.getParameterOffset(rotation); //position and offset of the parameters must be set to the clusters values g->setClusterMode(true, m_isFixed); //calculate the appropriate local values @@ -716,7 +724,7 @@ typename ClusterMath::Scalar ClusterMath::calcOnePoint(const typename template typename ClusterMath::Scalar ClusterMath::calcTwoPoints(const typename ClusterMath::Kernel::Vector3& p1, - const typename ClusterMath::Kernel::Vector3& p2) { + const typename ClusterMath::Kernel::Vector3& p2) { //two points have their minimal scale at the mid position. Scaling perpendicular to this //line allows arbitrary scale values. Best is to have the scale dir move towards the origin diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index e211a99c6840..fd45c6b69fc1 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -28,7 +28,7 @@ namespace dcm { namespace details { //we need a custom orientation type to allow coincidents with points -struct ci_orientation : public Equation { +struct ci_orientation : public Equation { using Equation::operator=; ci_orientation() : Equation(parallel) {}; @@ -37,6 +37,11 @@ struct ci_orientation : public Equation { template< typename Kernel, typename Tag1, typename Tag2 > struct type : public PseudoScale { + type() { + throw constraint_error() << boost::errinfo_errno(103) << error_message("unsupported geometry in coincidence/alignment orientation constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; typedef std::vector > Vec; @@ -126,6 +131,11 @@ struct ci_distance : public Equation { template< typename Kernel, typename Tag1, typename Tag2 > struct type : public PseudoScale { + type() { + throw constraint_error() << boost::errinfo_errno(104) << error_message("unsupported geometry in coincidence/alignment distance constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; typedef std::vector > Vec; diff --git a/src/Mod/Assembly/App/opendcm/module3d/defines.hpp b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp index 60549e18cb36..fb49f2cd32cd 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/defines.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp @@ -20,6 +20,8 @@ #ifndef GCM_DEFINES_3D_H #define GCM_DEFINES_3D_H +#include + namespace dcm { namespace details { @@ -28,6 +30,11 @@ enum { cluster3D = 100}; struct m3d {}; //base of module3d::type to allow other modules check for it } + +//exception codes are needed by the user +//typedef boost::error_info solver_failure_type; +struct creation_error : virtual boost::exception {}; + } #endif diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index b21c84ff80b2..a511dbb1e478 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -212,6 +212,8 @@ struct Module3D { void removeGeometry3D(Identifier id); void removeConstraint3D(Identifier id); + using inheriter_base::removeGeometry3D; + using inheriter_base::removeConstraint3D; bool hasGeometry3D(Identifier id); Geom getGeometry3D(Identifier id); diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index b767b4dae343..edc8a65959d0 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -20,12 +20,16 @@ #ifndef GCM_SOLVER_3D_H #define GCM_SOLVER_3D_H -#include - #include "defines.hpp" #include "clustermath.hpp" #include "opendcm/core/sheduler.hpp" #include "opendcm/core/traits.hpp" +#include +#include + +#include +#include +#include namespace dcm { namespace details { @@ -88,6 +92,23 @@ struct SystemSolver : public Job { Eigen::aligned_allocator >& vec); }; + struct DummyScaler { + void operator()() {}; + }; + + struct cycle_dedector:public boost::default_dfs_visitor { + + bool& m_dedected; + cycle_dedector(bool& ed) : m_dedected(ed) { + m_dedected = false; + }; + + template + void back_edge(Edge u, const Graph& g) { + m_dedected = true; + } + }; + SystemSolver(); virtual void execute(Sys& sys); void solveCluster(boost::shared_ptr cluster, Sys& sys); @@ -128,7 +149,7 @@ void MES::recalculate() { std::pair< oiter, oiter > oit = m_cluster->template getObjects(*eit.first); for(; oit.first != oit.second; oit.first++) { if(*oit.first) - (*oit.first)->calculate(Base::Scaling); + (*oit.first)->calculate(Base::Scaling, Base::rot_only); } } }; @@ -185,10 +206,10 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() template void SystemSolver::Rescaler::collectPseudoPoints( - boost::shared_ptr::Cluster> parent, - LocalVertex cluster, - std::vector::Kernel::Vector3, - Eigen::aligned_allocator::Kernel::Vector3> >& vec) { + boost::shared_ptr::Cluster> parent, + LocalVertex cluster, + std::vector::Kernel::Vector3, + Eigen::aligned_allocator::Kernel::Vector3> >& vec) { std::vector > vec2; typedef typename Cluster::template object_iterator c_iter; @@ -233,138 +254,202 @@ void SystemSolver::execute(Sys& sys) { template void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sys) { - //set out and solve all relevant subclusters - typedef typename Cluster::cluster_iterator citer; - std::pair cit = cluster->clusters(); - for(; cit.first != cit.second; cit.first++) { - - boost::shared_ptr c = (*cit.first).second; - if(c->template getClusterProperty() && - c->template getClusterProperty() == details::cluster3D) - solveCluster(c, sys); - } + try { + //set out and solve all relevant subclusters + typedef typename Cluster::cluster_iterator citer; + std::pair cit = cluster->clusters(); + for(; cit.first != cit.second; cit.first++) { - int params=0, constraints=0; - typename Kernel::number_type scale = 1; + boost::shared_ptr c = (*cit.first).second; + if(c->template getClusterProperty() && + c->template getClusterProperty() == details::cluster3D) + solveCluster(c, sys); + } - //get the ammount of parameters and constraint equations we need - typedef typename boost::graph_traits::vertex_iterator iter; - std::pair it = boost::vertices(*cluster); - for(; it.first != it.second; it.first++) { + int params=0, constraints=0; + typename Kernel::number_type scale = 1; + + //get the ammount of parameters and constraint equations we need + typedef typename boost::graph_traits::vertex_iterator iter; + std::pair it = boost::vertices(*cluster); + for(; it.first != it.second; it.first++) { + + //when cluster and not fixed it has trans and rot parameter + if(cluster->isCluster(*it.first)) { + if(!cluster->template getSubclusterProperty(*it.first)) { + params += 6; + } + } else { + params += cluster->template getObject(*it.first)->m_parameterCount; + }; + } - //when cluster and not fixed it has trans and rot parameter - if(cluster->isCluster(*it.first)) { - if(!cluster->template getSubclusterProperty(*it.first)) { - params += 6; - } - } else { - params += cluster->template getObject(*it.first)->m_parameterCount; + //count the equations in the constraints + typedef typename Cluster::template object_iterator ocit; + typedef typename boost::graph_traits::edge_iterator e_iter; + std::pair e_it = boost::edges(*cluster); + for(; e_it.first != e_it.second; e_it.first++) { + std::pair< ocit, ocit > it = cluster->template getObjects(*e_it.first); + for(; it.first != it.second; it.first++) + constraints += (*it.first)->equationCount(); }; - } - - //count the equations in the constraints - typedef typename Cluster::template object_iterator ocit; - typedef typename boost::graph_traits::edge_iterator e_iter; - std::pair e_it = boost::edges(*cluster); - for(; e_it.first != e_it.second; e_it.first++) { - std::pair< ocit, ocit > it = cluster->template getObjects(*e_it.first); - for(; it.first != it.second; it.first++) - constraints += (*it.first)->equationCount(); - }; - if(params <= 0 || constraints <= 0) { - //TODO:throw + if(params <= 0 || constraints <= 0) { + //TODO:throw #ifdef USE_LOGGING - BOOST_LOG(log)<< "Error in system counting: params = " << params << " and constraints = "<isCluster(*it.first)) { - boost::shared_ptr c = cluster->getVertexCluster(*it.first); - if(!cluster->template getSubclusterProperty(*it.first)) - c->template getClusterProperty().finishCalculation(); - else - c->template getClusterProperty().finishFixCalculation(); + } else { - std::vector& vec = c->template getClusterProperty().getGeometry(); - for(typename std::vector::iterator vit = vec.begin(); vit != vec.end(); vit++) - (*vit)->finishCalculation(); + // we have rotations, so let's check our options. first search for cycles, as systems with them + // always need the full solver power + bool has_cycle; + cycle_dedector cd(has_cycle); + //create te needed property map, fill it and run the test + property_map vi_map(cluster); + cluster->initIndexMaps(); + boost::depth_first_search(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map)); + + bool done = false; + if(!has_cycle) { +#ifdef USE_LOGGING + BOOST_LOG(log)<< "non-cyclic system dedected" +#endif + //cool, lets do uncylic. first all rotational constraints with rotational parameters + mes.setAccess(rotation); + mes.setGeneralEquationAccess(false); + //solve can be done without catching exceptions, because this only fails if the system in + //unsolvable + DummyScaler re; + Kernel::solve(mes, re); + + //now let's see if we have to go on with the translations + mes.setAccess(general); + mes.setGeneralEquationAccess(true); + mes.recalculate(); + if(mes.Residual.norm()<1e-6) + done = true; + else { + //let's try translation only + try { + DummyScaler re; + Kernel::solve(mes, re); + done=true; + } catch(boost::exception& e) { + //not successful, so we need brute force + done = false; + } + } + }; + + //not done already? try it the hard way! + if(!done) { +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Full scale solver used" +#endif + Rescaler re(cluster, mes); + re(); + Kernel::solve(mes, re); +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Numbers of rescale: "<template getObject(*it.first); - g->scale(mes.Scaling); - g->finishCalculation(); + //solving is done, now go to all relevant geometries and clusters and write the values back + it = boost::vertices(*cluster); + for(; it.first != it.second; it.first++) { + + if(cluster->isCluster(*it.first)) { + boost::shared_ptr c = cluster->getVertexCluster(*it.first); + if(!cluster->template getSubclusterProperty(*it.first)) + c->template getClusterProperty().finishCalculation(); + else + c->template getClusterProperty().finishFixCalculation(); + + std::vector& vec = c->template getClusterProperty().getGeometry(); + for(typename std::vector::iterator vit = vec.begin(); vit != vec.end(); vit++) + (*vit)->finishCalculation(); + + } else { + Geom g = cluster->template getObject(*it.first); + g->scale(mes.Scaling); + g->finishCalculation(); + } } + //we have solved this cluster + cluster->template setClusterProperty(false); + + } catch(boost::exception& x) { + throw; } - //we have solved this cluster - cluster->template setClusterProperty(false); }; }//details From f26ca75e508af9588103e39f11270b6814aba377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 23 Jun 2013 12:17:11 +0200 Subject: [PATCH 140/664] msvc adaptions --- src/Mod/Assembly/App/opendcm/core.hpp | 9 +++++++++ src/Mod/Assembly/App/opendcm/module3d/solver.hpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index c58af05a6097..f9eacdf67fc0 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -23,6 +23,15 @@ #ifdef _WIN32 //warning about to long decoraded names, won't affect the code correctness #pragma warning( disable : 4503 ) + + //disable boost concept checks, as some of them have alignment problems which bring msvc to an error + //(for example DFSvisitor check in boost::graph::depht_first_search) + //this has no runtime effect as these are only compile time checks + #include + #undef BOOST_CONCEPT_ASSERT + #define BOOST_CONCEPT_ASSERT(Model) + #include + #endif #include "core/geometry.hpp" diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index edc8a65959d0..31823a1099bc 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -402,7 +402,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy DummyScaler re; Kernel::solve(mes, re); done=true; - } catch(boost::exception& e) { + } catch(boost::exception& ) { //not successful, so we need brute force done = false; } @@ -447,7 +447,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //we have solved this cluster cluster->template setClusterProperty(false); - } catch(boost::exception& x) { + } catch(boost::exception& ) { throw; } }; From 9e7b46311376307738fa2df75c91cc738cbd6dc9 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 3 Jul 2013 11:51:27 +0200 Subject: [PATCH 141/664] Allow geometry from other bodies in the same par as external geometry for sketches --- src/Mod/Sketcher/App/SketchObject.cpp | 4 +++- src/Mod/Sketcher/App/SketchObject.h | 3 +++ src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 13 +++++++------ src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 1a0ca7cfed47..25eafc4b8e7f 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -83,6 +83,8 @@ SketchObject::SketchObject() ADD_PROPERTY_TYPE(Constraints, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch constraints"); ADD_PROPERTY_TYPE(ExternalGeometry,(0,0),"Sketch",(App::PropertyType)(App::Prop_None),"Sketch external geometry"); + allowOtherBody = true; + for (std::vector::iterator it=ExternalGeo.begin(); it != ExternalGeo.end(); ++it) if (*it) delete *it; ExternalGeo.clear(); @@ -2713,7 +2715,7 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) { // so far only externals to the support of the sketch and datum features - if (Support.getValue() != Obj) + if (!allowOtherBody && (Support.getValue() != Obj)) if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) && !Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) return -1; diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 931978cf5475..7224417eee65 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -259,6 +259,9 @@ class SketcherExport SketchObject : public Part::Part2DObject /// gets the solved sketch as a reference inline Sketch &getSolvedSketch(void) {return solvedSketch;} + // Flag to allow external geometry from other bodies than the one this sketch belongs to + bool allowOtherBody; + protected: /// get called by the container when a property has changed virtual void onChanged(const App::Property* /*prop*/); diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index fa82d573a0e4..d9cc5bf9103a 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -376,10 +376,11 @@ PyObject* SketchObjectPy::addExternal(PyObject *args) return 0; // get the target object for the external link - App::DocumentObject * Obj = this->getSketchObjectPtr()->getDocument()->getObject(ObjectName); + Sketcher::SketchObject* skObj = this->getSketchObjectPtr(); + App::DocumentObject * Obj = skObj->getDocument()->getObject(ObjectName); if (!Obj) { std::stringstream str; - str << ObjectName << "does not exist in the document"; + str << ObjectName << " does not exist in the document"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } @@ -388,21 +389,21 @@ PyObject* SketchObjectPy::addExternal(PyObject *args) if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { // OK } else if (Obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - if (this->getSketchObjectPtr()->Support.getValue() != Obj) { + if (!skObj->allowOtherBody && (skObj->Support.getValue() != Obj)) { std::stringstream str; - str << ObjectName << "is not supported by this sketch"; + str << ObjectName << " is not supported by this sketch"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } } else if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { std::stringstream str; - str << ObjectName << "must be a Part feature or a datum feature"; + str << ObjectName << " must be a Part feature or a datum feature"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } // add the external - if (this->getSketchObjectPtr()->addExternal(Obj,SubName) < 0) { + if (skObj->addExternal(Obj,SubName) < 0) { std::stringstream str; str << "Not able to add external shape element"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 49b1fca37828..35adb3825a10 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4481,7 +4481,7 @@ namespace SketcherGui { pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) return true; - if (pObj != support) + if (!sketch->allowOtherBody && (pObj != support)) return false; if (!sSubName || sSubName[0] == '\0') return false; From 97fb44ddd50f1806621716673a469ba09d9d0be7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 3 Jul 2013 11:51:58 +0200 Subject: [PATCH 142/664] Detect external geometry that is a circle which becomes a bspline after projection --- src/Mod/Sketcher/App/SketchObject.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 25eafc4b8e7f..7f669ae0df45 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -46,6 +46,9 @@ # include # include # include +# include +# include +# include # include # include # include @@ -3246,6 +3249,30 @@ void SketchObject::rebuildExternalGeometry(void) arc->Construction = true; ExternalGeo.push_back(arc); } + } else if (projCurve.GetType() == GeomAbs_BSplineCurve) { + // Unfortunately, a normal projection of a circle can also give a Bspline + // Split the spline into arcs + GeomConvert_BSplineCurveKnotSplitting bSplineSplitter(projCurve.BSpline(), 2); + //int s = bSplineSplitter.NbSplits(); + if ((curve.GetType() == GeomAbs_Circle) && (bSplineSplitter.NbSplits() == 2)) { + // Result of projection is actually a circle... + TColStd_Array1OfInteger splits(1, 2); + bSplineSplitter.Splitting(splits); + gp_Pnt p1 = projCurve.Value(splits(1)); + gp_Pnt p2 = projCurve.Value(splits(2)); + gp_Pnt p3 = projCurve.Value(0.5 * (splits(1) + splits(2))); + GC_MakeCircle circleMaker(p1, p2, p3); + Handle_Geom_Circle circ = circleMaker.Value(); + Part::GeomCircle* circle = new Part::GeomCircle(); + circle->setRadius(circ->Radius()); + gp_Pnt center = circ->Axis().Location(); + circle->setCenter(Base::Vector3d(center.X(), center.Y(), center.Z())); + + circle->Construction = true; + ExternalGeo.push_back(circle); + } else { + throw Base::Exception("BSpline: Not yet supported geometry for external geometry"); + } } else if (projCurve.GetType() == GeomAbs_Ellipse) { gp_Elips e = projCurve.Ellipse(); From da12aa8805f9dcb13636dbf18e7cb26b733af3f1 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Jul 2013 11:28:29 +0200 Subject: [PATCH 143/664] Allow mapping a sketch to a datum plane --- src/Mod/Sketcher/Gui/Command.cpp | 55 ++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp index d07494049508..1b087cfd0542 100644 --- a/src/Mod/Sketcher/Gui/Command.cpp +++ b/src/Mod/Sketcher/Gui/Command.cpp @@ -373,10 +373,15 @@ void CmdSketcherMapSketch::activated(int iMsg) std::string featName = sel[index]->getNameInDocument(); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter PlaneFilter ("SELECT PartDesign::Plane COUNT 1"); + Gui::SelectionFilter BasePlaneFilter ("SELECT App::Plane COUNT 1"); + + std::string supportString; + Part::Feature *part; + if (FaceFilter.match()) { // get the selected object - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); - Base::Placement ObjectPos = part->Placement.getValue(); + part = static_cast(FaceFilter.Result[0][0].getObject()); const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); if (sub.empty()) { // No assert for wrong user input! @@ -393,14 +398,6 @@ void CmdSketcherMapSketch::activated(int iMsg) return; } - std::vector input = part->getOutList(); - if (std::find(input.begin(), input.end(), sel[index]) != input.end()) { - QMessageBox::warning(Gui::getMainWindow(), - qApp->translate(className(),"Cyclic dependency"), - qApp->translate(className(),"You cannot choose a support object depending on the selected sketch!")); - return; - } - // get the selected sub shape (a Face) const Part::TopoShape &shape = part->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); @@ -421,18 +418,36 @@ void CmdSketcherMapSketch::activated(int iMsg) return; } - std::string supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); - - openCommand("Map a Sketch on Face"); - doCommand(Gui,"App.activeDocument().%s.Support = %s",featName.c_str(),supportString.c_str()); - doCommand(Gui,"App.activeDocument().recompute()"); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",featName.c_str()); - } - else { + supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); + } else if (PlaneFilter.match()) { + part = static_cast(PlaneFilter.Result[0][0].getObject()); + supportString = std::string("(App.activeDocument().") + + part->getNameInDocument() + ", ['front'])"; + } else if (BasePlaneFilter.match()) { + part = NULL; + supportString = std::string("(App.activeDocument().") + + BasePlaneFilter.Result[0][0].getObject()->getNameInDocument() + ", ['front'])"; + } else { QMessageBox::warning(Gui::getMainWindow(), - qApp->translate(className(), "No face selected"), - qApp->translate(className(), "No face was selected to map the sketch to")); + qApp->translate(className(), "No face or plane selected"), + qApp->translate(className(), "No face or datum plane was selected to map the sketch to")); + return; + } + + if (part != NULL) { + std::vector input = part->getOutList(); + if (std::find(input.begin(), input.end(), sel[index]) != input.end()) { + QMessageBox::warning(Gui::getMainWindow(), + qApp->translate(className(),"Cyclic dependency"), + qApp->translate(className(),"You cannot choose a support object depending on the selected sketch!")); + return; + } } + + openCommand("Map a Sketch on Face"); + doCommand(Gui,"App.activeDocument().%s.Support = %s",featName.c_str(),supportString.c_str()); + doCommand(Gui,"App.activeDocument().recompute()"); + doCommand(Gui,"Gui.activeDocument().setEdit('%s')",featName.c_str()); } bool CmdSketcherMapSketch::isActive(void) From c5358ee3072266c2550bf18ca2e95da589d89e09 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Jul 2013 11:29:16 +0200 Subject: [PATCH 144/664] Prevent unknown exception thrown while loading a part --- src/Mod/PartDesign/App/DatumPlane.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index fec4ff5bc0bf..9f95deb7fc99 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -182,10 +182,14 @@ void Plane::onChanged(const App::Property *prop) if (prop == &References) { refTypes.clear(); std::vector refs = References.getValues(); - std::vector refnames = References.getSubValues(); + std::vector refnames = References.getSubValues(); - for (int r = 0; r < refs.size(); r++) + for (int r = 0; r < refs.size(); r++) { + const Part::Feature* ref = static_cast(refs[r]); + if ((ref != NULL) && ref->Shape.getValue().IsNull()) + continue; // This can happen while a document is being restored from a file refTypes.insert(getRefType(refs[r], refnames[r])); + } if (fabs(Angle.getValue()) > Precision::Confusion()) refTypes.insert(ANGLE); From 1e615043cd9965c187061b872c4eb65e26817dad Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Jul 2013 11:30:00 +0200 Subject: [PATCH 145/664] Give user feedback about not being able to extrude UpToFace if sketch is on a datum plane --- src/Mod/PartDesign/App/FeaturePad.cpp | 3 +++ src/Mod/PartDesign/App/FeaturePocket.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 6d6288ed5b9e..638d69828d42 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -157,6 +157,9 @@ App::DocumentObjectExecReturn *Pad::execute(void) TopoDS_Shape prism; std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { + // TODO: Write our own PrismMaker which does not depend on a solid base shape + if (base.IsNull()) + return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch is located on a face"); // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index a06da743e8c1..c7dbfcc1ecfa 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -134,6 +134,9 @@ App::DocumentObjectExecReturn *Pocket::execute(void) std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToFace") { + if (base.IsNull()) + return new App::DocumentObjectExecReturn("Pocket: Extruding up to a face is only possible if the sketch is located on a face"); + // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); From 2d080dd92b4c34b9c9264cf88054b33dc8b8bd70 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Jul 2013 11:31:14 +0200 Subject: [PATCH 146/664] Prevent unnecessary error messages while loading a part --- src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp | 10 ++++++---- src/Mod/PartDesign/Gui/ViewProviderGroove.cpp | 4 +++- src/Mod/PartDesign/Gui/ViewProviderPad.cpp | 4 +++- src/Mod/PartDesign/Gui/ViewProviderPocket.cpp | 4 +++- src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp | 4 +++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp index f5986f053674..3bd3f686323c 100644 --- a/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskBooleanParameters.cpp @@ -350,10 +350,12 @@ bool TaskDlgBooleanParameters::reject() PartDesign::Boolean* obj = static_cast(BooleanView->getObject()); Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc != NULL) { - doc->setShow(obj->BaseFeature.getValue()->getNameInDocument()); - std::vector bodies = obj->Bodies.getValues(); - for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) - doc->setShow((*b)->getNameInDocument()); + if (obj->BaseFeature.getValue() != NULL) { + doc->setShow(obj->BaseFeature.getValue()->getNameInDocument()); + std::vector bodies = obj->Bodies.getValues(); + for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) + doc->setShow((*b)->getNameInDocument()); + } } // roll back the done things diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp index 09b120110ed8..e87c6db1ff8c 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp @@ -54,7 +54,9 @@ ViewProviderGroove::~ViewProviderGroove() std::vector ViewProviderGroove::claimChildren(void)const { std::vector temp; - temp.push_back(static_cast(getObject())->Sketch.getValue()); + App::DocumentObject* sketch = static_cast(getObject())->Sketch.getValue(); + if (sketch != NULL) + temp.push_back(sketch); return temp; } diff --git a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp index 4204ca62dfa5..3c7745a67d77 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPad.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPad.cpp @@ -55,7 +55,9 @@ ViewProviderPad::~ViewProviderPad() std::vector ViewProviderPad::claimChildren(void)const { std::vector temp; - temp.push_back(static_cast(getObject())->Sketch.getValue()); + App::DocumentObject* sketch = static_cast(getObject())->Sketch.getValue(); + if (sketch != NULL) + temp.push_back(sketch); return temp; } diff --git a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp index 23d04a981b50..8a0639d7a314 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp @@ -54,7 +54,9 @@ ViewProviderPocket::~ViewProviderPocket() std::vector ViewProviderPocket::claimChildren(void)const { std::vector temp; - temp.push_back(static_cast(getObject())->Sketch.getValue()); + App::DocumentObject* sketch = static_cast(getObject())->Sketch.getValue(); + if (sketch != NULL) + temp.push_back(sketch); return temp; } diff --git a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp index 05b18d4d91ae..86bcd221cf92 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderRevolution.cpp @@ -54,7 +54,9 @@ ViewProviderRevolution::~ViewProviderRevolution() std::vector ViewProviderRevolution::claimChildren(void)const { std::vector temp; - temp.push_back(static_cast(getObject())->Sketch.getValue()); + App::DocumentObject* sketch = static_cast(getObject())->Sketch.getValue(); + if (sketch != NULL) + temp.push_back(sketch); return temp; } From fa020cf867746acbc987ef2c727fc65d80fcb21b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 7 Jul 2013 11:31:59 +0200 Subject: [PATCH 147/664] Allow selecting geometry from another body inside the same part as a reference --- src/Mod/PartDesign/Gui/FeaturePickDialog.cpp | 2 +- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 18 ++++++++++-------- src/Mod/PartDesign/Gui/ReferenceSelection.h | 8 +++++++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp index 9576b7bbac52..b0b0d0e616ea 100644 --- a/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp +++ b/src/Mod/PartDesign/Gui/FeaturePickDialog.cpp @@ -68,7 +68,7 @@ FeaturePickDialog::FeaturePickDialog(std::vector& objects, connect(ui->radioXRef, SIGNAL(toggled(bool)), this, SLOT(onUpdate(bool))); ui->checkReverse->setChecked(false); - ui->checkOtherBody->setChecked(false); + ui->checkOtherBody->setChecked(true); ui->checkOtherBody->setEnabled(false); // TODO: implement ui->checkOtherFeature->setChecked(false); ui->checkOtherFeature->setEnabled(false); // TODO: implement diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 46f97f293397..7cb465735281 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -60,7 +60,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c // Allow selecting Part::Datum features from the active Body if (ActivePartObject == NULL) return false; - if (!ActivePartObject->hasFeature(pObj)) + if (!allowOtherBody && !ActivePartObject->hasFeature(pObj)) return false; if (plane && (pObj->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId()))) @@ -73,16 +73,18 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c return false; } - // Handle selection of geometry elements - if (support == NULL) - return false; + // Handle selection of geometry elements if (!sSubName || sSubName[0] == '\0') return false; - if (pObj != support) - return false; + if (!allowOtherBody) { + if (support == NULL) + return false; + if (pObj != support) + return false; + } std::string subName(sSubName); if (edge && subName.size() > 4 && subName.substr(0,4) == "Edge") { - const Part::TopoShape &shape = static_cast(support)->Shape.getValue(); + const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Edge& edge = TopoDS::Edge(sh); if (!edge.IsNull()) { @@ -96,7 +98,7 @@ bool ReferenceSelection::allow(App::Document* pDoc, App::DocumentObject* pObj, c } } if (plane && subName.size() > 4 && subName.substr(0,4) == "Face") { - const Part::TopoShape &shape = static_cast(support)->Shape.getValue(); + const Part::TopoShape &shape = static_cast(pObj)->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(subName.c_str()); const TopoDS_Face& face = TopoDS::Face(sh); if (!face.IsNull()) { diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.h b/src/Mod/PartDesign/Gui/ReferenceSelection.h index 46699c9de39f..7c719e4b8755 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.h +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.h @@ -30,14 +30,20 @@ namespace PartDesignGui { class ReferenceSelection : public Gui::SelectionFilterGate { const App::DocumentObject* support; + // If set to true, allow picking edges or planes or both bool edge, plane; + // If set to true, allow only linear edges and planar faces bool planar; + // If set to true, allow picking datum points bool point; + // If set to true, allow picking objects from another body in the same part + bool allowOtherBody; + public: ReferenceSelection(const App::DocumentObject* support_, const bool edge_, const bool plane_, const bool planar_, const bool point_ = false) : Gui::SelectionFilterGate((Gui::SelectionFilter*)0), - support(support_), edge(edge_), plane(plane_), planar(planar_), point(point_) + support(support_), edge(edge_), plane(plane_), planar(planar_), point(point_), allowOtherBody(true) { } /** From f1b5a6044ded3529dfffb2bdff6fb86d4bf0c11d Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 10 Jul 2013 10:15:50 +0200 Subject: [PATCH 148/664] Allow extruding from a datum plane to another face or plane, optionally with an offset --- src/Mod/PartDesign/App/FeaturePad.cpp | 83 +++++++++++++------ src/Mod/PartDesign/App/FeaturePad.h | 1 + src/Mod/PartDesign/App/FeaturePocket.cpp | 3 +- src/Mod/PartDesign/App/FeaturePocket.h | 1 + src/Mod/PartDesign/App/FeatureSketchBased.cpp | 15 +++- src/Mod/PartDesign/App/FeatureSketchBased.h | 3 +- .../PartDesign/Gui/TaskDatumParameters.cpp | 6 +- .../PartDesign/Gui/TaskGrooveParameters.cpp | 2 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 56 ++++++++++++- src/Mod/PartDesign/Gui/TaskPadParameters.h | 2 + src/Mod/PartDesign/Gui/TaskPadParameters.ui | 31 ++++++- .../PartDesign/Gui/TaskPocketParameters.cpp | 45 +++++++++- src/Mod/PartDesign/Gui/TaskPocketParameters.h | 2 + .../PartDesign/Gui/TaskPocketParameters.ui | 22 ++++- .../Gui/TaskRevolutionParameters.cpp | 2 +- .../Gui/TaskSketchBasedParameters.cpp | 2 +- 16 files changed, 232 insertions(+), 44 deletions(-) diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 638d69828d42..90b524c1aa58 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -39,6 +39,9 @@ # include # include # include +# include +# include +# include #endif #include @@ -64,6 +67,7 @@ Pad::Pad() ADD_PROPERTY_TYPE(Length,(100.0),"Pad",App::Prop_None,"Pad length"); ADD_PROPERTY_TYPE(Length2,(100.0),"Pad",App::Prop_None,"P"); ADD_PROPERTY_TYPE(UpToFace,(0),"Pad",App::Prop_None,"Face where pad will end"); + ADD_PROPERTY(Offset,(0.0)); } short Pad::mustExecute() const @@ -155,12 +159,9 @@ App::DocumentObjectExecReturn *Pad::execute(void) sketchshape.Move(invObjLoc); TopoDS_Shape prism; - std::string method(Type.getValueAsString()); + std::string method(Type.getValueAsString()); if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") { - // TODO: Write our own PrismMaker which does not depend on a solid base shape - if (base.IsNull()) - return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch is located on a face"); - // Note: This will return an unlimited planar face if support is a datum plane + // Note: This will return an unlimited planar face if support is a datum plane TopoDS_Face supportface = getSupportFace(); supportface.Move(invObjLoc); @@ -173,27 +174,57 @@ App::DocumentObjectExecReturn *Pad::execute(void) getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } - getUpToFace(upToFace, base, supportface, sketchshape, method, dir); - - // A support object is always required and we need to use BRepFeat_MakePrism - // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid - // because the feature does not add any material. This only happens with the "2" option, though - // Note: It might be possible to pass a shell or a compound containing multiple faces - // as the Until parameter of Perform() - // Note: Multiple independent wires are not supported, we should check for that and - // warn the user - // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results - // Check supportface for limits, otherwise Perform() throws an exception - TopExp_Explorer Ex(supportface,TopAbs_WIRE); - if (!Ex.More()) - supportface = TopoDS_Face(); - BRepFeat_MakePrism PrismMaker; - PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); - PrismMaker.Perform(upToFace); - - if (!PrismMaker.IsDone()) - return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); - prism = PrismMaker.Shape(); + getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue()); + + // TODO: Write our own PrismMaker which does not depend on a solid base shape + if (base.IsNull()) { + // Workaround because BRepFeat_MakePrism requires the base face located on a solid to be able to extrude up to a face + // Handle special case of extruding up to a face or plane parallel to the base face + BRepAdaptor_Surface adapt(upToFace); + if (adapt.GetType() != GeomAbs_Plane) + return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face"); + + double angle = dir.Angle(adapt.Plane().Axis().Direction()); + if (angle > Precision::Confusion()) + return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it"); + + // Project basepoint of sketch onto the UpToFace to determine distance and direction + gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z); + GeomAPI_ProjectPointOnSurf prj(basePoint, adapt.Surface().Surface()); + if (prj.NbPoints() != 1) + return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed to find extrusion direction"); + // Distance + double length = prj.Distance(1) + Offset.getValue(); + if (length < Precision::Confusion()) + return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height"); + + // Direction (the distance is always positive) + gp_Pnt prjP = prj.NearestPoint(); + dir = gp_Dir(gp_Vec(basePoint, prjP)); + dir.Transform(invObjLoc.Transformation()); + + generatePrism(prism, sketchshape, "Length", dir, length, 0.0, false, false); + } else { + // A support object is always required and we need to use BRepFeat_MakePrism + // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid + // because the feature does not add any material. This only happens with the "2" option, though + // Note: It might be possible to pass a shell or a compound containing multiple faces + // as the Until parameter of Perform() + // Note: Multiple independent wires are not supported, we should check for that and + // warn the user + // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results + // Check supportface for limits, otherwise Perform() throws an exception + TopExp_Explorer Ex(supportface,TopAbs_WIRE); + if (!Ex.More()) + supportface = TopoDS_Face(); + BRepFeat_MakePrism PrismMaker; + PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); + PrismMaker.Perform(upToFace); + + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); + prism = PrismMaker.Shape(); + } } else { generatePrism(prism, sketchshape, method, dir, L, L2, Midplane.getValue(), Reversed.getValue()); diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h index 510bf20fe4b5..72b087804ffe 100644 --- a/src/Mod/PartDesign/App/FeaturePad.h +++ b/src/Mod/PartDesign/App/FeaturePad.h @@ -42,6 +42,7 @@ class PartDesignExport Pad : public Additive App::PropertyEnumeration Type; App::PropertyLength Length; App::PropertyLength Length2; + App::PropertyFloat Offset; /** @name methods override feature */ //@{ diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index c7dbfcc1ecfa..43e07b69a6bc 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -62,6 +62,7 @@ Pocket::Pocket() Type.setEnums(TypeEnums); ADD_PROPERTY_TYPE(Length,(100.0),"Pocket",App::Prop_None,"Pocket length"); ADD_PROPERTY_TYPE(UpToFace,(0),"Pocket",App::Prop_None,"Face where pocket will end"); + ADD_PROPERTY(Offset,(0.0)); } short Pocket::mustExecute() const @@ -150,7 +151,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void) getUpToFaceFromLinkSub(upToFace, UpToFace); upToFace.Move(invObjLoc); } - getUpToFace(upToFace, base, supportface, sketchshape, method, dir); + getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue()); // Special treatment because often the created stand-alone prism is invalid (empty) because // BRepFeat_MakePrism(..., 2, 1) is buggy diff --git a/src/Mod/PartDesign/App/FeaturePocket.h b/src/Mod/PartDesign/App/FeaturePocket.h index 57b298e77e7c..250bbca80c7f 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.h +++ b/src/Mod/PartDesign/App/FeaturePocket.h @@ -39,6 +39,7 @@ class PartDesignExport Pocket : public Subtractive App::PropertyEnumeration Type; App::PropertyLength Length; + App::PropertyFloat Offset; /** @name methods override feature */ //@{ diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 4f0d74c21f84..13365014637e 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -494,7 +494,8 @@ void SketchBased::getUpToFace(TopoDS_Face& upToFace, const TopoDS_Face& supportface, const TopoDS_Shape& sketchshape, const std::string& method, - const gp_Dir& dir) + const gp_Dir& dir, + const double offset) { if ((method == "UpToLast") || (method == "UpToFirst")) { // Check for valid support object @@ -564,6 +565,18 @@ void SketchBased::getUpToFace(TopoDS_Face& upToFace, if (distSS.Value() < Precision::Confusion()) throw Base::Exception("SketchBased: Up to face: Must not intersect sketch!"); + // Move the face in the extrusion direction + // TODO: For non-planar faces, we could consider offsetting the surface + if (fabs(offset) > Precision::Confusion()) { + if (adapt2.GetType() == GeomAbs_Plane) { + gp_Trsf mov; + mov.SetTranslation(offset * gp_Vec(dir)); + TopLoc_Location loc(mov); + upToFace.Move(loc); + } else { + throw Base::Exception("SketchBased: Up to Face: Offset not supported yet for non-planar faces"); + } + } } void SketchBased::generatePrism(TopoDS_Shape& prism, diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 5336b218cd0e..aff24dac18c7 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -101,7 +101,8 @@ class PartDesignExport SketchBased : public PartDesign::Feature const TopoDS_Face& supportface, const TopoDS_Shape& sketchshape, const std::string& method, - const gp_Dir& dir); + const gp_Dir& dir, + const double offset); /** * Generate a linear prism * It will be a stand-alone solid created with BRepPrimAPI_MakePrism diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 6e75ea845544..1c0876310fa0 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -68,13 +68,13 @@ const QString makeRefString(const App::DocumentObject* obj, const std::string& s if ((sub.size() > 4) && (sub.substr(0,4) == "Face")) { int subId = std::atoi(&sub[4]); - return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Face") + QString::number(subId); + return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Face") + QString::number(subId); } else if ((sub.size() > 4) && (sub.substr(0,4) == "Edge")) { int subId = std::atoi(&sub[4]); - return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Edge") + QString::number(subId); + return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Edge") + QString::number(subId); } if ((sub.size() > 6) && (sub.substr(0,6) == "Vertex")) { int subId = std::atoi(&sub[6]); - return QString::fromAscii(obj->getNameInDocument()) + QObject::tr(":Vertex") + QString::number(subId); + return QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Vertex") + QString::number(subId); } return QObject::tr("No reference selected"); diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp index 27011e7ad375..c3a7a530c7a3 100644 --- a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -331,7 +331,7 @@ void TaskGrooveParameters::apply() ui->grooveAngle->apply(); std::vector sub; App::DocumentObject* obj; - parameter->getReferenceAxis(obj, sub); + getReferenceAxis(obj, sub); std::string axis = getPythonStr(obj, sub); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 529e553d4d63..61df266fd1c8 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -72,6 +72,8 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg this, SLOT(onReversed(bool))); connect(ui->lengthEdit2, SIGNAL(valueChanged(double)), this, SLOT(onLength2Changed(double))); + connect(ui->spinOffset, SIGNAL(valueChanged(double)), + this, SLOT(onOffsetChanged(double))); connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), this, SLOT(onModeChanged(int))); connect(ui->buttonFace, SIGNAL(clicked()), @@ -86,6 +88,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg // Temporarily prevent unnecessary feature recomputes ui->lengthEdit->blockSignals(true); ui->lengthEdit2->blockSignals(true); + ui->spinOffset->blockSignals(true); ui->checkBoxMidplane->blockSignals(true); ui->checkBoxReversed->blockSignals(true); ui->buttonFace->blockSignals(true); @@ -102,6 +105,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg bool midplane = pcPad->Midplane.getValue(); bool reversed = pcPad->Reversed.getValue(); Base::Quantity l2 = pcPad->Length2.getQuantityValue(); + double off = pcPad->Offset.getValue(); int index = pcPad->Type.getValue(); // must extract value here, clear() kills it! App::DocumentObject* obj = pcPad->UpToFace.getValue(); std::vector subStrings = pcPad->UpToFace.getSubValues(); @@ -120,11 +124,13 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg ui->lengthEdit2->setMinimum(0); ui->lengthEdit2->setMaximum(INT_MAX); ui->lengthEdit2->setValue(l2); + ui->spinOffset->setMaximum(INT_MAX); + ui->spinOffset->setMinimum(-INT_MAX); + ui->spinOffset->setValue(off); // Bind input fields to properties ui->lengthEdit->bind(pcPad->Length); ui->lengthEdit2->bind(pcPad->Length2); - ui->checkBoxMidplane->setChecked(midplane); // According to bug #0000521 the reversed option // shouldn't be de-activated if the pad has a support face @@ -132,7 +138,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg if ((obj != NULL) && PartDesign::Feature::isDatum(obj)) ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); else if (faceId >= 0) - ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + tr("Face") + QString::number(faceId)); else ui->lineFaceName->setText(tr("No face selected")); @@ -148,6 +154,7 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg // activate and de-activate dialog elements as appropriate ui->lengthEdit->blockSignals(false); ui->lengthEdit2->blockSignals(false); + ui->spinOffset->blockSignals(false); ui->checkBoxMidplane->blockSignals(false); ui->checkBoxReversed->blockSignals(false); ui->buttonFace->blockSignals(false); @@ -167,8 +174,13 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,bool newObj, QWidg void TaskPadParameters::updateUI(int index) { if (index == 0) { // dimension + ui->lengthEdit->setVisible(true); ui->lengthEdit->setEnabled(true); ui->lengthEdit->selectNumber(); + ui->labelLength->setVisible(true); + ui->spinOffset->setVisible(false); + ui->spinOffset->setEnabled(false); + ui->labelOffset->setVisible(false); // Make sure that the spin box has the focus to get key events // Calling setFocus() directly doesn't work because the spin box is not // yet visible. @@ -176,22 +188,38 @@ void TaskPadParameters::updateUI(int index) ui->checkBoxMidplane->setEnabled(true); // Reverse only makes sense if Midplane is not true ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); + ui->labelLength2->setVisible(false); + ui->lengthEdit2->setVisible(false); ui->lengthEdit2->setEnabled(false); ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); onButtonFace(false); } else if (index == 1 || index == 2) { // up to first/last + ui->lengthEdit->setVisible(false); ui->lengthEdit->setEnabled(false); + ui->labelLength->setVisible(false); + ui->spinOffset->setVisible(true); + ui->spinOffset->setEnabled(true); + ui->labelOffset->setVisible(true); ui->checkBoxMidplane->setEnabled(false); ui->checkBoxReversed->setEnabled(true); + ui->labelLength2->setVisible(false); + ui->lengthEdit2->setVisible(false); ui->lengthEdit2->setEnabled(false); ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); onButtonFace(false); } else if (index == 3) { // up to face + ui->lengthEdit->setVisible(false); ui->lengthEdit->setEnabled(false); + ui->labelLength->setVisible(false); + ui->spinOffset->setVisible(true); + ui->spinOffset->setEnabled(true); + ui->labelOffset->setVisible(true); ui->checkBoxMidplane->setEnabled(false); ui->checkBoxReversed->setEnabled(false); + ui->labelLength2->setVisible(false); + ui->lengthEdit2->setVisible(false); ui->lengthEdit2->setEnabled(false); ui->buttonFace->setEnabled(true); ui->lineFaceName->setEnabled(true); @@ -201,10 +229,17 @@ void TaskPadParameters::updateUI(int index) onButtonFace(true); } else { // two dimensions ui->lengthEdit->setEnabled(true); + ui->lengthEdit->setVisible(true); ui->lengthEdit->selectNumber(); QMetaObject::invokeMethod(ui->lengthEdit, "setFocus", Qt::QueuedConnection); + ui->labelLength->setVisible(true); + ui->spinOffset->setVisible(false); + ui->spinOffset->setEnabled(false); + ui->labelOffset->setVisible(false); ui->checkBoxMidplane->setEnabled(false); ui->checkBoxReversed->setEnabled(false); + ui->labelLength2->setVisible(true); + ui->lengthEdit2->setVisible(true); ui->lengthEdit2->setEnabled(true); ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); @@ -268,6 +303,13 @@ void TaskPadParameters::onLength2Changed(double len) recomputeFeature(); } +void TaskPadParameters::onOffsetChanged(double len) +{ + PartDesign::Pad* pcPad = static_cast(vp->getObject()); + pcPad->Offset.setValue(len); + recomputeFeature(); +} + void TaskPadParameters::onModeChanged(int index) { PartDesign::Pad* pcPad = static_cast(vp->getObject()); @@ -322,6 +364,11 @@ double TaskPadParameters::getLength2(void) const return ui->lengthEdit2->value().getValue(); } +double TaskPadParameters::getOffset(void) const +{ + return ui->spinOffset->value(); +} + int TaskPadParameters::getMode(void) const { return ui->changeMode->currentIndex(); @@ -346,6 +393,7 @@ void TaskPadParameters::changeEvent(QEvent *e) if (e->type() == QEvent::LanguageChange) { ui->lengthEdit->blockSignals(true); ui->lengthEdit2->blockSignals(true); + ui->spinOffset->blockSignals(true); ui->lineFaceName->blockSignals(true); ui->changeMode->blockSignals(true); int index = ui->changeMode->currentIndex(); @@ -369,10 +417,11 @@ void TaskPadParameters::changeEvent(QEvent *e) ui->lineFaceName->setPlaceholderText(tr("No face selected")); #endif ui->lineFaceName->setText(ok ? - parts[0] + tr(":Face") + QString::number(faceId) : + parts[0] + QString::fromAscii(":") + tr("Face") + QString::number(faceId) : QString()); ui->lengthEdit->blockSignals(false); ui->lengthEdit2->blockSignals(false); + ui->spinOffset->blockSignals(false); ui->lineFaceName->blockSignals(false); ui->changeMode->blockSignals(false); } @@ -404,6 +453,7 @@ void TaskPadParameters::apply() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = %s", name.c_str(), facename.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", cname); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!vp->getObject()->isValid()) throw Base::Exception(vp->getObject()->getStatusString()); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index 575032319cfd..60bfe013676a 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -53,6 +53,7 @@ class TaskPadParameters : public TaskSketchBasedParameters TaskPadParameters(ViewProviderPad *PadView,bool newObj=false,QWidget *parent = 0); ~TaskPadParameters(); + double getOffset(void) const; void saveHistory(void); void apply(); @@ -61,6 +62,7 @@ private Q_SLOTS: void onMidplane(bool); void onReversed(bool); void onLength2Changed(double); + void onOffsetChanged(double); void onModeChanged(int); void onButtonFace(const bool pressed = true); void onFaceName(const QString& text); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.ui b/src/Mod/PartDesign/Gui/TaskPadParameters.ui index aade56ebe364..ee876fe8bc3e 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.ui @@ -37,7 +37,7 @@ - + Length @@ -61,6 +61,33 @@ + + + + + + Offset + + + + + + + 0.000000000000000 + + + 999999999.000000000000000 + + + 5.000000000000000 + + + 0.000000000000000 + + + + + @@ -81,7 +108,7 @@ - + 2nd length diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index c0cc3008de98..023735e2b1a5 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -67,6 +67,8 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge connect(ui->pocketLength, SIGNAL(valueChanged(double)), this, SLOT(onLengthChanged(double))); + connect(ui->spinOffset, SIGNAL(valueChanged(double)), + this, SLOT(onOffsetChanged(double))); connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), this, SLOT(onMidplaneChanged(bool))); connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), @@ -84,6 +86,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge // Temporarily prevent unnecessary feature recomputes ui->pocketLength->blockSignals(true); + ui->spinOffset->blockSignals(true); ui->checkBoxMidplane->blockSignals(true); ui->checkBoxReversed->blockSignals(true); ui->buttonFace->blockSignals(true); @@ -93,6 +96,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge // Get the feature data PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); double l = pcPocket->Length.getValue(); + double off = pcPocket->Offset.getValue(); bool midplane = pcPocket->Midplane.getValue(); bool reversed = pcPocket->Reversed.getValue(); int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it! @@ -110,12 +114,15 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->pocketLength->setMinimum(0); ui->pocketLength->setMaximum(INT_MAX); ui->pocketLength->setValue(l); + ui->spinOffset->setMinimum(-INT_MAX); + ui->spinOffset->setMaximum(INT_MAX); + ui->spinOffset->setValue(off); ui->checkBoxMidplane->setChecked(midplane); ui->checkBoxReversed->setChecked(reversed); if ((obj != NULL) && PartDesign::Feature::isDatum(obj)) ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument())); else if (faceId >= 0) - ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + tr("Face") + + ui->lineFaceName->setText(QString::fromAscii(obj->getNameInDocument()) + QString::fromAscii(":") + tr("Face") + QString::number(faceId)); else ui->lineFaceName->setText(tr("No face selected")); @@ -131,6 +138,7 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge ui->pocketLength->bind(pcPocket->Length); ui->pocketLength->blockSignals(false); + ui->spinOffset->blockSignals(false); ui->checkBoxMidplane->blockSignals(false); ui->checkBoxReversed->blockSignals(false); ui->buttonFace->blockSignals(false); @@ -157,9 +165,13 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge void TaskPocketParameters::updateUI(int index) { if (index == 0) { // Only this option requires a numeric value // Dimension + ui->pocketLength->setVisible(true); ui->pocketLength->setEnabled(true); ui->pocketLength->selectAll(); QMetaObject::invokeMethod(ui->pocketLength, "setFocus", Qt::QueuedConnection); + ui->spinOffset->setVisible(false); + ui->spinOffset->setEnabled(false); + ui->spinOffset->setEnabled(false); ui->checkBoxMidplane->setEnabled(true); // Reverse only makes sense if Midplane is not true ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of dimension @@ -169,21 +181,35 @@ void TaskPocketParameters::updateUI(int index) } else if (index == 1) { // Through all ui->checkBoxMidplane->setEnabled(true); ui->checkBoxReversed->setEnabled(!ui->checkBoxMidplane->isChecked()); // Will flip direction of through all + ui->pocketLength->setVisible(false); ui->pocketLength->setEnabled(false); + ui->spinOffset->setVisible(false); + ui->spinOffset->setVisible(false); + ui->spinOffset->setEnabled(false); ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); onButtonFace(false); } else if (index == 2) { // Neither value nor face required // To First ui->pocketLength->setEnabled(false); + ui->pocketLength->setVisible(false); ui->checkBoxMidplane->setEnabled(false); // Can't have a midplane to a single face ui->checkBoxReversed->setEnabled(false); // Will change the direction it seeks for its first face? // Doesnt work so is currently disabled. Fix probably lies // somwhere in IF block on line 125 of FeaturePocket.cpp + ui->labelLength->setVisible(false); + ui->spinOffset->setVisible(true); + ui->spinOffset->setEnabled(true); + ui->labelOffset->setVisible(true); ui->buttonFace->setEnabled(false); ui->lineFaceName->setEnabled(false); onButtonFace(false); } else if (index == 3) { // Only this option requires to select a face // Up to face ui->pocketLength->setEnabled(false); + ui->pocketLength->setVisible(false); + ui->labelLength->setVisible(false); + ui->spinOffset->setVisible(true); + ui->spinOffset->setEnabled(true); + ui->labelOffset->setVisible(true); ui->checkBoxMidplane->setEnabled(false); ui->checkBoxReversed->setEnabled(false); // No need for reverse since user-chosen face will dtermine direction ui->buttonFace->setEnabled(true); @@ -228,6 +254,13 @@ void TaskPocketParameters::onLengthChanged(double len) recomputeFeature(); } +void TaskPocketParameters::onOffsetChanged(double len) +{ + PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); + pcPocket->Offset.setValue(len); + recomputeFeature(); +} + void TaskPocketParameters::onMidplaneChanged(bool on) { PartDesign::Pocket* pcPocket = static_cast(vp->getObject()); @@ -297,6 +330,11 @@ double TaskPocketParameters::getLength(void) const return ui->pocketLength->value().getValue(); } +double TaskPocketParameters::getOffset(void) const +{ + return ui->spinOffset->value(); +} + bool TaskPocketParameters::getReversed(void) const { return ui->checkBoxReversed->isChecked(); @@ -325,6 +363,7 @@ void TaskPocketParameters::changeEvent(QEvent *e) TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { ui->pocketLength->blockSignals(true); + ui->spinOffset->blockSignals(true); ui->lineFaceName->blockSignals(true); ui->changeMode->blockSignals(true); int index = ui->changeMode->currentIndex(); @@ -344,9 +383,10 @@ void TaskPocketParameters::changeEvent(QEvent *e) faceId = upToFace.remove(0,4).toInt(&ok); } ui->lineFaceName->setText(ok ? - parts[0] + tr(":Face") + QString::number(faceId) : + parts[0] + QString::fromAscii(":") + tr("Face") + QString::number(faceId) : tr("No face selected")); ui->pocketLength->blockSignals(false); + ui->spinOffset->blockSignals(false); ui->lineFaceName->blockSignals(false); ui->changeMode->blockSignals(false); } @@ -366,6 +406,7 @@ void TaskPocketParameters::apply() } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.UpToFace = None", name.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i", name.c_str(), getReversed()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f", name.c_str(), getOffset()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!vp->getObject()->isValid()) throw Base::Exception(vp->getObject()->getStatusString()); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index 77cd96d8ec13..53359d2ed77c 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -53,12 +53,14 @@ class TaskPocketParameters : public TaskSketchBasedParameters TaskPocketParameters(ViewProviderPocket *PocketView,QWidget *parent = 0); ~TaskPocketParameters(); + double getOffset(void) const; bool getReversed(void) const; QByteArray getFaceName(void) const; void apply(); private Q_SLOTS: void onLengthChanged(double); + void onOffsetChanged(double); void onMidplaneChanged(bool); void onReversedChanged(bool); void onModeChanged(int); diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui index 5a1f41c07702..82f8a7f347b5 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui @@ -7,7 +7,7 @@ 0 0 241 - 188 + 233 @@ -49,7 +49,7 @@ - + Length @@ -67,6 +67,24 @@ + + + + + + Offset + + + + + + + 999999999.000000000000000 + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 339592b9eaeb..910f3cd96e76 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -332,7 +332,7 @@ void TaskRevolutionParameters::apply() ui->revolveAngle->apply(); std::vector sub; App::DocumentObject* obj; - parameter->getReferenceAxis(obj, sub); + getReferenceAxis(obj, sub); std::string axis = getPythonStr(obj, sub); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.ReferenceAxis = %s",name.c_str(),axis.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(), getMidplane() ? 1 : 0); diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 2cfb7f030c91..08097599e07f 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -79,7 +79,7 @@ const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChan refStr = QString::fromAscii(selObj->getNameInDocument()); } else { int faceId = std::atoi(&subname[4]); - refStr = QString::fromAscii(selObj->getNameInDocument()) + QObject::tr(":Face") + QString::number(faceId); + refStr = QString::fromAscii(selObj->getNameInDocument()) + QString::fromAscii(":") + QObject::tr("Face") + QString::number(faceId); } std::vector upToFaces(1,subname); From e735cf7c3af850f7c6fb966d6b2a3fe9c31c77b8 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 14 Jul 2013 08:59:49 +0200 Subject: [PATCH 149/664] Allow moving features between bodies from context menu of tree view --- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 3 + src/Mod/PartDesign/Gui/Command.cpp | 83 +++++++++++++++++++ src/Mod/PartDesign/Gui/Workbench.cpp | 3 +- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 13365014637e..b5f3633b6ec5 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -1020,6 +1020,9 @@ void SketchBased::getAxis(const App::DocumentObject *pcReferenceAxis, const std: Base::Vector3d& base, Base::Vector3d& dir) { dir = Base::Vector3d(0,0,0); // If unchanged signals that no valid axis was found + if (pcReferenceAxis == NULL) + return; + Part::Part2DObject* sketch = getVerifiedSketch(); Base::Placement SketchPlm = sketch->Placement.getValue(); Base::Vector3d SketchPos = SketchPlm.getPosition(); diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index df36ff97cda5..462cb344745e 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -300,6 +300,88 @@ bool CmdPartDesignDuplicateSelection::isActive(void) return false; } +//=========================================================================== +// PartDesign_MoveFeature +//=========================================================================== + +DEF_STD_CMD_A(CmdPartDesignMoveFeature); + +CmdPartDesignMoveFeature::CmdPartDesignMoveFeature() + :Command("PartDesign_MoveFeature") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Move object to other body"); + sToolTipText = QT_TR_NOOP("Moves the selected object to another body"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = ""; +} + +void CmdPartDesignMoveFeature::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + + // Create a list of all bodies in this part + std::vector bodies = getDocument()->getObjectsOfType(Part::BodyBase::getClassTypeId()); + + // Ask user to select the target body + bool ok; + QStringList items; + for (std::vector::iterator it = bodies.begin(); it != bodies.end(); ++it) + items.push_back(QString::fromUtf8((*it)->Label.getValue())); + QString text = QInputDialog::getItem(Gui::getMainWindow(), + qApp->translate(className(), "Select body"), + qApp->translate(className(), "Select a body from the list"), + items, 0, false, &ok); + if (!ok) return; + int index = items.indexOf(text); + + PartDesign::Body* target = static_cast(bodies[index]); + + openCommand("Move an object"); + + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + // Find body of this feature + Part::BodyBase* source = PartDesign::Body::findBodyOf(*f); + if (source == target) continue; + bool featureIsTip = (source->Tip.getValue() == *f); + + // Remove from source body + doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + source->getNameInDocument(), (*f)->getNameInDocument()); + // Add to target body (always at the Tip) + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + target->getNameInDocument(), (*f)->getNameInDocument()); + + // Adjust visibility of features + if (PartDesign::Body::isSolidFeature(*f)) { + // If we removed the tip of the source body, make the new tip visible + if (featureIsTip) { + App::DocumentObject* prevSolidFeature = source->getPrevSolidFeature(); + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + } + + // Hide old tip and show new tip (the moved feature) of the target body + App::DocumentObject* prevSolidFeature = target->getPrevSolidFeature(); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); + } + } +} + +bool CmdPartDesignMoveFeature::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // PartDesign_Datum //=========================================================================== @@ -1690,6 +1772,7 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); rcCmdMgr.addCommand(new CmdPartDesignDuplicateSelection()); + rcCmdMgr.addCommand(new CmdPartDesignMoveFeature()); rcCmdMgr.addCommand(new CmdPartDesignPlane()); rcCmdMgr.addCommand(new CmdPartDesignLine()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 665cda863d61..5e104fe55add 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -280,7 +280,8 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) - *item << "PartDesign_MoveTip"; + *item << "PartDesign_MoveTip" + << "PartDesign_MoveFeature"; } } From 38ab82a94d484605d93d2a33aab2afa93a6f1157 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 15 Jul 2013 07:40:03 +0200 Subject: [PATCH 150/664] Allow external references from other body but not from same body outside the support --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 35adb3825a10..b60ef85f99e6 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include "ViewProviderSketch.h" #include "DrawSketchHandler.h" @@ -4481,8 +4482,17 @@ namespace SketcherGui { pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) return true; - if (!sketch->allowOtherBody && (pObj != support)) - return false; + if (pObj != support) { + // Selection outside of support not allowed + if (!sketch->allowOtherBody) + return false; + + // Selection outside of support allowed if from other body + // TODO: There is still a possibility of creating cyclic references here + if (Part::BodyBase::findBodyOf(pObj) == Part::BodyBase::findBodyOf(support)) + return false; + } + if (!sSubName || sSubName[0] == '\0') return false; std::string element(sSubName); From 4d674831d3b975d20ea46bc5c2b03ef2992cf360 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 15 Jul 2013 21:44:24 +0200 Subject: [PATCH 151/664] Fix broken placement of boolean operations --- src/Mod/PartDesign/App/FeatureBoolean.cpp | 53 ++++++++++++++++------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureBoolean.cpp b/src/Mod/PartDesign/App/FeatureBoolean.cpp index 978ef0bea966..998d49e6477b 100644 --- a/src/Mod/PartDesign/App/FeatureBoolean.cpp +++ b/src/Mod/PartDesign/App/FeatureBoolean.cpp @@ -27,6 +27,11 @@ # include # include # include +# include +# include +# include +# include +# include #endif #include "Body.h" @@ -60,40 +65,58 @@ short Boolean::mustExecute() const App::DocumentObjectExecReturn *Boolean::execute(void) { - // Get the base shape to operate on - Part::TopoShape baseTopShape; + // Check the parameters + const Part::Feature* baseFeature; try { - baseTopShape = getBaseTopoShape(); + baseFeature = getBaseObject(); } catch (const Base::Exception&) { - return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid base shape"); + return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid BaseFeature"); } std::vector bodies = Bodies.getValues(); if (bodies.empty()) return App::DocumentObject::StdReturn; + // Get the base shape to operate on + Part::TopoShape baseTopShape = baseFeature->Shape.getShape(); + if (baseTopShape._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid base shape"); + + // Position this feature by the base feature + this->Placement.setValue(baseFeature->Placement.getValue()); + TopLoc_Location invObjLoc = this->getLocation().Inverted(); + // create an untransformed copy of the base shape Part::TopoShape baseShape(baseTopShape); baseShape.setTransform(Base::Matrix4D()); TopoDS_Shape result = baseShape._Shape; - // Position this feature by the first body - const Part::Feature* baseFeature; - try { - baseFeature = getBaseObject(); - } catch (const Base::Exception&) { - return new App::DocumentObjectExecReturn("Cannot do boolean operation with invalid BaseFeature"); - } - this->Placement.setValue(baseFeature->Placement.getValue()); - // Get the operation type std::string type = Type.getValueAsString(); for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { - // Extract the body shape + // Extract the body shape. Its important to get the actual feature that provides the last solid in the body + // so that the placement will be right PartDesign::Body* body = static_cast(*b); - TopoDS_Shape shape = body->Shape.getValue(); + Part::Feature* tipSolid = static_cast(body->getPrevSolidFeature()); + if (tipSolid == NULL) + continue; + TopoDS_Shape shape = tipSolid->Shape.getValue(); + + // Move the shape to the location of the base shape + Base::Placement pl = body->Placement.getValue(); + // TODO: Why is Feature::getLocation() protected? + Base::Rotation rot(pl.getRotation()); + Base::Vector3d axis; + double angle; + rot.getValue(axis, angle); + gp_Trsf trf; + trf.SetRotation(gp_Ax1(gp_Pnt(), gp_Dir(axis.x, axis.y, axis.z)), angle); + trf.SetTranslationPart(gp_Vec(pl.getPosition().x,pl.getPosition().y,pl.getPosition().z)); + TopLoc_Location bLoc(trf); + shape.Move(invObjLoc.Multiplied(bLoc)); + TopoDS_Shape boolOp; if (type == "Fuse") { From 7174a259f0e4f9086dfce0f2f455aeed92f55afd Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 16 Jul 2013 20:53:31 +0200 Subject: [PATCH 152/664] Two minor fixes --- src/Mod/PartDesign/Gui/Command.cpp | 2 ++ src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 462cb344745e..50a5abd03040 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -357,6 +357,8 @@ void CmdPartDesignMoveFeature::activated(int iMsg) // Add to target body (always at the Tip) doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", target->getNameInDocument(), (*f)->getNameInDocument()); + // Recompute to update the shape + doCommand(Gui,"App.activeDocument().recompute()"); // Adjust visibility of features if (PartDesign::Body::isSolidFeature(*f)) { diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 468ca2249419..bae6159f2f59 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -4563,13 +4563,13 @@ void ViewProviderSketch::unsetEdit(int ModNum) delete edit; edit = 0; - } - try { - // and update the sketch - getSketchObject()->getDocument()->recompute(); - } - catch (...) { + try { + // and update the sketch + getSketchObject()->getDocument()->recompute(); + } + catch (...) { + } } // clear the selection and set the new/edited sketch(convenience) From b2dd70e6356e7f803d80fd1743ec81df6e765b5b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 26 Jul 2013 15:56:23 +0200 Subject: [PATCH 153/664] PartDesign Body migration: Handle sketch planes offset from base planes --- src/Mod/PartDesign/Gui/Workbench.cpp | 83 +++++++++++++++++++++------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 5e104fe55add..be4fe5801907 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -28,6 +28,9 @@ # include # include # include +# include +# include +# include #endif #include "Workbench.h" @@ -106,6 +109,7 @@ void switchToDocument(const App::Document* doc) // This adds both the base planes and the body // Note: In the following code we rely on the first body always having the name "Body"! Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); + activeBody = static_cast(doc->getObject("Body")); // Assign all document features to the new body std::string modelString = ""; @@ -138,6 +142,9 @@ void switchToDocument(const App::Document* doc) } // Re-route all sketches without support to the base planes + Gui::Command::openCommand("Migrate part to Body feature"); + std::vector::const_iterator prevf; + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { Sketcher::SketchObject* sketch = static_cast(*f); @@ -146,38 +153,72 @@ void switchToDocument(const App::Document* doc) continue; // Sketch is on a face of a solid Base::Placement plm = sketch->Placement.getValue(); Base::Vector3d pnt = plm.getPosition(); - // Currently we only handle positions that correspond to the base planes - if (pnt.Length() > Precision::Confusion()) { - QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), - QObject::tr("Please edit ") + QString::fromAscii(sketch->getNameInDocument()) + - QObject::tr("and redefine it to use a Base or Datum plane as the sketch plane.")); - break; // avoid repeating this message for every sketch - } + + // Currently we only handle positions that are parallel to the base planes Base::Rotation rot = plm.getRotation(); Base::Vector3d SketchVector(0,0,1); rot.multVec(SketchVector, SketchVector); std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front"; if (side == "back") SketchVector *= -1.0; + int index; + + if (SketchVector == Base::Vector3d(0,0,1)) + index = 0; + else if (SketchVector == Base::Vector3d(0,1,0)) + index = 1; + else if (SketchVector == Base::Vector3d(1,0,0)) + index = 2; + else { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), + QObject::tr("Please edit '") + QString::fromAscii(sketch->getNameInDocument()) + + QObject::tr("' and redefine it to use a Base or Datum plane as the sketch plane.")); + continue; + } - if (SketchVector == Base::Vector3d(0,0,1)) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", - sketch->getNameInDocument(), BaseplaneNames[0], side.c_str()); - } else if (SketchVector == Base::Vector3d(0,1,0)) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", - sketch->getNameInDocument(), BaseplaneNames[1], side.c_str()); - } else if (SketchVector == Base::Vector3d(1,0,0)) { + // Find the normal distance from origin to the sketch plane + gp_Pln pln(gp_Pnt (pnt.x, pnt.y, pnt.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); + double offset = pln.Distance(gp_Pnt(0,0,0)); + + if (fabs(offset) < Precision::Confusion()) { + // One of the base planes Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", - sketch->getNameInDocument(), BaseplaneNames[2], side.c_str()); + sketch->getNameInDocument(), BaseplaneNames[index], side.c_str()); } else { - QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), - QObject::tr("Please edit") + QString::fromAscii(sketch->getNameInDocument()) + - QObject::tr("and redefine it to use a Base or Datum plane as the sketch plane.")); - break; // avoid repeating this message for every sketch + // Offset to base plane + // Find out which direction we need to offset + double a = SketchVector.GetAngle(pnt); + if ((a < -M_PI_2) || (a > M_PI_2)) + offset *= -1.0; + + // Insert a new datum plane before the sketch + App::DocumentObject* oldTip = ActivePartObject->Tip.getValue(); + Gui::Selection().clearSelection(); + if (f != features.begin()) + Gui::Selection().addSelection((*prevf)->getDocument()->getName(), (*prevf)->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + + std::string Datum = (*f)->getDocument()->getUniqueObjectName("DatumPlane"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",Datum.c_str()); + QString refStr = QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(BaseplaneNames[index]) + + QString::fromAscii(",'')]"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.References = %s",Datum.c_str(), refStr.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Offset = %f",Datum.c_str(), offset); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + activeBody->getNameInDocument(), Datum.c_str()); + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", + sketch->getNameInDocument(), Datum.c_str(), side.c_str()); + + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); } } - } - activeBody = static_cast(doc->getObject("Body")); + prevf = f; + } } else { // Find active body for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { From 36a00f45b61462ac2267476381359ecbd6f7614a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 26 Jul 2013 15:56:56 +0200 Subject: [PATCH 154/664] PartDesign Body migration: Fix migration of MultiTransform sub-features --- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 9 +++++++++ src/Mod/PartDesign/Gui/Workbench.cpp | 14 ++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index e28d867d3fd6..318884ae2ab4 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,14 @@ std::vector ViewProviderBody::claimChildren(void)const if (sketch != NULL) OutSet.insert(sketch); } + + // Transformations of a MultiTransform feature get claimed under the feature, too + if ((*it)->isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) { + std::vector trfs = static_cast(*it)->Transformations.getValues(); + for (std::vector::const_iterator t = trfs.begin(); t != trfs.end(); t++) + if ((*t) != NULL) + OutSet.insert(*t); + } } // remove the otherwise handled objects, preserving their order so the order in the TreeWidget is correct diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index be4fe5801907..dcf40ed32715 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -141,6 +142,19 @@ void switchToDocument(const App::Document* doc) } } + // Set BaseFeature property to NULL for members of MultiTransform + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + if ((*f)->getTypeId().isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) { + std::vector trfs = static_cast(*f)->Transformations.getValues(); + for (std::vector::const_iterator t = trfs.begin(); t != trfs.end(); t++) { + if ((*t) != NULL) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = None", + (*t)->getNameInDocument()); + } + } + } + } + // Re-route all sketches without support to the base planes Gui::Command::openCommand("Migrate part to Body feature"); std::vector::const_iterator prevf; From 6a02b5849f6670cbcde121bb01005c19546f483c Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 28 Jul 2013 21:32:25 +0200 Subject: [PATCH 155/664] Body: Transformed Features inside a MultiTransform are not considered to be solid features --- src/Mod/PartDesign/App/Body.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index b09b95158bff..01f317ab4afe 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -32,6 +32,7 @@ #include "Body.h" #include "BodyPy.h" #include "FeatureSketchBased.h" +#include "FeatureTransformed.h" #include "DatumPoint.h" #include "DatumLine.h" #include "DatumPlane.h" @@ -191,7 +192,15 @@ const bool Body::isSolidFeature(const App::DocumentObject* f) if (f == NULL) return false; - return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())); + if (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { + // Transformed Features inside a MultiTransform are not solid features + // They can be recognized because the Originals property is empty (it is contained + // in the MultiTransform instead) + if (f->getTypeId().isDerivedFrom(PartDesign::Transformed::getClassTypeId()) && + static_cast(f)->Originals.getValues().empty()) + return false; + return true; + } } const bool Body::isAllowed(const App::DocumentObject* f) From b8dc8181bc9a63a5e7cefa44d6dafee043e07bb5 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 28 Jul 2013 21:34:25 +0200 Subject: [PATCH 156/664] Added menu item to move a feature in the tree inside a body --- src/Mod/PartDesign/Gui/Command.cpp | 77 ++++++++++++++++++++++++++++ src/Mod/PartDesign/Gui/Workbench.cpp | 3 +- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 50a5abd03040..47cbfecd96e5 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -384,6 +384,82 @@ bool CmdPartDesignMoveFeature::isActive(void) return false; } +DEF_STD_CMD_A(CmdPartDesignMoveFeatureInTree); + +CmdPartDesignMoveFeatureInTree::CmdPartDesignMoveFeatureInTree() + :Command("PartDesign_MoveFeatureInTree") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Move object after other object"); + sToolTipText = QT_TR_NOOP("Moves the selected object and insert it after another object"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = ""; +} + +void CmdPartDesignMoveFeatureInTree::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + + // Create a list of all features in this body + std::vector model = pcActiveBody->Model.getValues(); + + // Ask user to select the target feature + bool ok; + QStringList items; + for (std::vector::iterator it = model.begin(); it != model.end(); ++it) + items.push_back(QString::fromUtf8((*it)->Label.getValue())); + QString text = QInputDialog::getItem(Gui::getMainWindow(), + qApp->translate(className(), "Select feature"), + qApp->translate(className(), "Select a feature from the list"), + items, 0, false, &ok); + if (!ok) return; + int index = items.indexOf(text); + PartDesign::Feature* target = static_cast(model[index]); + + openCommand("Move an object inside tree"); + + // Set insert point at the selected feature + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + Gui::Selection().clearSelection(); + if (target != NULL) + Gui::Selection().addSelection(target->getDocument()->getName(), target->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + if (*f == target) continue; + + // Remove and re-insert the feature from the Body + // Note: If the tip was moved then the new tip will be at the moved position, that is, at the same + // feature as before! + doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + } + + // Recompute to update the shape + doCommand(Gui,"App.activeDocument().recompute()"); + // Set insert point where it was before + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); +} + +bool CmdPartDesignMoveFeatureInTree::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // PartDesign_Datum //=========================================================================== @@ -1775,6 +1851,7 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignDuplicateSelection()); rcCmdMgr.addCommand(new CmdPartDesignMoveFeature()); + rcCmdMgr.addCommand(new CmdPartDesignMoveFeatureInTree()); rcCmdMgr.addCommand(new CmdPartDesignPlane()); rcCmdMgr.addCommand(new CmdPartDesignLine()); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index dcf40ed32715..54bd2a70f3c6 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -336,7 +336,8 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) *item << "PartDesign_MoveTip" - << "PartDesign_MoveFeature"; + << "PartDesign_MoveFeature" + << "PartDesign_MoveFeatureInTree"; } } From f3fbf6f28551e44fee20e001f38375966025b9ba Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 28 Jul 2013 21:34:55 +0200 Subject: [PATCH 157/664] Improved migration of PartDesign parts to the new Body structure --- src/Mod/PartDesign/Gui/Workbench.cpp | 269 ++++++++++++++++----------- 1 file changed, 156 insertions(+), 113 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 54bd2a70f3c6..1849d87f4661 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -97,142 +97,185 @@ Workbench::~Workbench() void switchToDocument(const App::Document* doc) { - if (doc == NULL) return; + if (doc == NULL) return; PartDesign::Body* activeBody = NULL; std::vector bodies = doc->getObjectsOfType(PartDesign::Body::getClassTypeId()); // Is there a body feature in this document? if (bodies.empty()) { - // Get the objects now, before adding the Body and the base planes - std::vector features = doc->getObjects(); - - // This adds both the base planes and the body - // Note: In the following code we rely on the first body always having the name "Body"! - Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); - activeBody = static_cast(doc->getObject("Body")); + Gui::Command::openCommand("Migrate part to Body feature"); - // Assign all document features to the new body - std::string modelString = ""; + // Get the objects now, before adding the Body and the base planes + std::vector features = doc->getObjects(); - for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + // Assign all non-PartDesign features to a new group + bool groupCreated = false; + for (std::vector::iterator f = features.begin(); f != features.end(); ) { if ((*f)->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || (*f)->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) { - modelString += std::string(modelString.empty() ? "" : ",") + "App.ActiveDocument." + (*f)->getNameInDocument(); + ++f; + } else { + if (!groupCreated) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", + QObject::tr("NonBodyFeatures").toStdString().c_str()); + groupCreated = true; + } + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().NonBodyFeatures.addObject(App.activeDocument().getObject('%s'))", + (*f)->getNameInDocument()); + f = features.erase(f); } } - - if (!modelString.empty()) { - modelString = std::string("[") + modelString + "]"; - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Body.Model = %s", modelString.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().Body.Tip = App.activeDocument().%s", features.back()->getNameInDocument()); + // TODO: Fold the group (is that possible through the Python interface?) + + // Try to find the root(s) of the model tree (the features that depend on no other feature) + // Note: We assume a linear graph, except for MultiTransform features + std::vector roots; + for (std::vector::iterator f = features.begin(); f != features.end(); f++) { + // Note: The dependency list always contains at least the object itself + std::vector ftemp; + ftemp.push_back(*f); + if (doc->getDependencyList(ftemp).size() == 1) + roots.push_back(*f); } - // Initialize the BaseFeature property of all PartDesign solid features - App::DocumentObject* baseFeature = NULL; - for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { - if (PartDesign::Body::isSolidFeature(*f)) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = %s", - (*f)->getNameInDocument(), - baseFeature == NULL ? - "None" : - (std::string("App.activeDocument().") + baseFeature->getNameInDocument()).c_str()); - - baseFeature = *f; + // Always create at least the first body, even if the document is empty + // This adds both the base planes and the body + Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); + activeBody = PartDesignGui::ActivePartObject; + + + // Create one Body for every root and put the appropriate features into it + for (std::vector::iterator r = roots.begin(); r != roots.end(); r++) { + if (r != roots.begin()) { + Gui::Command::runCommand(Gui::Command::Doc, "FreeCADGui.runCommand('PartDesign_Body')"); + activeBody = PartDesignGui::ActivePartObject; } - } - // Set BaseFeature property to NULL for members of MultiTransform - for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { - if ((*f)->getTypeId().isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) { - std::vector trfs = static_cast(*f)->Transformations.getValues(); - for (std::vector::const_iterator t = trfs.begin(); t != trfs.end(); t++) { - if ((*t) != NULL) { - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = None", - (*t)->getNameInDocument()); + std::set inList; + inList.insert(*r); // start with the root feature + std::vector bodyFeatures; + bodyFeatures.push_back(*r); + std::string modelString = ""; + do { + std::set newInList; + for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) { + std::vector iL = doc->getInList(*o); + newInList.insert(iL.begin(), iL.end()); + } + inList = newInList; // TODO: Memory leak? Unnecessary copying? + for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) { + std::vector::iterator feat = std::find(features.begin(), features.end(), *o); + if (feat != features.end()) { + bodyFeatures.push_back(*o); + modelString += std::string(modelString.empty() ? "" : ",") + "App.ActiveDocument." + (*o)->getNameInDocument(); + features.erase(feat); + } else { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Non-linear tree"), + QObject::tr("Please look at '") + QString::fromAscii((*o)->getNameInDocument()) + + QObject::tr("' and make sure that the migration result is what you would expect.")); } } + } while (!inList.empty()); + + if (!modelString.empty()) { + modelString = std::string("[") + modelString + "]"; + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Model = %s", activeBody->getNameInDocument(), modelString.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", activeBody->getNameInDocument(), bodyFeatures.back()->getNameInDocument()); } - } - // Re-route all sketches without support to the base planes - Gui::Command::openCommand("Migrate part to Body feature"); - std::vector::const_iterator prevf; - - for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { - if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { - Sketcher::SketchObject* sketch = static_cast(*f); - App::DocumentObject* support = sketch->Support.getValue(); - if (support != NULL) - continue; // Sketch is on a face of a solid - Base::Placement plm = sketch->Placement.getValue(); - Base::Vector3d pnt = plm.getPosition(); - - // Currently we only handle positions that are parallel to the base planes - Base::Rotation rot = plm.getRotation(); - Base::Vector3d SketchVector(0,0,1); - rot.multVec(SketchVector, SketchVector); - std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front"; - if (side == "back") SketchVector *= -1.0; - int index; - - if (SketchVector == Base::Vector3d(0,0,1)) - index = 0; - else if (SketchVector == Base::Vector3d(0,1,0)) - index = 1; - else if (SketchVector == Base::Vector3d(1,0,0)) - index = 2; - else { - QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), - QObject::tr("Please edit '") + QString::fromAscii(sketch->getNameInDocument()) + - QObject::tr("' and redefine it to use a Base or Datum plane as the sketch plane.")); - continue; + // Initialize the BaseFeature property of all PartDesign solid features + App::DocumentObject* baseFeature = NULL; + for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) { + if (PartDesign::Body::isSolidFeature(*f)) { + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.BaseFeature = %s", + (*f)->getNameInDocument(), + baseFeature == NULL ? + "None" : + (std::string("App.activeDocument().") + baseFeature->getNameInDocument()).c_str()); + + baseFeature = *f; } + } - // Find the normal distance from origin to the sketch plane - gp_Pln pln(gp_Pnt (pnt.x, pnt.y, pnt.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); - double offset = pln.Distance(gp_Pnt(0,0,0)); - - if (fabs(offset) < Precision::Confusion()) { - // One of the base planes - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", - sketch->getNameInDocument(), BaseplaneNames[index], side.c_str()); - } else { - // Offset to base plane - // Find out which direction we need to offset - double a = SketchVector.GetAngle(pnt); - if ((a < -M_PI_2) || (a > M_PI_2)) - offset *= -1.0; - - // Insert a new datum plane before the sketch - App::DocumentObject* oldTip = ActivePartObject->Tip.getValue(); - Gui::Selection().clearSelection(); - if (f != features.begin()) - Gui::Selection().addSelection((*prevf)->getDocument()->getName(), (*prevf)->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); - - std::string Datum = (*f)->getDocument()->getUniqueObjectName("DatumPlane"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",Datum.c_str()); - QString refStr = QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(BaseplaneNames[index]) + - QString::fromAscii(",'')]"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.References = %s",Datum.c_str(), refStr.toStdString().c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Offset = %f",Datum.c_str(), offset); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", - activeBody->getNameInDocument(), Datum.c_str()); - Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", - sketch->getNameInDocument(), Datum.c_str(), side.c_str()); - - Gui::Selection().clearSelection(); - Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); - Gui::Selection().clearSelection(); + // Re-route all sketches without support to the base planes + std::vector::const_iterator prevf; + + for (std::vector::const_iterator f = bodyFeatures.begin(); f != bodyFeatures.end(); f++) { + if ((*f)->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { + Sketcher::SketchObject* sketch = static_cast(*f); + App::DocumentObject* support = sketch->Support.getValue(); + if (support != NULL) + continue; // Sketch is on a face of a solid + Base::Placement plm = sketch->Placement.getValue(); + Base::Vector3d pnt = plm.getPosition(); + + // Currently we only handle positions that are parallel to the base planes + Base::Rotation rot = plm.getRotation(); + Base::Vector3d SketchVector(0,0,1); + rot.multVec(SketchVector, SketchVector); + std::string side = (SketchVector.x + SketchVector.y + SketchVector.z) < 0.0 ? "back" : "front"; + if (side == "back") SketchVector *= -1.0; + int index; + + if (SketchVector == Base::Vector3d(0,0,1)) + index = 0; + else if (SketchVector == Base::Vector3d(0,1,0)) + index = 1; + else if (SketchVector == Base::Vector3d(1,0,0)) + index = 2; + else { + QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), + QObject::tr("Please edit '") + QString::fromAscii(sketch->getNameInDocument()) + + QObject::tr("' and redefine it to use a Base or Datum plane as the sketch plane.")); + continue; + } + + // Find the normal distance from origin to the sketch plane + gp_Pln pln(gp_Pnt (pnt.x, pnt.y, pnt.z), gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z)); + double offset = pln.Distance(gp_Pnt(0,0,0)); + + if (fabs(offset) < Precision::Confusion()) { + // One of the base planes + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", + sketch->getNameInDocument(), BaseplaneNames[index], side.c_str()); + } else { + // Offset to base plane + // Find out which direction we need to offset + double a = SketchVector.GetAngle(pnt); + if ((a < -M_PI_2) || (a > M_PI_2)) + offset *= -1.0; + + // Insert a new datum plane before the sketch + App::DocumentObject* oldTip = activeBody->Tip.getValue(); + Gui::Selection().clearSelection(); + if (f != bodyFeatures.begin()) + Gui::Selection().addSelection(doc->getName(), (*prevf)->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + + std::string Datum = doc->getUniqueObjectName("DatumPlane"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",Datum.c_str()); + QString refStr = QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(BaseplaneNames[index]) + + QString::fromAscii(",'')]"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.References = %s",Datum.c_str(), refStr.toStdString().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Offset = %f",Datum.c_str(), offset); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + activeBody->getNameInDocument(), Datum.c_str()); + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", + sketch->getNameInDocument(), Datum.c_str(), side.c_str()); + + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(doc->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); + } } - } - prevf = f; - } + prevf = f; + } + } } else { // Find active body for (std::vector::const_iterator b = bodies.begin(); b != bodies.end(); b++) { @@ -279,7 +322,7 @@ void switchToDocument(const App::Document* doc) activeBody = static_cast(bodies.front()); if (activeBody != NULL) { - Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); + //Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); } else { QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Could not create body"), From d550506f2801690f344d4a4b86bdb6426f3cb9d2 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 29 Jul 2013 21:11:44 +0200 Subject: [PATCH 158/664] Fix handling of MultiTransform features when migrating to Body --- src/Mod/PartDesign/App/Body.cpp | 18 ++++++++++++------ src/Mod/PartDesign/App/Body.h | 3 +++ src/Mod/PartDesign/Gui/Workbench.cpp | 12 +++++++++++- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 01f317ab4afe..7b33bc7fb762 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -187,6 +187,17 @@ const bool Body::isAfterTip(const App::DocumentObject *f) { return (it > tip); } +const bool Body::isMemberOfMultiTransform(const App::DocumentObject* f) +{ + if (f == NULL) + return false; + + // This can be recognized because the Originals property is empty (it is contained + // in the MultiTransform instead) + return (f->getTypeId().isDerivedFrom(PartDesign::Transformed::getClassTypeId()) && + static_cast(f)->Originals.getValues().empty()); +} + const bool Body::isSolidFeature(const App::DocumentObject* f) { if (f == NULL) @@ -194,12 +205,7 @@ const bool Body::isSolidFeature(const App::DocumentObject* f) if (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { // Transformed Features inside a MultiTransform are not solid features - // They can be recognized because the Originals property is empty (it is contained - // in the MultiTransform instead) - if (f->getTypeId().isDerivedFrom(PartDesign::Transformed::getClassTypeId()) && - static_cast(f)->Originals.getValues().empty()) - return false; - return true; + return !isMemberOfMultiTransform(f); } } diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 345a903082b5..0d3d0e1ee3f2 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -84,6 +84,9 @@ class PartDesignExport Body : public Part::BodyBase /// Remove the feature from the body void removeFeature(App::DocumentObject* feature); + /// Return true if the given feature is member of a MultiTransform feature + static const bool isMemberOfMultiTransform(const App::DocumentObject* f); + /** * Return true if the given feature is a solid feature allowed in a Body. Currently this is only valid * for features derived from PartDesign::Feature diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 1849d87f4661..def22f8c13bd 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -160,6 +160,9 @@ void switchToDocument(const App::Document* doc) do { std::set newInList; for (std::set::const_iterator o = inList.begin(); o != inList.end(); o++) { + // Omit members of a MultiTransform from the inList, to avoid migration errors + if (PartDesign::Body::isMemberOfMultiTransform(*o)) + continue; std::vector iL = doc->getInList(*o); newInList.insert(iL.begin(), iL.end()); } @@ -181,7 +184,14 @@ void switchToDocument(const App::Document* doc) if (!modelString.empty()) { modelString = std::string("[") + modelString + "]"; Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Model = %s", activeBody->getNameInDocument(), modelString.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", activeBody->getNameInDocument(), bodyFeatures.back()->getNameInDocument()); + // Set the Tip, but not to a member of a MultiTransform! + for (std::vector::const_reverse_iterator f = bodyFeatures.rbegin(); f != bodyFeatures.rend(); f++) { + if (PartDesign::Body::isMemberOfMultiTransform(*f)) + continue; + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s", + activeBody->getNameInDocument(), (*f)->getNameInDocument()); + break; + } } // Initialize the BaseFeature property of all PartDesign solid features From 61430e67e1353a9ee5e771a18fe14bb7a1587e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Fri, 2 Aug 2013 17:39:49 +0000 Subject: [PATCH 159/664] put constraint selection message in dialog window --- .../Assembly/App/opendcm/module3d/solver.hpp | 8 ++--- src/Mod/Assembly/Gui/CommandConstraints.cpp | 33 ++++++++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index 31823a1099bc..d2ce5d1d984f 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -382,10 +382,10 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy #ifdef USE_LOGGING BOOST_LOG(log)<< "non-cyclic system dedected" #endif - //cool, lets do uncylic. first all rotational constraints with rotational parameters - mes.setAccess(rotation); + //cool, lets do uncylic. first all rotational constraints with rotational parameters + mes.setAccess(rotation); mes.setGeneralEquationAccess(false); - //solve can be done without catching exceptions, because this only fails if the system in + //solve can be done without catching exceptions, because this only fails if the system is //unsolvable DummyScaler re; Kernel::solve(mes, re); @@ -414,7 +414,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy #ifdef USE_LOGGING BOOST_LOG(log)<< "Full scale solver used" #endif - Rescaler re(cluster, mes); + Rescaler re(cluster, mes); re(); Kernel::solve(mes, re); #ifdef USE_LOGGING diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index 198dbff5a949..d415c9d38aba 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -125,14 +125,16 @@ void CmdAssemblyConstraintDistance::activated(int iMsg) std::vector objs = Gui::Selection().getSelectionEx(); if(objs.size() != 2) { - Base::Console().Message("you must select two geometries on two diffrent parts\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select two geometries on two different parts")); return; }; Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); if(!part1 || !part2) { - Base::Console().Message("The selected objects need to belong to the active assembly\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; @@ -183,7 +185,8 @@ void CmdAssemblyConstraintFix::activated(int iMsg) std::vector objs = Gui::Selection().getSelectionEx(); if(objs.size() != 1) { - Base::Console().Message("you must select one part\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select one part only")); return; }; @@ -232,14 +235,16 @@ void CmdAssemblyConstraintAngle::activated(int iMsg) std::vector objs = Gui::Selection().getSelectionEx(); if(objs.size() != 2) { - Base::Console().Message("you must select two geometries on two diffrent parts\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select two geometries on two different parts")); return; }; Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); if(!part1 || !part2) { - Base::Console().Message("The selected objects need to belong to the active assembly\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; @@ -292,14 +297,16 @@ void CmdAssemblyConstraintOrientation::activated(int iMsg) std::vector objs = Gui::Selection().getSelectionEx(); if(objs.size() != 2) { - Base::Console().Message("you must select two geometries on two diffrent parts\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select two geometries on two different parts")); return; }; Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); if(!part1 || !part2) { - Base::Console().Message("The selected objects need to belong to the active assembly\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; @@ -354,14 +361,16 @@ void CmdAssemblyConstraintCoincidence::activated(int iMsg) std::vector objs = Gui::Selection().getSelectionEx(); if(objs.size() != 2) { - Base::Console().Message("you must select two geometries on two diffrent parts\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select two geometries on two different parts")); return; }; Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); if(!part1 || !part2) { - Base::Console().Message("The selected objects need to belong to the active assembly\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; @@ -416,14 +425,16 @@ void CmdAssemblyConstraintAlignment::activated(int iMsg) std::vector objs = Gui::Selection().getSelectionEx(); if(objs.size() != 2) { - Base::Console().Message("you must select two geometries on two diffrent parts\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select two geometries on two different parts")); return; }; Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); if(!part1 || !part2) { - Base::Console().Message("The selected objects need to belong to the active assembly\n"); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; From 46700422fd7f1280217c9f405bc96d672a4ed174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Fri, 2 Aug 2013 18:37:19 +0000 Subject: [PATCH 160/664] make constaints and group not greyed in tree --- src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h | 3 +++ src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h | 2 ++ src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h | 2 ++ src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h | 2 ++ src/Mod/Assembly/Gui/ViewProviderConstraintFix.h | 2 ++ src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp | 2 +- src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h | 4 +++- src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h | 2 ++ 8 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h index 38d2fadde932..459206fd546e 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h @@ -34,6 +34,9 @@ class AssemblyGuiExport ViewProviderConstraintAlignment : public Gui::ViewProvid public: ViewProviderConstraintAlignment(); + + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h index cd68cbe8c47e..ed1097f4d15f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h @@ -35,6 +35,8 @@ class AssemblyGuiExport ViewProviderConstraintAngle : public Gui::ViewProviderDo public: ViewProviderConstraintAngle(); + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h index a4cbacd734b4..dee6ab0a259e 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h @@ -35,6 +35,8 @@ class AssemblyGuiExport ViewProviderConstraintCoincidence : public Gui::ViewProv public: ViewProviderConstraintCoincidence(); + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h index 1c1c1c364465..9fbff5ba2aa2 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h @@ -35,6 +35,8 @@ class AssemblyGuiExport ViewProviderConstraintDistance : public Gui::ViewProvide public: ViewProviderConstraintDistance(); + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h index d4fabcc0c2e0..66a1e158e8b3 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h @@ -35,6 +35,8 @@ class AssemblyGuiExport ViewProviderConstraintFix : public Gui::ViewProviderDocu public: ViewProviderConstraintFix(); + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp index a03662c2dd91..b8a7c2d4a8f1 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.cpp @@ -57,7 +57,7 @@ void ViewProviderConstraintGroup::attach(App::DocumentObject *pcFeat) // putting all together with the switch -// addDisplayMaskMode(getChildRoot(), "Main"); + //addDisplayMaskMode(getChildRoot(), "Main"); } void ViewProviderConstraintGroup::setDisplayMode(const char* ModeName) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h index dabcb2af9587..2adb572ffb24 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintGroup.h @@ -46,8 +46,10 @@ class AssemblyGuiExport ViewProviderConstraintGroup : public Gui::ViewProviderDo virtual std::vector getDisplayModes(void) const; virtual std::vector claimChildren(void)const; - virtual std::vector claimChildren3D(void)const; + + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h index 1109d5d89be5..4276a46df636 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h @@ -35,6 +35,8 @@ class AssemblyGuiExport ViewProviderConstraintOrientation : public Gui::ViewProv public: ViewProviderConstraintOrientation(); + /// checks whether the view provider is visible or not in tree + virtual bool isShow(void) const {return true;}; }; }; From e0efc30893dac6bbd10862fb282def3dd8432242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sat, 3 Aug 2013 13:40:13 +0000 Subject: [PATCH 161/664] add visualisation to the constraints --- src/Mod/Assembly/Gui/CMakeLists.txt | 2 + .../Assembly/Gui/ViewProviderConstraint.cpp | 343 ++++++++++++++++++ src/Mod/Assembly/Gui/ViewProviderConstraint.h | 100 +++++ .../Gui/ViewProviderConstraintAlignment.h | 8 +- .../Gui/ViewProviderConstraintAngle.h | 6 +- .../Gui/ViewProviderConstraintCoincidence.h | 6 +- .../Gui/ViewProviderConstraintDistance.h | 5 +- .../Gui/ViewProviderConstraintFix.cpp | 21 ++ .../Assembly/Gui/ViewProviderConstraintFix.h | 8 +- .../Gui/ViewProviderConstraintOrientation.h | 6 +- 10 files changed, 480 insertions(+), 25 deletions(-) create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraint.cpp create mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraint.h diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 4779c12e2894..837b78fa94f8 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -40,6 +40,8 @@ SET(AssemblyGuiViewProvider_SRCS ViewProviderPart.h ViewProviderAssembly.cpp ViewProviderAssembly.h + ViewProviderConstraint.cpp + ViewProviderConstraint.h ViewProviderConstraintGroup.cpp ViewProviderConstraintGroup.h ViewProviderConstraintFix.cpp diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp new file mode 100644 index 000000000000..d5c49cf62c5f --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -0,0 +1,343 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 "ViewProviderConstraint.h" +#include "Mod/Assembly/App/Constraint.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace AssemblyGui; + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintInternal, PartGui::ViewProviderPart) + +ViewProviderConstraintInternal::ViewProviderConstraintInternal() +{ + //constraint entiti color + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 421075455UL); // dark grey (25,25,25) + float r, g, b; + r = ((scol >> 24) & 0xff) / 255.0; + g = ((scol >> 16) & 0xff) / 255.0; + b = ((scol >> 8) & 0xff) / 255.0; + + long unsigned ccol = hGrp->GetUnsigned("FullyConstrainedColor", 421075455UL); + float r2, g2, b2; + r2 = ((ccol >> 24) & 0xff) / 255.0; + g2 = ((ccol >> 16) & 0xff) / 255.0; + b2 = ((ccol >> 8) & 0xff) / 255.0; + + + int lwidth = hGrp->GetInt("DefaultShapeLineWidth", 2) + 1; + App::Material mat; + mat.ambientColor.set(0.2f, 0.2f, 0.2f); + mat.diffuseColor.set(r2, g2, b2); + mat.specularColor.set(0.0f, 0.0f, 0.0f); + mat.emissiveColor.set(0.0f, 0.0f, 0.0f); + mat.shininess = 1.0f; + mat.transparency = 0.5f; + LineMaterial.setValue(mat); + PointMaterial.setValue(mat); + LineColor.setValue(mat.diffuseColor); + PointColor.setValue(mat.diffuseColor); + mat.diffuseColor.set(r, g, b); + DiffuseColor.setValue(mat.diffuseColor); + LineWidth.setValue(lwidth); + PointSize.setValue(lwidth); + + Transparency.setValue(50); +}; + +void ViewProviderConstraintInternal::updateVis(const TopoDS_Shape& shape) +{ + updateVisual(shape); +}; + +void ViewProviderConstraintInternal::updatePlacement(const Base::Placement& p) +{ + float q0 = (float)p.getRotation().getValue()[0]; + float q1 = (float)p.getRotation().getValue()[1]; + float q2 = (float)p.getRotation().getValue()[2]; + float q3 = (float)p.getRotation().getValue()[3]; + float px = (float)p.getPosition().x; + float py = (float)p.getPosition().y; + float pz = (float)p.getPosition().z; + pcTransform->rotation.setValue(q0, q1, q2, q3); + pcTransform->translation.setValue(px, py, pz); + pcTransform->center.setValue(0.0f, 0.0f, 0.0f); +} + +void ViewProviderConstraintInternal::switch_node(bool onoff) +{ + if(onoff) + pcModeSwitch->whichChild = 0; + else + pcModeSwitch->whichChild = -1; +} + + +PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraint, PartGui::ViewProviderPart) + +ViewProviderConstraint::ViewProviderConstraint() +{ + Selectable.setValue(false); + + //constraint entiti color + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 421075455UL); // dark grey (25,25,25) + float r, g, b; + r = ((scol >> 24) & 0xff) / 255.0; + g = ((scol >> 16) & 0xff) / 255.0; + b = ((scol >> 8) & 0xff) / 255.0; + + long unsigned ccol = hGrp->GetUnsigned("FullyConstrainedColor", 421075455UL); + float r2, g2, b2; + r2 = ((ccol >> 24) & 0xff) / 255.0; + g2 = ((ccol >> 16) & 0xff) / 255.0; + b2 = ((ccol >> 8) & 0xff) / 255.0; + + + int lwidth = hGrp->GetInt("DefaultShapeLineWidth", 2) + 1; + App::Material mat; + mat.ambientColor.set(0.2f, 0.2f, 0.2f); + mat.diffuseColor.set(r2, g2, b2); + mat.specularColor.set(0.0f, 0.0f, 0.0f); + mat.emissiveColor.set(0.0f, 0.0f, 0.0f); + mat.shininess = 1.0f; + mat.transparency = 0.5f; + LineMaterial.setValue(mat); + PointMaterial.setValue(mat); + LineColor.setValue(mat.diffuseColor); + PointColor.setValue(mat.diffuseColor); + mat.diffuseColor.set(r, g, b); + DiffuseColor.setValue(mat.diffuseColor); + LineWidth.setValue(lwidth); + PointSize.setValue(lwidth); + + Transparency.setValue(50); +} + +bool ViewProviderConstraint::isShow() const +{ + return Visibility.getValue(); +} + + +void ViewProviderConstraint::attach(App::DocumentObject* pcFeat) +{ + SoAnnotation* m_anno1 = new SoAnnotation; + SoAnnotation* m_anno2 = new SoAnnotation; + + //call parent attach method for normal processing of one visual path + ViewProviderPart::attach(pcFeat); + //bring a annotation node before the normal view mode (others are not used) + m_anno1->addChild(pcModeSwitch->getChild(0)); + pcModeSwitch->replaceChild(0, m_anno1); + + //now also attach a second visual path to the root for our second constraint element + internal_vp.attach(pcFeat); + pcRoot->addChild(m_anno2); + m_anno2->addChild(internal_vp.getRoot()); + + internal_vp.setDisplayMM("Flat Lines"); +} + + +void ViewProviderConstraint::updateData(const App::Property* prop) +{ + Base::Console().Message("update: %s\n", prop->getName()); + + if(Visibility.getValue() && m_selected) { + + draw(); + } + + Gui::ViewProviderGeometryObject::updateData(prop); + internal_vp.Gui::ViewProviderGeometryObject::updateData(prop); +} + +void ViewProviderConstraint::onChanged(const App::Property* prop) +{ + + Base::Console().Message("changed: %s, selected: %i\n", prop->getName(), m_selected); + + // parent expects the app object to be part::feature, but it isn't. so we have to avoid + // the visability prop as this results in accessing of the part::feature and would crash + if(prop == &Visibility) { + if(Visibility.getValue() && m_selected) { + internal_vp.show(); + draw(); + } + else + internal_vp.hide(); + + ViewProviderGeometryObject::onChanged(prop); + internal_vp.onChGO(prop); + } + else { + ViewProviderPart::onChanged(prop); + internal_vp.onChPa(prop); + } +} + +void ViewProviderConstraint::draw() +{ + + TopoDS_Shape s1 = getConstraintShape(1); + updateVisual(s1); + + TopoDS_Shape s2 = getConstraintShape(2); + internal_vp.updateVis(s2); + + App::DocumentObject* obj1 = dynamic_cast(pcObject)->First.getValue(); + + if(!obj1) + return; + + Assembly::ItemPart* part1 = static_cast(obj1); + + if(!part1) + return; + + //the internal draw algorithm removes all locations. but we have this subshape extracted + //from a complex one, therefore it's translation is not respected in the parts rotation + //and if it gets cut away the geometry will be at wrong position + TopLoc_Location l1 = s1.Location(); + gp_XYZ tr1 = l1.Transformation().TranslationPart(); + Base::Placement p1(Base::Vector3d(tr1.X(), tr1.Y(), tr1.Z()), Base::Rotation()); + p1 = part1->Placement.getValue() * p1; + + float q0 = (float)p1.getRotation().getValue()[0]; + float q1 = (float)p1.getRotation().getValue()[1]; + float q2 = (float)p1.getRotation().getValue()[2]; + float q3 = (float)p1.getRotation().getValue()[3]; + float px = (float)p1.getPosition().x; + float py = (float)p1.getPosition().y; + float pz = (float)p1.getPosition().z; + pcTransform->rotation.setValue(q0, q1, q2, q3); + pcTransform->translation.setValue(px, py, pz); + pcTransform->center.setValue(0.0f, 0.0f, 0.0f); + + //Second part + //*********** + App::DocumentObject* obj2 = dynamic_cast(pcObject)->Second.getValue(); + + if(!obj2) + return; + + //here it's a bit more involved, as the coind tree structure let's the first transform node + //transform the second part too. + Assembly::ItemPart* part2 = static_cast(obj2); + + if(!part2) + return; + + //the internal draw algorithm removes all locations. but we have this subshape extracted + //from a complex one, therefore it's shape internal translation is not respected in the parts rotation + //and if it gets cut away the geometry will be at wrong position + TopLoc_Location l2 = s2.Location(); + gp_XYZ tr2 = l2.Transformation().TranslationPart(); + Base::Placement p2(Base::Vector3d(tr2.X(), tr2.Y(), tr2.Z()), Base::Rotation()); + + p2 = p1.inverse() * (part2->Placement.getValue() * p2); + internal_vp.updatePlacement(p2); +} + +void ViewProviderConstraint::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if(Gui::Selection().isSelected(pcObject) && Visibility.getValue()) { + m_selected = true; + + internal_vp.switch_node(true); + pcModeSwitch->whichChild = 0; + draw(); + } + else { + internal_vp.switch_node(false); + pcModeSwitch->whichChild = -1; + m_selected = false; + } +} + + +TopoDS_Shape ViewProviderConstraint::getConstraintShape(int link) +{ + + if(link == 1) { + //subshape of first link + //********************** + App::DocumentObject* obj1 = dynamic_cast(pcObject)->First.getValue(); + + if(!obj1) + return TopoDS_Shape(); + + Assembly::ItemPart* part1 = static_cast(obj1); + + if(!part1) + return TopoDS_Shape(); + + Part::TopoShape ts; + App::DocumentObject* feature1 = part1->Model.getValue(); + + if(feature1->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + ts = static_cast(feature1)->Shape.getShape(); + } + else return TopoDS_Shape(); + + TopoDS_Shape s1 = ts.getSubShape(dynamic_cast(pcObject)->First.getSubValues()[0].c_str()); + + return s1; + } + else { + //subshape of second link + //********************** + App::DocumentObject* obj2 = dynamic_cast(pcObject)->Second.getValue(); + + if(!obj2) + return TopoDS_Shape(); + + Assembly::ItemPart* part2 = static_cast(obj2); + + if(!part2) + return TopoDS_Shape(); + + Part::TopoShape ts2; + App::DocumentObject* feature2 = part2->Model.getValue(); + + if(feature2->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + ts2 = static_cast(feature2)->Shape.getShape(); + } + else return TopoDS_Shape(); + + TopoDS_Shape s2 = ts2.getSubShape(dynamic_cast(pcObject)->Second.getSubValues()[0].c_str()); + + return s2; + }; +} diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h new file mode 100644 index 000000000000..83547f8fc2ee --- /dev/null +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -0,0 +1,100 @@ +/*************************************************************************** + * Copyright (c) 2013 Stefan Tröger * + * * + * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINT_H +#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINT_H + +#include +#include +#include +#include + +namespace AssemblyGui { + +//class for internal use to alllow access to protected functions of view provider part. +class AssemblyGuiExport ViewProviderConstraintInternal : public PartGui::ViewProviderPart { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintInternal); + +public: + ViewProviderConstraintInternal(); + void updateVis(const TopoDS_Shape& shape); + void setDisplayMM(const char* mode) { + setDisplayMaskMode(mode); + }; + void onChGO(const App::Property* prop) { + ViewProviderGeometryObject::onChanged(prop); + }; + void onChPa(const App::Property* prop) { + ViewProviderPart::onChanged(prop); + }; + //update the transformation node with a Placement + void updatePlacement(const Base::Placement& p); + //switch the display mode node on or off + void switch_node(bool onoff); +}; + + +//this class adds highlight functionality to the constraint: when a constraint is selected +//in the tree all used geometries are shown +class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart, + public Gui::SelectionObserver { + + PROPERTY_HEADER(AssemblyGui::ViewProviderConstraint); + +public: + ViewProviderConstraint(); + + //attach needs to be overridden to attach the second viewprovider and to include + //annotation nodes + virtual void attach(App::DocumentObject* pcObj); + + //needs to be overridden as this viewprovider dos not represent a Part::Feature + virtual void updateData(const App::Property*); + //needs to be overridden as this viewprovider dos not represent a Part::Feature + virtual void onChanged(const App::Property* prop); + + //get the shape which is used by the constraint for highlighting + virtual TopoDS_Shape getConstraintShape(int link); + + //needs to be overridden as we use the modeselection node for on and off and not for + //hide and show in the normal way + virtual bool isShow(void) const; + +private: + //we need two seperate visual representations, as both constraint parts have different + //placements. + ViewProviderConstraintInternal internal_vp; + + //update visualisation and placements of the scenegraph + void draw(); + + //watch if something got selected in the tree + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + + bool m_selected; +}; + +}; + +#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h index 459206fd546e..703937d25cb7 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h @@ -24,20 +24,16 @@ #ifndef ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTAlignment_H #define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTAlignment_H -#include +#include "ViewProviderConstraint.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderConstraintAlignment : public Gui::ViewProviderDocumentObject { +class AssemblyGuiExport ViewProviderConstraintAlignment : public ViewProviderConstraint { PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintAlignment); public: ViewProviderConstraintAlignment(); - - /// checks whether the view provider is visible or not in tree - virtual bool isShow(void) const {return true;}; - }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h index ed1097f4d15f..51b1e849ae8f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h @@ -24,19 +24,17 @@ #ifndef ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTANGLE_H #define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTANGLE_H -#include +#include "ViewProviderConstraint.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderConstraintAngle : public Gui::ViewProviderDocumentObject { +class AssemblyGuiExport ViewProviderConstraintAngle : public ViewProviderConstraint { PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintAngle); public: ViewProviderConstraintAngle(); - /// checks whether the view provider is visible or not in tree - virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h index dee6ab0a259e..e922488d06a2 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h @@ -24,19 +24,17 @@ #ifndef ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTCoincidence_H #define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTCoincidence_H -#include +#include "ViewProviderConstraint.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderConstraintCoincidence : public Gui::ViewProviderDocumentObject { +class AssemblyGuiExport ViewProviderConstraintCoincidence : public ViewProviderConstraint { PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintCoincidence); public: ViewProviderConstraintCoincidence(); - /// checks whether the view provider is visible or not in tree - virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h index 9fbff5ba2aa2..574158da1d80 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h @@ -25,18 +25,17 @@ #define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTDISTANCE_H #include +#include "ViewProviderConstraint.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderConstraintDistance : public Gui::ViewProviderDocumentObject { +class AssemblyGuiExport ViewProviderConstraintDistance : public ViewProviderConstraint { PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintDistance); public: ViewProviderConstraintDistance(); - /// checks whether the view provider is visible or not in tree - virtual bool isShow(void) const {return true;}; }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp index f3f9d22efc33..5c673ac9f4f5 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp @@ -22,6 +22,8 @@ #include "PreCompiled.h" #include "ViewProviderConstraintFix.h" +#include "Mod/Assembly/App/ConstraintFix.h" +#include using namespace AssemblyGui; @@ -32,3 +34,22 @@ ViewProviderConstraintFix::ViewProviderConstraintFix() { sPixmap = "Assembly_ConstraintLock"; } +TopoDS_Shape ViewProviderConstraintFix::getConstraintShape(int link) +{ + if(link == 1) { + + App::DocumentObject* obj = dynamic_cast(pcObject)->First.getValue(); + if(!obj) + return TopoDS_Shape(); + + Assembly::ItemPart* part = static_cast(obj); + if(!part) + return TopoDS_Shape(); + + //return the whole shape + return part->getShape(); + } + + //there is no second link, only one part is fixed per constraint + return TopoDS_Shape(); +} diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h index 66a1e158e8b3..7e0658880721 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h @@ -24,19 +24,19 @@ #ifndef ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTFIX_H #define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTFIX_H -#include +#include "ViewProviderConstraint.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderConstraintFix : public Gui::ViewProviderDocumentObject { +class AssemblyGuiExport ViewProviderConstraintFix : public ViewProviderConstraint { PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintFix); public: ViewProviderConstraintFix(); - /// checks whether the view provider is visible or not in tree - virtual bool isShow(void) const {return true;}; + // override linked shape as we want to highlight the whole part + TopoDS_Shape getConstraintShape(int link); }; }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h index 4276a46df636..3f4bebfc0c50 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h @@ -24,19 +24,17 @@ #ifndef ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTORIENTATION_H #define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTORIENTATION_H -#include +#include "ViewProviderConstraint.h" namespace AssemblyGui { -class AssemblyGuiExport ViewProviderConstraintOrientation : public Gui::ViewProviderDocumentObject { +class AssemblyGuiExport ViewProviderConstraintOrientation : public ViewProviderConstraint { PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintOrientation); public: ViewProviderConstraintOrientation(); - /// checks whether the view provider is visible or not in tree - virtual bool isShow(void) const {return true;}; }; }; From 26cd6de30f187d5dda2c803e9503e210caf4f8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sat, 3 Aug 2013 15:06:08 +0000 Subject: [PATCH 162/664] avoid drawing artefacts when adding new constraint --- src/Mod/Assembly/Gui/ViewProviderConstraint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index d5c49cf62c5f..d7c5ed7002ed 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -105,7 +105,7 @@ void ViewProviderConstraintInternal::switch_node(bool onoff) PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraint, PartGui::ViewProviderPart) -ViewProviderConstraint::ViewProviderConstraint() +ViewProviderConstraint::ViewProviderConstraint() : m_selected(false) { Selectable.setValue(false); From 98d81ed483f75234180549ce8448994a9eaf3aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 4 Aug 2013 08:51:38 +0000 Subject: [PATCH 163/664] make subproduct solving work --- src/Mod/Assembly/App/ItemAssembly.cpp | 41 +- src/Mod/Assembly/App/ItemAssembly.h | 3 +- .../App/opendcm/module3d/clustermath.hpp | 9 +- .../App/opendcm/modulePart/module.hpp | 68 +++- src/Mod/Assembly/Gui/CommandConstraints.cpp | 380 +++++++++++------- .../Assembly/Gui/ViewProviderConstraint.cpp | 26 +- src/Mod/Assembly/Gui/ViewProviderConstraint.h | 2 + 7 files changed, 366 insertions(+), 163 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index cf932865de5d..76c0f2a9bacf 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -73,6 +73,11 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) { //solve the system m_solver->solve(); + + //Parts have updated automaticly, however, currently there are no signals + //for subsystems. We have to retrieve the product placements therefore by hand + finish(boost::shared_ptr()); + } catch(dcm::solving_error& e) { Base::Console().Error("Solver failed with error %i: %s", *boost::get_error_info(e), @@ -163,7 +168,7 @@ ItemAssembly* ItemAssembly::getParentAssembly(ItemPart* part) { -ItemPart* ItemAssembly::getContainingPart(App::DocumentObject* obj) { +std::pair ItemAssembly::getContainingPart(App::DocumentObject* obj) { typedef std::vector::const_iterator iter; @@ -172,22 +177,24 @@ ItemPart* ItemAssembly::getContainingPart(App::DocumentObject* obj) { if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) { if(static_cast(*it)->holdsObject(obj)) - return static_cast(*it); + return std::make_pair(static_cast(*it), this); } else if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { - Assembly::ItemPart* part = static_cast(*it)->getContainingPart(obj); - if(part) + std::pair part = static_cast(*it)->getContainingPart(obj); + if(part.first && part.second) return part; } }; - return NULL; + return std::pair(NULL, NULL); } void ItemAssembly::init(boost::shared_ptr parent) { - if(parent) + if(parent) { m_solver = boost::shared_ptr(parent->createSubsystem()); + m_solver->setTransformation(this->Placement.getValue()); + } typedef std::vector::const_iterator iter; @@ -201,5 +208,27 @@ void ItemAssembly::init(boost::shared_ptr parent) { }; } +//no signals for subsystems, we need to extract the placement by hand +void ItemAssembly::finish(boost::shared_ptr parent) { + + Base::Console().Message("finish\n"); + if(parent) { + Base::Console().Message("set product placement\n"); + Base::Placement p = m_solver->getTransformation(); + this->Placement.setValue(p); + } + + typedef std::vector::const_iterator iter; + + const std::vector& vector = Items.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + static_cast(*it)->finish(m_solver); + } + }; +} + } diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index f9050c55d02f..9a7c2a2cc743 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -60,8 +60,9 @@ class AssemblyExport ItemAssembly : public Assembly::Item bool isParentAssembly(ItemPart* part); ItemAssembly* getParentAssembly(ItemPart* part); - ItemPart* getContainingPart(App::DocumentObject* obj); + std::pair< ItemPart*, ItemAssembly* > getContainingPart(App::DocumentObject* obj); void init(boost::shared_ptr parent); + void finish(boost::shared_ptr parent); boost::shared_ptr m_solver; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp index 2d44b1995a68..989ad3e0cc14 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -418,7 +418,7 @@ std::vector::Geom>& ClusterMath::getGeometry() { template ClusterMath::map_downstream::map_downstream(details::ClusterMath& cm, bool fix) : m_clusterMath(cm), m_isFixed(fix) { - m_transform = m_clusterMath.getTransform(); + m_transform = m_clusterMath.getTransform().inverse(); }; template @@ -431,13 +431,12 @@ void ClusterMath::map_downstream::operator()(Geom g) { //position and offset of the parameters must be set to the clusters values g->setClusterMode(true, m_isFixed); //calculate the appropriate local values - typename Kernel::Transform3D trans = m_transform.inverse(); - g->transform(trans); + g->transform(m_transform); }; template void ClusterMath::map_downstream::operator()(boost::shared_ptr c) { - m_transform *= c->template getClusterProperty().getTransform(); + m_transform *= c->template getClusterProperty().getTransform().inverse(); }; @@ -481,7 +480,7 @@ typename ClusterMath::Scalar ClusterMath::calculateClusterScale() { m_points.push_back((*it)->getPoint()); //start scale calculation - if(m_points.empty()) assert(false); //TODO: Throw + if(m_points.empty()) return 1.; else if(m_points.size() == 1) { const typename Kernel::Vector3 p = m_points[0]; return calcOnePoint(p); diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp index 208cd49cd858..8334c2c8a696 100644 --- a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -98,6 +98,9 @@ struct ModulePart { } Transform& m_transform; }; + + //collect all clustergraph upstream cluster transforms + void transform_traverse(Transform& t, boost::shared_ptr c); public: using Object::m_system; @@ -113,6 +116,15 @@ struct ModulePart { template void set(const T& geometry); + + //access the parts transformation + template + T& get(); + + //get the transformation from part local to overall global. In multi layer systems + //this means the successive transformation from this part to the toplevel cluster + template + T getGlobal(); virtual boost::shared_ptr clone(Sys& newSys); @@ -276,6 +288,9 @@ ModulePart::type::Part_base::Part_base(const T& geometry, Sys cluster->template setClusterProperty(false); + //the the clustermath transform + m_cluster->template getClusterProperty().getTransform() = m_transform; + #ifdef USE_LOGGING BOOST_LOG(log) << "Init: "< typename ModulePart::template type::Part_base::Geom ModulePart::type::Part_base::addGeometry3D(const T& geom, CoordinateFrame frame) { Geom g(new Geometry3D(geom, *m_system)); - if(frame == Local) - g->transform(m_transform); + + if(frame == Local) { + //we need to collect all transforms up to this part! + Transform t; + transform_traverse(t, m_cluster); + + g->transform(t); + } fusion::vector res = m_cluster->addVertex(); m_cluster->template setObject (fusion::at_c<0> (res), g); @@ -305,6 +326,19 @@ ModulePart::type::Part_base::addGeometry3D(const T& geom, Coo return g; }; +template +template +void ModulePart::type::Part_base::transform_traverse(ModulePart::type::Part_base::Transform& t, + boost::shared_ptr::type::Part_base::Cluster> c) { + + t *= c->template getClusterProperty().m_transform; + + if(c->isRoot()) + return; + + transform_traverse(t, c->parent()); +} + template template template @@ -312,6 +346,34 @@ void ModulePart::type::Part_base::set(const T& geometry) { Part_base::m_geometry = geometry; (typename geometry_traits::modell()).template extract::accessor >(geometry, Part_base::m_transform); + + //set the clustermath transform + m_cluster->template getClusterProperty().getTransform() = m_transform; +}; + +template +template +template +T& ModulePart::type::Part_base::get() { + + return get(this); +}; + +template +template +template +T ModulePart::type::Part_base::getGlobal() { + + //get the successive transform + Transform t; + transform_traverse(t, m_cluster); + + //put it into the user type + T ut; + (typename geometry_traits::modell()).template inject::accessor >(ut, t); + + return ut; }; template @@ -564,3 +626,5 @@ void ModulePart::type::EvaljuateCluster::execute(Sys& sys) { + + diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index d415c9d38aba..98653c51c4fe 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -40,29 +40,31 @@ using namespace std; -extern Assembly::Item *ActiveAsmObject; +extern Assembly::Item* ActiveAsmObject; // Helper methods =========================================================== -Assembly::ConstraintGroup * getConstraintGroup(Assembly::ItemAssembly *Asm) +Assembly::ConstraintGroup* getConstraintGroup(Assembly::ItemAssembly* Asm) { - Assembly::ConstraintGroup *ConstGrp = 0; + Assembly::ConstraintGroup* ConstGrp = 0; std::vector Ano = Asm->Annotations.getValues(); - for(std::vector::const_iterator it = Ano.begin();it!=Ano.end();++it){ - if((*it)->getTypeId().isDerivedFrom(Assembly::ConstraintGroup::getClassTypeId() )){ + + for(std::vector::const_iterator it = Ano.begin(); it != Ano.end(); ++it) { + if((*it)->getTypeId().isDerivedFrom(Assembly::ConstraintGroup::getClassTypeId())) { ConstGrp = static_cast(*it); break; } } + return ConstGrp; } -bool getConstraintPrerequisits(Assembly::ItemAssembly **Asm,Assembly::ConstraintGroup **ConstGrp) +bool getConstraintPrerequisits(Assembly::ItemAssembly** Asm, Assembly::ConstraintGroup** ConstGrp) { - if(!ActiveAsmObject || !ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())){ + if(!ActiveAsmObject || !ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Assembly"), - QObject::tr("You need a active (blue) Assembly to insert a Constraint. Please create a new one or make one active (double click).")); + QObject::tr("You need a active (blue) Assembly to insert a Constraint. Please create a new one or make one active (double click).")); return true; } @@ -70,15 +72,18 @@ bool getConstraintPrerequisits(Assembly::ItemAssembly **Asm,Assembly::Constraint // find the Constraint group of the active Assembly *ConstGrp = getConstraintGroup(*Asm); + // if it hasen't aleardy one, create one: - if(!*ConstGrp){ - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ConstraintGroup','ConstraintGroup')"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().ActiveObject.Label = 'ConstraintGroup'"); - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Annotations = App.activeDocument().%s.Annotations + [App.activeDocument().ActiveObject]",(*Asm)->getNameInDocument(),(*Asm)->getNameInDocument()); + if(!*ConstGrp) { + Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().addObject('Assembly::ConstraintGroup','ConstraintGroup')"); + Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().ActiveObject.Label = 'ConstraintGroup'"); + Gui::Command::doCommand(Gui::Command::Doc, "App.activeDocument().%s.Annotations = App.activeDocument().%s.Annotations + [App.activeDocument().ActiveObject]", (*Asm)->getNameInDocument(), (*Asm)->getNameInDocument()); } + // find now *ConstGrp = getConstraintGroup(*Asm); + if(!*ConstGrp) throw Base::Exception("Could not create Assembly::ConstraintGroup in active Assembly"); @@ -87,13 +92,14 @@ bool getConstraintPrerequisits(Assembly::ItemAssembly **Asm,Assembly::Constraint } -std::string asSubLinkString(Assembly::ItemPart* part, std::string element) { - std::string buf; +std::string asSubLinkString(Assembly::ItemPart* part, std::string element) +{ + std::string buf; buf += "(App.ActiveDocument."; - buf += part->getNameInDocument(); + buf += part->getNameInDocument(); buf += ",['"; buf += element; - buf += "'])"; + buf += "'])"; return buf; } @@ -102,7 +108,7 @@ std::string asSubLinkString(Assembly::ItemPart* part, std::string element) { DEF_STD_CMD(CmdAssemblyConstraintDistance); CmdAssemblyConstraintDistance::CmdAssemblyConstraintDistance() - :Command("Assembly_ConstraintDistance") + : Command("Assembly_ConstraintDistance") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); @@ -116,45 +122,57 @@ CmdAssemblyConstraintDistance::CmdAssemblyConstraintDistance() void CmdAssemblyConstraintDistance::activated(int iMsg) { - Assembly::ItemAssembly *Asm=0; - Assembly::ConstraintGroup *ConstGrp=0; + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; // retrive the standard objects needed - if(getConstraintPrerequisits(&Asm,&ConstGrp)) + if(getConstraintPrerequisits(&Asm, &ConstGrp)) return; - + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You need to select two geometries on two different parts")); + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("You need to select two geometries on two different parts")); return; }; - - Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); - Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); - if(!part1 || !part2) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + + std::pair part1 = Asm->getContainingPart(objs[0].getObject()); + std::pair part2 = Asm->getContainingPart(objs[1].getObject()); + + //checking the parts is enough, both or non! + if(!part1.first || !part2.first) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; - + + //check if this is the right place for the constraint + if( (part1.second == part2.second) && part1.second != Asm ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); + return; + } + bool ok; + double d = QInputDialog::getDouble(NULL, QObject::tr("Constraint value"), - QObject::tr("Distance:"), 0., -10000., 10000., 2, &ok); + QObject::tr("Distance:"), 0., -10000., 10000., 2, &ok); + if(!ok) - return; - + return; + openCommand("Insert Constraint Distance"); std::string ConstrName = getUniqueObjectName("Distance"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintDistance','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Distance = %f", d); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); - + doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintDistance','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Distance = %f", d); + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + commitCommand(); updateActive(); - + } /******************************************************************************************/ @@ -162,7 +180,7 @@ void CmdAssemblyConstraintDistance::activated(int iMsg) DEF_STD_CMD(CmdAssemblyConstraintFix); CmdAssemblyConstraintFix::CmdAssemblyConstraintFix() - :Command("Assembly_ConstraintFix") + : Command("Assembly_ConstraintFix") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); @@ -176,43 +194,56 @@ CmdAssemblyConstraintFix::CmdAssemblyConstraintFix() void CmdAssemblyConstraintFix::activated(int iMsg) { - Assembly::ItemAssembly *Asm=0; - Assembly::ConstraintGroup *ConstGrp=0; + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; // retrive the standard objects needed - if(getConstraintPrerequisits(&Asm,&ConstGrp)) + if(getConstraintPrerequisits(&Asm, &ConstGrp)) return; - + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You need to select one part only")); + QObject::tr("You need to select one part only")); return; }; - - Assembly::ItemPart* part = Asm->getContainingPart(objs[0].getObject()); - if(!part) { - Base::Console().Message("The selected object need to belong to the active assembly\n"); + + std::pair part = Asm->getContainingPart(objs[0].getObject()); + + if(!part.first) { + Base::Console().Message("The selected part need to belong to the active assembly\n"); return; }; - + + if(part.second != Asm) { + Base::Console().Message("The selected part need belongs to an subproduct, please add constraint there\n"); + return; + } + openCommand("Insert Constraint Fix"); + std::string ConstrName = getUniqueObjectName("Fix"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintFix','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); - + + doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintFix','%s')", ConstrName.c_str()); + + doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part.first, objs[0].getSubNames()[0]).c_str()); + + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + commitCommand(); + updateActive(); } + /******************************************************************************************/ DEF_STD_CMD(CmdAssemblyConstraintAngle); CmdAssemblyConstraintAngle::CmdAssemblyConstraintAngle() - :Command("Assembly_ConstraintAngle") + : Command("Assembly_ConstraintAngle") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); @@ -226,45 +257,57 @@ CmdAssemblyConstraintAngle::CmdAssemblyConstraintAngle() void CmdAssemblyConstraintAngle::activated(int iMsg) { - Assembly::ItemAssembly *Asm=0; - Assembly::ConstraintGroup *ConstGrp=0; + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; // retrive the standard objects needed - if(getConstraintPrerequisits(&Asm,&ConstGrp)) + if(getConstraintPrerequisits(&Asm, &ConstGrp)) return; - + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You need to select two geometries on two different parts")); + QObject::tr("You need to select two geometries on two different parts")); return; }; - - Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); - Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); - if(!part1 || !part2) { + + std::pair part1 = Asm->getContainingPart(objs[0].getObject()); + std::pair part2 = Asm->getContainingPart(objs[1].getObject()); + + //checking the parts is enough, both or non! + if(!part1.first || !part2.first) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; - + + //check if this is the right place for the constraint + if( ( (part1.second == part2.second) && part1.second != Asm ) && part1.second != Asm ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); + return; + } + bool ok; + double d = QInputDialog::getDouble(NULL, QObject::tr("Constraint value"), - QObject::tr("Angle:"), 0., 0., 360., 2, &ok); + QObject::tr("Angle:"), 0., 0., 360., 2, &ok); + if(!ok) - return; - + return; + openCommand("Insert Constraint Angle"); std::string ConstrName = getUniqueObjectName("Angle"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintAngle','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Angle = %f", d); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); - + doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintAngle','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Angle = %f", d); + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + commitCommand(); updateActive(); - + } @@ -274,7 +317,7 @@ void CmdAssemblyConstraintAngle::activated(int iMsg) DEF_STD_CMD(CmdAssemblyConstraintOrientation); CmdAssemblyConstraintOrientation::CmdAssemblyConstraintOrientation() - :Command("Assembly_ConstraintOrientation") + : Command("Assembly_ConstraintOrientation") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); @@ -288,48 +331,61 @@ CmdAssemblyConstraintOrientation::CmdAssemblyConstraintOrientation() void CmdAssemblyConstraintOrientation::activated(int iMsg) { - Assembly::ItemAssembly *Asm=0; - Assembly::ConstraintGroup *ConstGrp=0; + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; // retrive the standard objects needed - if(getConstraintPrerequisits(&Asm,&ConstGrp)) + if(getConstraintPrerequisits(&Asm, &ConstGrp)) return; - + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You need to select two geometries on two different parts")); + QObject::tr("You need to select two geometries on two different parts")); return; }; - - Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); - Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); - if(!part1 || !part2) { + + std::pair part1 = Asm->getContainingPart(objs[0].getObject()); + std::pair part2 = Asm->getContainingPart(objs[1].getObject()); + + //checking the parts is enough, both or non! + if(!part1.first || !part2.first) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; - + + //check if this is the right place for the constraint + if( (part1.second == part2.second) && part1.second != Asm ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); + return; + } + QStringList items; + items << QObject::tr("Parallel") << QObject::tr("Perpendicular") << QObject::tr("Equal") << QObject::tr("Opposite"); bool ok; + QString item = QInputDialog::getItem(NULL, QObject::tr("Constraint value"), - QObject::tr("Orientation:"), items, 0, false, &ok); - if (!ok || item.isEmpty()) + QObject::tr("Orientation:"), items, 0, false, &ok); + + if(!ok || item.isEmpty()) return; - + openCommand("Insert Constraint Orientation"); std::string ConstrName = getUniqueObjectName("Orientation"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintOrientation','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); - + doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintOrientation','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + commitCommand(); updateActive(); - + } /******************************************************************************************/ @@ -338,7 +394,7 @@ void CmdAssemblyConstraintOrientation::activated(int iMsg) DEF_STD_CMD(CmdAssemblyConstraintCoincidence); CmdAssemblyConstraintCoincidence::CmdAssemblyConstraintCoincidence() - :Command("Assembly_ConstraintCoincidence") + : Command("Assembly_ConstraintCoincidence") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); @@ -352,48 +408,61 @@ CmdAssemblyConstraintCoincidence::CmdAssemblyConstraintCoincidence() void CmdAssemblyConstraintCoincidence::activated(int iMsg) { - Assembly::ItemAssembly *Asm=0; - Assembly::ConstraintGroup *ConstGrp=0; + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; // retrive the standard objects needed - if(getConstraintPrerequisits(&Asm,&ConstGrp)) + if(getConstraintPrerequisits(&Asm, &ConstGrp)) return; - + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You need to select two geometries on two different parts")); + QObject::tr("You need to select two geometries on two different parts")); return; }; - - Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); - Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); - if(!part1 || !part2) { + + std::pair part1 = Asm->getContainingPart(objs[0].getObject()); + std::pair part2 = Asm->getContainingPart(objs[1].getObject()); + + //checking the parts is enough, both or non! + if(!part1.first || !part2.first) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; - + + //check if this is the right place for the constraint + if( (part1.second == part2.second) && part1.second != Asm ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); + return; + } + QStringList items; + items << QObject::tr("Parallel") << QObject::tr("Equal") << QObject::tr("Opposite"); bool ok; + QString item = QInputDialog::getItem(NULL, QObject::tr("Constraint value"), - QObject::tr("Orientation:"), items, 0, false, &ok); - if (!ok || item.isEmpty()) + QObject::tr("Orientation:"), items, 0, false, &ok); + + if(!ok || item.isEmpty()) return; - + openCommand("Insert Constraint Coincidence"); std::string ConstrName = getUniqueObjectName("Coincidence"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintCoincidence','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); - + doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintCoincidence','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + commitCommand(); updateActive(); - + } /******************************************************************************************/ @@ -402,7 +471,7 @@ void CmdAssemblyConstraintCoincidence::activated(int iMsg) DEF_STD_CMD(CmdAssemblyConstraintAlignment); CmdAssemblyConstraintAlignment::CmdAssemblyConstraintAlignment() - :Command("Assembly_ConstraintAlignment") + : Command("Assembly_ConstraintAlignment") { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); @@ -416,55 +485,70 @@ CmdAssemblyConstraintAlignment::CmdAssemblyConstraintAlignment() void CmdAssemblyConstraintAlignment::activated(int iMsg) { - Assembly::ItemAssembly *Asm=0; - Assembly::ConstraintGroup *ConstGrp=0; + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; // retrive the standard objects needed - if(getConstraintPrerequisits(&Asm,&ConstGrp)) + if(getConstraintPrerequisits(&Asm, &ConstGrp)) return; - + std::vector objs = Gui::Selection().getSelectionEx(); + if(objs.size() != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You need to select two geometries on two different parts")); + QObject::tr("You need to select two geometries on two different parts")); return; }; - - Assembly::ItemPart* part1 = Asm->getContainingPart(objs[0].getObject()); - Assembly::ItemPart* part2 = Asm->getContainingPart(objs[1].getObject()); - if(!part1 || !part2) { + + std::pair part1 = Asm->getContainingPart(objs[0].getObject()); + std::pair part2 = Asm->getContainingPart(objs[1].getObject()); + + //checking the parts is enough, both or non! + if(!part1.first || !part2.first) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); return; }; - + + //check if this is the right place for the constraint + if( (part1.second == part2.second) && part1.second != Asm ) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); + return; + } + QStringList items; + items << QObject::tr("Parallel") << QObject::tr("Equal") << QObject::tr("Opposite"); QDialog dialog; - Ui_AlignmentDialog ui; + + Ui_AlignmentDialog ui; + ui.setupUi(&dialog); + ui.comboBox->addItems(items); - if( dialog.exec() != QDialog::Accepted ) - return; - + + if(dialog.exec() != QDialog::Accepted) + return; + openCommand("Insert Constraint Alignment"); std::string ConstrName = getUniqueObjectName("Alignment"); - doCommand(Doc,"App.activeDocument().addObject('Assembly::ConstraintAlignment','%s')",ConstrName.c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Orientation = '%s'", ui.comboBox->currentText().toStdString().c_str()); - doCommand(Doc,"App.activeDocument().ActiveObject.Offset = %f", ui.doubleSpinBox->value()); - doCommand(Doc,"App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]",ConstGrp->getNameInDocument(),ConstGrp->getNameInDocument()); - + doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintAlignment','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Orientation = '%s'", ui.comboBox->currentText().toStdString().c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Offset = %f", ui.doubleSpinBox->value()); + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + commitCommand(); updateActive(); - + } void CreateAssemblyConstraintCommands(void) { - Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); + Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdAssemblyConstraintFix()); rcCmdMgr.addCommand(new CmdAssemblyConstraintDistance()); @@ -472,4 +556,6 @@ void CreateAssemblyConstraintCommands(void) rcCmdMgr.addCommand(new CmdAssemblyConstraintOrientation()); rcCmdMgr.addCommand(new CmdAssemblyConstraintCoincidence()); rcCmdMgr.addCommand(new CmdAssemblyConstraintAlignment()); - } +} + + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index d7c5ed7002ed..f52b9d40fcdd 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -232,7 +232,8 @@ void ViewProviderConstraint::draw() TopLoc_Location l1 = s1.Location(); gp_XYZ tr1 = l1.Transformation().TranslationPart(); Base::Placement p1(Base::Vector3d(tr1.X(), tr1.Y(), tr1.Z()), Base::Rotation()); - p1 = part1->Placement.getValue() * p1; + upstream_placement(p1, part1); + //p1 = part1->m_part->getGlobal() * p1; float q0 = (float)p1.getRotation().getValue()[0]; float q1 = (float)p1.getRotation().getValue()[1]; @@ -265,11 +266,32 @@ void ViewProviderConstraint::draw() TopLoc_Location l2 = s2.Location(); gp_XYZ tr2 = l2.Transformation().TranslationPart(); Base::Placement p2(Base::Vector3d(tr2.X(), tr2.Y(), tr2.Z()), Base::Rotation()); + upstream_placement(p2, part2); - p2 = p1.inverse() * (part2->Placement.getValue() * p2); + p2 = p1.inverse()*p2; + //p2 = p1.inverse() * (part2->m_part->getGlobal() * p2); internal_vp.updatePlacement(p2); } +void ViewProviderConstraint::upstream_placement(Base::Placement& p, Assembly::Item* item) { + + //successive transformation for this item + p = item->Placement.getValue() * p; + + typedef std::vector::const_iterator iter; + + //get all links to this item and see if we have more ItemAssemblys + const std::vector& vector = item->getInList(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + upstream_placement(p, static_cast(*it)); + return; + } + }; +}; + void ViewProviderConstraint::onSelectionChanged(const Gui::SelectionChanges& msg) { if(Gui::Selection().isSelected(pcObject) && Visibility.getValue()) { diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h index 83547f8fc2ee..cedcfcfef04e 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -28,6 +28,7 @@ #include #include #include +#include "Mod/Assembly/App/Item.h" namespace AssemblyGui { @@ -88,6 +89,7 @@ class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart //update visualisation and placements of the scenegraph void draw(); + void upstream_placement(Base::Placement& p, Assembly::Item* item); //watch if something got selected in the tree virtual void onSelectionChanged(const Gui::SelectionChanges& msg); From 7fe1d94a2165d104ecf6ef17ba82ceb2b2b88a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 4 Aug 2013 13:54:04 +0000 Subject: [PATCH 164/664] fix rotational/translational solver bugs in cylce detection and mapping --- src/Mod/Assembly/App/ConstraintGroup.cpp | 1 - src/Mod/Assembly/App/ItemAssembly.cpp | 2 -- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 6 +++--- src/Mod/Assembly/App/opendcm/module3d/solver.hpp | 12 +++++++++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp index 818f9aa37804..b8f6db81a077 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.cpp +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -85,5 +85,4 @@ void ConstraintGroup::init(ItemAssembly* ass) { } } - } diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 76c0f2a9bacf..960828f6002f 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -211,9 +211,7 @@ void ItemAssembly::init(boost::shared_ptr parent) { //no signals for subsystems, we need to extract the placement by hand void ItemAssembly::finish(boost::shared_ptr parent) { - Base::Console().Message("finish\n"); if(parent) { - Base::Console().Message("set product placement\n"); Base::Placement p = m_solver->getTransformation(); this->Placement.setValue(p); } diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 80f37d753fd2..392dc43da0f2 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -438,15 +438,15 @@ struct Kernel { void setAccess(ParameterType t) { if(t==complete) { - new(&Jacobi) VectorMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1)); + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1)); new(&Parameter) VectorMap(&m_parameter(0),m_params,DynStride(1,1)); } else if(t==rotation) { int num = m_param_trans_offset; - new(&Jacobi) VectorMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1)); } else if(t==general) { int num = m_params - m_param_trans_offset; - new(&Jacobi) VectorMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); + new(&Jacobi) MatrixMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1)); } }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index d2ce5d1d984f..3f8d5a114fc7 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -29,8 +29,12 @@ #include #include +#include #include +#include "Base/Console.h" +#include + namespace dcm { namespace details { @@ -374,10 +378,12 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy cycle_dedector cd(has_cycle); //create te needed property map, fill it and run the test property_map vi_map(cluster); + property_map vc_map(cluster); + property_map ec_map(cluster); cluster->initIndexMaps(); - boost::depth_first_search(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map)); - - bool done = false; + boost::undirected_dfs(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map).vertex_color_map(vc_map).edge_color_map(ec_map)); + + bool done = false; if(!has_cycle) { #ifdef USE_LOGGING BOOST_LOG(log)<< "non-cyclic system dedected" From 14c20fbe89a7ead65ccf82beb11750710526bf39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 4 Aug 2013 14:10:05 +0000 Subject: [PATCH 165/664] remove console messages --- src/Mod/Assembly/App/ConstraintGroup.cpp | 1 - src/Mod/Assembly/App/ItemAssembly.cpp | 3 +-- src/Mod/Assembly/App/ItemPart.cpp | 15 ++++----------- src/Mod/Assembly/Gui/ViewProviderConstraint.cpp | 5 ----- 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/src/Mod/Assembly/App/ConstraintGroup.cpp b/src/Mod/Assembly/App/ConstraintGroup.cpp index b8f6db81a077..3c79eae4214b 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.cpp +++ b/src/Mod/Assembly/App/ConstraintGroup.cpp @@ -68,7 +68,6 @@ short ConstraintGroup::mustExecute() const App::DocumentObjectExecReturn *ConstraintGroup::execute(void) { - Base::Console().Message("Recalculate constraint group\n"); touch(); return App::DocumentObject::StdReturn; } diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 960828f6002f..c1ff95d2379b 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -54,8 +54,7 @@ short ItemAssembly::mustExecute() const { } App::DocumentObjectExecReturn* ItemAssembly::execute(void) { - Base::Console().Message("Execute ItemAssembly\n"); - + try { //create a solver and init all child assemblys with subsolvers m_solver = boost::shared_ptr(new Solver); diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index f594ea931400..097b9dd2e281 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -65,8 +65,7 @@ short ItemPart::mustExecute() const App::DocumentObjectExecReturn *ItemPart::execute(void) { - Base::Console().Message("Recalculate ItemPart\n"); - this->touch(); + this->touch(); return App::DocumentObject::StdReturn; } @@ -102,9 +101,7 @@ bool ItemPart::holdsObject(App::DocumentObject* obj) const { void ItemPart::setCalculatedPlacement(boost::shared_ptr< Part3D > part) { - //part is the same as m_part, so it doasn't matter which one we use - Base::Console().Message("Set new calculated part placement\n"); - + //part is the same as m_part, so it doasn't matter which one we use Base::Placement p = dcm::get(part); Placement.setValue(p); } @@ -120,7 +117,6 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) boost::shared_ptr geometry; if(m_part->hasGeometry3D(Type)) { return m_part->getGeometry3D(Type); - //Base::Console().Message("Already has geometry, nothing added\n"); } else { Part::TopoShape ts; App::DocumentObject* obj = Model.getValue(); @@ -134,10 +130,8 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) if(s.ShapeType() == TopAbs_FACE) { TopoDS_Face face = TopoDS::Face(s); BRepAdaptor_Surface surface(face); - //Base::Console().Message("Fase selected\n"); switch(surface.GetType()) { case GeomAbs_Plane: { - //Base::Console().Message("plane selected\n"); gp_Pln plane = surface.Plane(); if(face.Orientation()==TopAbs_REVERSED) { gp_Dir dir = plane.Axis().Direction(); @@ -147,7 +141,6 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) break; } case GeomAbs_Cylinder: { - //Base::Console().Message("cylinder selected\n"); gp_Cylinder cyl = surface.Cylinder(); geometry = m_part->addGeometry3D(cyl, Type, dcm::Local); break; @@ -181,11 +174,11 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) return boost::shared_ptr< Geometry3D >(); } }; - +/* std::stringstream s; s<m_global; Base::Console().Message("Added geom: %s, %s\n", Type, s.str().c_str()); - +*/ return geometry; } diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index f52b9d40fcdd..b26e2cc55c4f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -172,8 +172,6 @@ void ViewProviderConstraint::attach(App::DocumentObject* pcFeat) void ViewProviderConstraint::updateData(const App::Property* prop) { - Base::Console().Message("update: %s\n", prop->getName()); - if(Visibility.getValue() && m_selected) { draw(); @@ -185,9 +183,6 @@ void ViewProviderConstraint::updateData(const App::Property* prop) void ViewProviderConstraint::onChanged(const App::Property* prop) { - - Base::Console().Message("changed: %s, selected: %i\n", prop->getName(), m_selected); - // parent expects the app object to be part::feature, but it isn't. so we have to avoid // the visability prop as this results in accessing of the part::feature and would crash if(prop == &Visibility) { From bf8d5e7aa92f839ce4ba61fa876c899c7e5bc51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 4 Aug 2013 15:56:43 +0000 Subject: [PATCH 166/664] fix subassembly transformation bug --- src/Mod/Assembly/App/ItemAssembly.cpp | 1 + src/Mod/Assembly/App/ItemPart.cpp | 6 +----- src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp | 8 +++++++- src/Mod/Assembly/App/opendcm/modulePart/module.hpp | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index c1ff95d2379b..44e95c995092 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -56,6 +56,7 @@ short ItemAssembly::mustExecute() const { App::DocumentObjectExecReturn* ItemAssembly::execute(void) { try { + //create a solver and init all child assemblys with subsolvers m_solver = boost::shared_ptr(new Solver); init(boost::shared_ptr()); diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index 097b9dd2e281..f138668e669e 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -174,11 +174,7 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) return boost::shared_ptr< Geometry3D >(); } }; -/* - std::stringstream s; - s<m_global; - Base::Console().Message("Added geom: %s, %s\n", Type, s.str().c_str()); -*/ + return geometry; } diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp index 989ad3e0cc14..97592cc00c17 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -29,6 +29,8 @@ #include #include "defines.hpp" +#include "Base/Console.h" + #define MAXFAKTOR 1.2 //the maximal distance allowd by a point normed to the cluster size #define MINFAKTOR 0.8 //the minimal distance allowd by a point normed to the cluster size #define SKALEFAKTOR 1. //the faktor by which the biggest size is multiplied to get the scale value @@ -436,7 +438,11 @@ void ClusterMath::map_downstream::operator()(Geom g) { template void ClusterMath::map_downstream::operator()(boost::shared_ptr c) { - m_transform *= c->template getClusterProperty().getTransform().inverse(); + //we transform the GLOBAL geometries to local ones in the subcluster! therefore + //we are not interested in the successive transformations, we only transform the + //global geometries with the cluster transform we want them to be local in, and thats + //the one supplied in the constructor + //m_transform *= c->template getClusterProperty().getTransform().inverse(); }; diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp index 8334c2c8a696..3e13ec294c0e 100644 --- a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -314,8 +314,8 @@ ModulePart::type::Part_base::addGeometry3D(const T& geom, Coo //we need to collect all transforms up to this part! Transform t; transform_traverse(t, m_cluster); - - g->transform(t); + + g->transform(t); } fusion::vector res = m_cluster->addVertex(); From e9e1b452809902bfcdfb7e1e426592901109e7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 12 Aug 2013 19:49:28 +0000 Subject: [PATCH 167/664] allow non-rigid subassemblies --- src/Mod/Assembly/App/Constraint.cpp | 21 +- src/Mod/Assembly/App/Constraint.h | 4 +- src/Mod/Assembly/App/ConstraintAlignment.cpp | 2 +- src/Mod/Assembly/App/ConstraintAlignment.h | 2 +- src/Mod/Assembly/App/ConstraintAngle.cpp | 2 +- src/Mod/Assembly/App/ConstraintAngle.h | 2 +- .../Assembly/App/ConstraintCoincidence.cpp | 2 +- src/Mod/Assembly/App/ConstraintCoincidence.h | 2 +- src/Mod/Assembly/App/ConstraintDistance.cpp | 2 +- src/Mod/Assembly/App/ConstraintDistance.h | 2 +- src/Mod/Assembly/App/ConstraintFix.cpp | 4 +- src/Mod/Assembly/App/ConstraintFix.h | 2 +- src/Mod/Assembly/App/ConstraintGroup.h | 2 +- .../Assembly/App/ConstraintOrientation.cpp | 2 +- src/Mod/Assembly/App/ConstraintOrientation.h | 2 +- src/Mod/Assembly/App/ItemAssembly.cpp | 113 +++++++---- src/Mod/Assembly/App/ItemAssembly.h | 16 +- src/Mod/Assembly/App/ItemPart.cpp | 182 +++++++++++------- src/Mod/Assembly/App/ItemPart.h | 4 + src/Mod/Assembly/Gui/CommandConstraints.cpp | 1 + .../Assembly/Gui/ViewProviderConstraint.cpp | 1 + .../Gui/ViewProviderConstraintFix.cpp | 1 + 22 files changed, 234 insertions(+), 137 deletions(-) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp index 84772447ea81..0343a39f7eb3 100644 --- a/src/Mod/Assembly/App/Constraint.cpp +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -79,7 +79,7 @@ App::DocumentObjectExecReturn *Constraint::execute(void) return App::DocumentObject::StdReturn; } -boost::shared_ptr Constraint::initLink(ItemAssembly* ass, App::PropertyLinkSub& link) { +boost::shared_ptr Constraint::initLink(App::PropertyLinkSub& link) { //check if we have Assembly::ItemPart if( link.getValue()->getTypeId() != ItemPart::getClassTypeId() ) { @@ -92,27 +92,16 @@ boost::shared_ptr Constraint::initLink(ItemAssembly* ass, App::Prope return boost::shared_ptr(); //get the relevant solver in which the part needs to be added - Assembly::ItemAssembly* p_ass = ass->getParentAssembly(part); - if(!p_ass) - return boost::shared_ptr(); - - boost::shared_ptr solver = p_ass->m_solver; - if(!solver) - return boost::shared_ptr(); - - if(!solver->hasPart(part->Uid.getValueStr())) { - part->m_part = solver->createPart(part->Placement.getValue(), part->Uid.getValueStr()); - part->m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, part, _1)); - }; + part->ensureInitialisation(); return part->getGeometry3D(link.getSubValues()[0].c_str()); } -void Constraint::init(ItemAssembly* ass) +void Constraint::init(Assembly::ItemAssembly* ass) { - m_first_geom = initLink(ass, First); - m_second_geom = initLink(ass, Second); + m_first_geom = initLink(First); + m_second_geom = initLink(Second); } PyObject *Constraint::getPyObject(void) diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h index 2be02e75661e..c6d00f23e4a9 100644 --- a/src/Mod/Assembly/App/Constraint.h +++ b/src/Mod/Assembly/App/Constraint.h @@ -45,7 +45,7 @@ class AssemblyExport Constraint : public App::DocumentObject boost::shared_ptr m_constraint; boost::shared_ptr m_first_geom, m_second_geom; - boost::shared_ptr< Geometry3D > initLink(Assembly::ItemAssembly* ass, App::PropertyLinkSub& link); + boost::shared_ptr< Geometry3D > initLink(App::PropertyLinkSub& link); public: Constraint(); @@ -66,7 +66,7 @@ class AssemblyExport Constraint : public App::DocumentObject /** @brief initialize the constraint in the assembly solver */ - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintAlignment.cpp b/src/Mod/Assembly/App/ConstraintAlignment.cpp index f2ad98cd3047..dd08b205f12a 100644 --- a/src/Mod/Assembly/App/ConstraintAlignment.cpp +++ b/src/Mod/Assembly/App/ConstraintAlignment.cpp @@ -63,7 +63,7 @@ App::DocumentObjectExecReturn *ConstraintAlignment::execute(void) return App::DocumentObject::StdReturn; } -void ConstraintAlignment::init(ItemAssembly* ass) { +void ConstraintAlignment::init(Assembly::ItemAssembly* ass) { //cant use the base class init as we only need one part Constraint::init(ass); diff --git a/src/Mod/Assembly/App/ConstraintAlignment.h b/src/Mod/Assembly/App/ConstraintAlignment.h index 7e5dfc23592e..b9ba6279bd34 100644 --- a/src/Mod/Assembly/App/ConstraintAlignment.h +++ b/src/Mod/Assembly/App/ConstraintAlignment.h @@ -52,7 +52,7 @@ class AssemblyExport ConstraintAlignment : public Assembly::Constraint } //@} - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace PartDesign diff --git a/src/Mod/Assembly/App/ConstraintAngle.cpp b/src/Mod/Assembly/App/ConstraintAngle.cpp index 69fa6479f433..f7c19bd3db1f 100644 --- a/src/Mod/Assembly/App/ConstraintAngle.cpp +++ b/src/Mod/Assembly/App/ConstraintAngle.cpp @@ -57,7 +57,7 @@ App::DocumentObjectExecReturn *ConstraintAngle::execute(void) return App::DocumentObject::StdReturn; } -void ConstraintAngle::init(ItemAssembly* ass) +void ConstraintAngle::init(Assembly::ItemAssembly* ass) { //init the parts and geometries Constraint::init(ass); diff --git a/src/Mod/Assembly/App/ConstraintAngle.h b/src/Mod/Assembly/App/ConstraintAngle.h index 29bce3e25cf1..60ffd110fca4 100644 --- a/src/Mod/Assembly/App/ConstraintAngle.h +++ b/src/Mod/Assembly/App/ConstraintAngle.h @@ -51,7 +51,7 @@ class AssemblyExport ConstraintAngle : public Assembly::Constraint } //@} - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintCoincidence.cpp b/src/Mod/Assembly/App/ConstraintCoincidence.cpp index f0ec83382ed2..326787e62903 100644 --- a/src/Mod/Assembly/App/ConstraintCoincidence.cpp +++ b/src/Mod/Assembly/App/ConstraintCoincidence.cpp @@ -63,7 +63,7 @@ App::DocumentObjectExecReturn *ConstraintCoincidence::execute(void) return App::DocumentObject::StdReturn; } -void ConstraintCoincidence::init(ItemAssembly* ass) { +void ConstraintCoincidence::init(Assembly::ItemAssembly* ass) { //cant use the base class init as we only need one part Constraint::init(ass); diff --git a/src/Mod/Assembly/App/ConstraintCoincidence.h b/src/Mod/Assembly/App/ConstraintCoincidence.h index 180d9bd4f36e..c20e4a75dba3 100644 --- a/src/Mod/Assembly/App/ConstraintCoincidence.h +++ b/src/Mod/Assembly/App/ConstraintCoincidence.h @@ -51,7 +51,7 @@ class AssemblyExport ConstraintCoincidence : public Assembly::Constraint } //@} - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintDistance.cpp b/src/Mod/Assembly/App/ConstraintDistance.cpp index 10ef64745e56..7d79923b6c6d 100644 --- a/src/Mod/Assembly/App/ConstraintDistance.cpp +++ b/src/Mod/Assembly/App/ConstraintDistance.cpp @@ -70,7 +70,7 @@ App::DocumentObjectExecReturn *ConstraintDistance::execute(void) return App::DocumentObject::StdReturn; } -void ConstraintDistance::init(ItemAssembly* ass) +void ConstraintDistance::init(Assembly::ItemAssembly* ass) { //init the parts and geometries Constraint::init(ass); diff --git a/src/Mod/Assembly/App/ConstraintDistance.h b/src/Mod/Assembly/App/ConstraintDistance.h index e3f3f22fb217..549e0e4341ff 100644 --- a/src/Mod/Assembly/App/ConstraintDistance.h +++ b/src/Mod/Assembly/App/ConstraintDistance.h @@ -53,7 +53,7 @@ class AssemblyExport ConstraintDistance : public Assembly::Constraint } //@} - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintFix.cpp b/src/Mod/Assembly/App/ConstraintFix.cpp index 06771fd07742..fe05bb32baef 100644 --- a/src/Mod/Assembly/App/ConstraintFix.cpp +++ b/src/Mod/Assembly/App/ConstraintFix.cpp @@ -63,10 +63,10 @@ App::DocumentObjectExecReturn* ConstraintFix::execute(void) { return App::DocumentObject::StdReturn; } -void ConstraintFix::init(ItemAssembly* ass) { +void ConstraintFix::init(Assembly::ItemAssembly* ass) { //cant use the base class init as we only need one part - initLink(ass, First); + initLink(First); //get the part Assembly::ItemPart* part = static_cast(First.getValue()); diff --git a/src/Mod/Assembly/App/ConstraintFix.h b/src/Mod/Assembly/App/ConstraintFix.h index 8e2a4c59c42d..6c0f92564cdd 100644 --- a/src/Mod/Assembly/App/ConstraintFix.h +++ b/src/Mod/Assembly/App/ConstraintFix.h @@ -50,7 +50,7 @@ class AssemblyExport ConstraintFix : public Assembly::Constraint } //@} - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintGroup.h b/src/Mod/Assembly/App/ConstraintGroup.h index 8c671ab604dd..efd6c734d837 100644 --- a/src/Mod/Assembly/App/ConstraintGroup.h +++ b/src/Mod/Assembly/App/ConstraintGroup.h @@ -57,7 +57,7 @@ class AssemblyExport ConstraintGroup : public App::DocumentObject } //@} - void init(ItemAssembly* ass); + void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintOrientation.cpp b/src/Mod/Assembly/App/ConstraintOrientation.cpp index 56728dbc9d73..0150a6d8f697 100644 --- a/src/Mod/Assembly/App/ConstraintOrientation.cpp +++ b/src/Mod/Assembly/App/ConstraintOrientation.cpp @@ -66,7 +66,7 @@ App::DocumentObjectExecReturn* ConstraintOrientation::execute(void) { return App::DocumentObject::StdReturn; } -void ConstraintOrientation::init(ItemAssembly* ass) { +void ConstraintOrientation::init(Assembly::ItemAssembly* ass) { //init the parts and geometries Constraint::init(ass); diff --git a/src/Mod/Assembly/App/ConstraintOrientation.h b/src/Mod/Assembly/App/ConstraintOrientation.h index 9c356bca9812..14be368974cf 100644 --- a/src/Mod/Assembly/App/ConstraintOrientation.h +++ b/src/Mod/Assembly/App/ConstraintOrientation.h @@ -51,7 +51,7 @@ class AssemblyExport ConstraintOrientation : public Assembly::Constraint } //@} - virtual void init(ItemAssembly* ass); + virtual void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 44e95c995092..e7f54efffae9 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -33,6 +33,7 @@ #include #include "ItemAssembly.h" +#include "ItemPart.h" #include "ConstraintGroup.h" #include @@ -47,6 +48,7 @@ PROPERTY_SOURCE(Assembly::ItemAssembly, Assembly::Item) ItemAssembly::ItemAssembly() { ADD_PROPERTY(Items,(0)); ADD_PROPERTY(Annotations,(0)); + ADD_PROPERTY(Rigid,(true)); } short ItemAssembly::mustExecute() const { @@ -54,35 +56,30 @@ short ItemAssembly::mustExecute() const { } App::DocumentObjectExecReturn* ItemAssembly::execute(void) { - + try { - + //create a solver and init all child assemblys with subsolvers m_solver = boost::shared_ptr(new Solver); - init(boost::shared_ptr()); - - //get the constraint group and init the constraints - typedef std::vector::const_iterator iter; - - const std::vector& vector = Annotations.getValues(); - for(iter it=vector.begin(); it != vector.end(); it++) { - - if((*it)->getTypeId() == Assembly::ConstraintGroup::getClassTypeId()) - static_cast(*it)->init(this); - }; + m_downstream_placement = Base::Placement(Base::Vector3(0,0,0), Base::Rotation()); + Base::Placement dummy; + initSolver(boost::shared_ptr(), dummy, false); + initConstraints(boost::shared_ptr()); //solve the system m_solver->solve(); - - //Parts have updated automaticly, however, currently there are no signals - //for subsystems. We have to retrieve the product placements therefore by hand - finish(boost::shared_ptr()); - - } catch(dcm::solving_error& e) { + + //Parts have updated automaticly, however, currently there are no signals + //for subsystems. We have to retrieve the product placements therefore by hand + finish(boost::shared_ptr()); + + } + catch(dcm::solving_error& e) { Base::Console().Error("Solver failed with error %i: %s", *boost::get_error_info(e), boost::get_error_info(e)->c_str()); - } catch(dcm::creation_error& e) { + } + catch(dcm::creation_error& e) { Base::Console().Error("Creation failed with error %i: %s", *boost::get_error_info(e), boost::get_error_info(e)->c_str()); @@ -139,7 +136,8 @@ bool ItemAssembly::isParentAssembly(ItemPart* part) { for(iter it=vector.begin(); it != vector.end(); it++) { if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) - if(*it == part) return true; + if(*it == part) + return true; }; return false; @@ -155,12 +153,14 @@ ItemAssembly* ItemAssembly::getParentAssembly(ItemPart* part) { if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) { if(*it == part) return this; - } else if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { - - Assembly::ItemAssembly* assembly = static_cast(*it)->getParentAssembly(part); - if(assembly) - return assembly; } + else + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + Assembly::ItemAssembly* assembly = static_cast(*it)->getParentAssembly(part); + if(assembly) + return assembly; + } }; return (ItemAssembly*)NULL; @@ -178,22 +178,32 @@ std::pair ItemAssembly::getContainingPart(App::Documen if((*it)->getTypeId() == Assembly::ItemPart::getClassTypeId()) { if(static_cast(*it)->holdsObject(obj)) return std::make_pair(static_cast(*it), this); - } else if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { - - std::pair part = static_cast(*it)->getContainingPart(obj); - if(part.first && part.second) - return part; } + else + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + std::pair part = static_cast(*it)->getContainingPart(obj); + if(part.first && part.second) + return part; + } }; return std::pair(NULL, NULL); } -void ItemAssembly::init(boost::shared_ptr parent) { +void ItemAssembly::initSolver(boost::shared_ptr parent, Base::Placement& PL_downstream, bool stopped) { if(parent) { - m_solver = boost::shared_ptr(parent->createSubsystem()); - m_solver->setTransformation(this->Placement.getValue()); + if(Rigid.getValue() || stopped) { + m_solver = boost::shared_ptr(parent->createSubsystem()); + m_solver->setTransformation(this->Placement.getValue()); + stopped = true; //all below belongs to this rigid group + } + else { + m_solver = parent; + PL_downstream *= this->Placement.getValue(); + m_downstream_placement = PL_downstream; + } } typedef std::vector::const_iterator iter; @@ -203,19 +213,45 @@ void ItemAssembly::init(boost::shared_ptr parent) { if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { - static_cast(*it)->init(m_solver); + static_cast(*it)->initSolver(m_solver, PL_downstream, stopped); } }; } +void ItemAssembly::initConstraints(boost::shared_ptr parent) { + + + if(!parent || !Rigid.getValue()) { + //get the constraint group and init the constraints + typedef std::vector::const_iterator iter; + + const std::vector& vector = Annotations.getValues(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if((*it)->getTypeId() == Assembly::ConstraintGroup::getClassTypeId()) + static_cast(*it)->init(this); + }; + + // iterate down as long as a non-rigid subsystem exists + const std::vector& vector2 = Items.getValues(); + for(iter it=vector2.begin(); it != vector2.end(); it++) { + + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) + static_cast(*it)->initConstraints(m_solver); + + }; + } +} + //no signals for subsystems, we need to extract the placement by hand void ItemAssembly::finish(boost::shared_ptr parent) { - if(parent) { - Base::Placement p = m_solver->getTransformation(); - this->Placement.setValue(p); + if(parent && Rigid.getValue()) { + Base::Placement p = m_solver->getTransformation(); + this->Placement.setValue(p); } + typedef std::vector::const_iterator iter; const std::vector& vector = Items.getValues(); @@ -226,6 +262,7 @@ void ItemAssembly::finish(boost::shared_ptr parent) { static_cast(*it)->finish(m_solver); } }; + } diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 9a7c2a2cc743..37912d0fea72 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -28,11 +28,12 @@ #include "Item.h" #include "Solver.h" -#include "ItemPart.h" namespace Assembly { +class ItemPart; + class AssemblyExport ItemAssembly : public Assembly::Item { PROPERTY_HEADER(Assembly::ItemAssembly); @@ -42,6 +43,7 @@ class AssemblyExport ItemAssembly : public Assembly::Item App::PropertyLinkList Items; App::PropertyLinkList Annotations; + App::PropertyBool Rigid; /** @name methods override feature */ //@{ @@ -61,10 +63,20 @@ class AssemblyExport ItemAssembly : public Assembly::Item ItemAssembly* getParentAssembly(ItemPart* part); std::pair< ItemPart*, ItemAssembly* > getContainingPart(App::DocumentObject* obj); - void init(boost::shared_ptr parent); + + //create a new solver for this assembly and initalise all downstream itemassemblys either with a + //subsystem (if they are rigid) or with this solver plus the downstream placement + void initSolver(boost::shared_ptr parent, Base::Placement& pl_downstream, bool stopped); + + //initialise the oen constraint group and go downstream as long as non-rigid itemassemblys exist, + //which need to be initialised too + void initConstraints(boost::shared_ptr parent); + + //read the downstream itemassemblys and set their placement to the propertyplacement void finish(boost::shared_ptr parent); boost::shared_ptr m_solver; + Base::Placement m_downstream_placement; }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ItemPart.cpp b/src/Mod/Assembly/App/ItemPart.cpp index f138668e669e..ee3a67d3eb1f 100644 --- a/src/Mod/Assembly/App/ItemPart.cpp +++ b/src/Mod/Assembly/App/ItemPart.cpp @@ -29,6 +29,7 @@ #include #include "ItemPart.h" +#include "ItemAssembly.h" #include #include #include @@ -46,47 +47,47 @@ using namespace Assembly; namespace Assembly { +struct AssemblyItemException : std::exception { + const char* what() const throw() { return "Assembly items are in wrong structure";} +}; + PROPERTY_SOURCE(Assembly::ItemPart, Assembly::Item) -ItemPart::ItemPart() -{ - ADD_PROPERTY(Model, (0)); +ItemPart::ItemPart() { + ADD_PROPERTY(Model, (0)); ADD_PROPERTY(Annotation,(0)); } -short ItemPart::mustExecute() const -{ +short ItemPart::mustExecute() const { //if (Sketch.isTouched() || // Length.isTouched()) // return 1; return 0; } -App::DocumentObjectExecReturn *ItemPart::execute(void) -{ - this->touch(); - return App::DocumentObject::StdReturn; +App::DocumentObjectExecReturn* ItemPart::execute(void) { + + this->touch(); + return App::DocumentObject::StdReturn; } -TopoDS_Shape ItemPart::getShape(void) const -{ +TopoDS_Shape ItemPart::getShape(void) const { App::DocumentObject* obj = Model.getValue(); - if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + if(obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { return static_cast(obj)->Shape.getValue(); } return TopoDS_Shape(); } -PyObject *ItemPart::getPyObject(void) -{ - if (PythonObject.is(Py::_None())){ +PyObject* ItemPart::getPyObject(void) { + if(PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new ItemPartPy(this),true); } - return Py::new_reference_to(PythonObject); + return Py::new_reference_to(PythonObject); } bool ItemPart::holdsObject(App::DocumentObject* obj) const { @@ -94,66 +95,114 @@ bool ItemPart::holdsObject(App::DocumentObject* obj) const { //get the body object and the relevant model list Part::BodyBase* base = static_cast(Model.getValue()); const std::vector& vector = base->Model.getValues(); - + //check if it holds the relevant document object return std::find(vector.begin(), vector.end(), obj)!=vector.end(); } void ItemPart::setCalculatedPlacement(boost::shared_ptr< Part3D > part) { - //part is the same as m_part, so it doasn't matter which one we use + //part is the same as m_part, so it doasn't matter which one we use Base::Placement p = dcm::get(part); - Placement.setValue(p); + + ItemAssembly* ass = getParentAssembly(); + if(!ass) + throw AssemblyItemException(); + + if(ass->Rigid.getValue()) + Placement.setValue(p); + else + Placement.setValue(ass->m_downstream_placement.inverse()*p); } +ItemAssembly* ItemPart::getParentAssembly() { + + typedef std::vector::const_iterator iter; + + const std::vector& vector = getInList(); + for(iter it=vector.begin(); it != vector.end(); it++) { + + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) + return static_cast(*it); + }; + + return (ItemAssembly*)NULL; +} + +void ItemPart::ensureInitialisation() { + + ItemAssembly* ass = getParentAssembly(); + if(!ass) + throw AssemblyItemException(); + + boost::shared_ptr solver = ass->m_solver; + if(!solver) + throw AssemblyItemException(); + + if(!solver->hasPart(Uid.getValueStr())) { + + //if the assembly is not rigid it was not added to the solver, so we need to incorporate its placement + if(ass->Rigid.getValue()) { + m_part = solver->createPart(Placement.getValue(), Uid.getValueStr()); + } + else { + m_part = solver->createPart(ass->m_downstream_placement*Placement.getValue(), Uid.getValueStr()); + } + m_part->connectSignal(boost::bind(&ItemPart::setCalculatedPlacement, this, _1)); + }; +} + + +boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) { -boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) -{ - //check if the item is initialized - if(!m_part) - return boost::shared_ptr< Geometry3D >(); - + if(!m_part) + return boost::shared_ptr< Geometry3D >(); + boost::shared_ptr geometry; if(m_part->hasGeometry3D(Type)) { return m_part->getGeometry3D(Type); - } else { - Part::TopoShape ts; - App::DocumentObject* obj = Model.getValue(); + } + else { + Part::TopoShape ts; + App::DocumentObject* obj = Model.getValue(); - if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - ts = static_cast(obj)->Shape.getShape(); - } - else return boost::shared_ptr< Geometry3D >(); - - TopoDS_Shape s = ts.getSubShape(Type); + if(obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + ts = static_cast(obj)->Shape.getShape(); + } + else + return boost::shared_ptr< Geometry3D >(); + + TopoDS_Shape s = ts.getSubShape(Type); if(s.ShapeType() == TopAbs_FACE) { TopoDS_Face face = TopoDS::Face(s); BRepAdaptor_Surface surface(face); switch(surface.GetType()) { - case GeomAbs_Plane: { - gp_Pln plane = surface.Plane(); - if(face.Orientation()==TopAbs_REVERSED) { - gp_Dir dir = plane.Axis().Direction(); - plane = gp_Pln(plane.Location(), dir.Reversed()); - } - geometry = m_part->addGeometry3D(plane, Type, dcm::Local); - break; + case GeomAbs_Plane: { + gp_Pln plane = surface.Plane(); + if(face.Orientation()==TopAbs_REVERSED) { + gp_Dir dir = plane.Axis().Direction(); + plane = gp_Pln(plane.Location(), dir.Reversed()); } - case GeomAbs_Cylinder: { - gp_Cylinder cyl = surface.Cylinder(); - geometry = m_part->addGeometry3D(cyl, Type, dcm::Local); - break; - } - default: - Base::Console().Message("Unsuported Surface Geometrie Type at selection\n"); - return boost::shared_ptr< Geometry3D >(); + geometry = m_part->addGeometry3D(plane, Type, dcm::Local); + break; + } + case GeomAbs_Cylinder: { + gp_Cylinder cyl = surface.Cylinder(); + geometry = m_part->addGeometry3D(cyl, Type, dcm::Local); + break; + } + default: + Base::Console().Message("Unsuported Surface Geometrie Type at selection\n"); + return boost::shared_ptr< Geometry3D >(); } - } else if(s.ShapeType() == TopAbs_EDGE) { - TopoDS_Edge edge = TopoDS::Edge(s); - BRepAdaptor_Curve curve(edge); - switch(curve.GetType()) { + } + else + if(s.ShapeType() == TopAbs_EDGE) { + TopoDS_Edge edge = TopoDS::Edge(s); + BRepAdaptor_Curve curve(edge); + switch(curve.GetType()) { case GeomAbs_Line: { gp_Lin line = curve.Line(); geometry = m_part->addGeometry3D(line, Type, dcm::Local); @@ -162,20 +211,23 @@ boost::shared_ptr< Geometry3D > ItemPart::getGeometry3D(const char* Type) default: Base::Console().Message("Unsuported Curve Geometrie Type at selection \n"); return boost::shared_ptr< Geometry3D >(); - } + } - } else if(s.ShapeType() == TopAbs_VERTEX) { - TopoDS_Vertex v1 = TopoDS::Vertex(s); - gp_Pnt point = BRep_Tool::Pnt(v1); - geometry = m_part->addGeometry3D(point, Type, dcm::Local); + } + else + if(s.ShapeType() == TopAbs_VERTEX) { + TopoDS_Vertex v1 = TopoDS::Vertex(s); + gp_Pnt point = BRep_Tool::Pnt(v1); + geometry = m_part->addGeometry3D(point, Type, dcm::Local); - } else { - Base::Console().Message("Unsuported Topologie Type at selection\n"); - return boost::shared_ptr< Geometry3D >(); - } + } + else { + Base::Console().Message("Unsuported Topologie Type at selection\n"); + return boost::shared_ptr< Geometry3D >(); + } }; - + return geometry; } -} \ No newline at end of file +} diff --git a/src/Mod/Assembly/App/ItemPart.h b/src/Mod/Assembly/App/ItemPart.h index c19e82740319..ac6a3e03096f 100644 --- a/src/Mod/Assembly/App/ItemPart.h +++ b/src/Mod/Assembly/App/ItemPart.h @@ -32,6 +32,8 @@ namespace Assembly { +class ItemAssembly; + class AssemblyExport ItemPart : public Assembly::Item { PROPERTY_HEADER(Assembly::ItemPart); @@ -57,6 +59,8 @@ class AssemblyExport ItemPart : public Assembly::Item virtual TopoDS_Shape getShape(void) const; bool holdsObject(App::DocumentObject* obj) const; + ItemAssembly* getParentAssembly(); + void ensureInitialisation(); boost::shared_ptr m_part; virtual boost::shared_ptr getGeometry3D(const char* Type ); diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index 98653c51c4fe..ead8bd81b8b0 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -35,6 +35,7 @@ #include "ui_AlignmentDialog.h" #include +#include #include diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index b26e2cc55c4f..b93bda78385f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #include "ViewProviderConstraint.h" #include "Mod/Assembly/App/Constraint.h" +#include "Mod/Assembly/App/ItemPart.h" #include #include #include diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp index 5c673ac9f4f5..5e03f755b6b7 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #include "ViewProviderConstraintFix.h" #include "Mod/Assembly/App/ConstraintFix.h" +#include "Mod/Assembly/App/ItemPart.h" #include using namespace AssemblyGui; From f61ae2e90ca6b33dacf8ae48bc37196d47d904b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 13 Aug 2013 17:03:59 +0000 Subject: [PATCH 168/664] allow to set rigid property via context menu --- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 34 +++++++++++++++++-- src/Mod/Assembly/Gui/ViewProviderAssembly.h | 5 +++ .../Assembly/Gui/ViewProviderConstraint.cpp | 12 +++++-- src/Mod/Assembly/Gui/ViewProviderConstraint.h | 2 ++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index ca1d578d31ef..8cdb3fe5713f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -52,7 +52,7 @@ bool ViewProviderItemAssembly::doubleClicked(void) return true; } -void ViewProviderItemAssembly::attach(App::DocumentObject *pcFeat) +void ViewProviderItemAssembly::attach(App::DocumentObject* pcFeat) { // call parent attach method ViewProviderGeometryObject::attach(pcFeat); @@ -64,10 +64,10 @@ void ViewProviderItemAssembly::attach(App::DocumentObject *pcFeat) void ViewProviderItemAssembly::setDisplayMode(const char* ModeName) { - if ( strcmp("Main",ModeName)==0 ) + if(strcmp("Main",ModeName)==0) setDisplayMaskMode("Main"); - ViewProviderGeometryObject::setDisplayMode( ModeName ); + ViewProviderGeometryObject::setDisplayMode(ModeName); } std::vector ViewProviderItemAssembly::getDisplayModes(void) const @@ -98,3 +98,31 @@ std::vector ViewProviderItemAssembly::claimChildren3D(void return static_cast(getObject())->Items.getValues(); } + +void ViewProviderItemAssembly::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + ViewProviderItem::setupContextMenu(menu, receiver, member); // call the base class + + QAction* toggle = menu->addAction(QObject::tr("Rigid subassembly"), receiver, member); + toggle->setData(QVariant(1000)); // identifier + toggle->setCheckable(true); + toggle->setToolTip(QObject::tr("Set if the subassembly shall be solved as on part (rigid) or if all parts of this assembly are solved for themselfe.")); + toggle->setStatusTip(QObject::tr("Set if the subassembly shall be solved as on part (rigid) or if all parts of this assembly are solved for themself.")); + bool prop = static_cast(getObject())->Rigid.getValue(); + toggle->setChecked(prop); +} + +bool ViewProviderItemAssembly::setEdit(int ModNum) +{ + if(ModNum == 1000) { // identifier + Gui::Command::openCommand("Change subassembly solving behaviour"); + if(!static_cast(getObject())->Rigid.getValue()) + Gui::Command::doCommand(Gui::Command::Doc,"FreeCAD.getDocument(\"%s\").getObject(\"%s\").Rigid = True",getObject()->getDocument()->getName(), getObject()->getNameInDocument()); + else + Gui::Command::doCommand(Gui::Command::Doc,"FreeCAD.getDocument(\"%s\").getObject(\"%s\").Rigid = False",getObject()->getDocument()->getName(), getObject()->getNameInDocument()); + + Gui::Command::commitCommand(); + return false; + } + return ViewProviderItem::setEdit(ModNum); // call the base class +} diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index 1e3fe40ccff3..1e30ef327a41 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -25,6 +25,8 @@ #define ASSEMBLYGUI_ViewProviderAssembly_H #include "ViewProvider.h" +#include +#include namespace AssemblyGui { @@ -48,6 +50,9 @@ class AssemblyGuiExport ViewProviderItemAssembly : public AssemblyGui::ViewProvi virtual std::vector claimChildren(void)const; virtual std::vector claimChildren3D(void)const; + + virtual void setupContextMenu(QMenu* menu, QObject* receiver, const char* member); + virtual bool setEdit(int ModNum); }; diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index b93bda78385f..4ea41bb4a021 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -170,9 +170,17 @@ void ViewProviderConstraint::attach(App::DocumentObject* pcFeat) internal_vp.setDisplayMM("Flat Lines"); } +void ViewProviderConstraint::update(const App::Property* prop) { -void ViewProviderConstraint::updateData(const App::Property* prop) -{ + if(Visibility.getValue() && m_selected) { + + draw(); + } + ViewProviderPart::update(prop); +} + + +void ViewProviderConstraint::updateData(const App::Property* prop) { if(Visibility.getValue() && m_selected) { draw(); diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h index cedcfcfef04e..9371a3f1c1f1 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -70,6 +70,8 @@ class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart //annotation nodes virtual void attach(App::DocumentObject* pcObj); + //update is for visual only + virtual void update(const App::Property*); //needs to be overridden as this viewprovider dos not represent a Part::Feature virtual void updateData(const App::Property*); //needs to be overridden as this viewprovider dos not represent a Part::Feature From 9a50535a4bf684a326fc1f5f703652d3f95e19ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 13 Aug 2013 18:47:58 +0000 Subject: [PATCH 169/664] adopt correct default colors and avoid crash due to context menu --- src/Mod/Assembly/Gui/ViewProviderConstraint.cpp | 13 +++++++++---- src/Mod/Assembly/Gui/ViewProviderConstraint.h | 3 +++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index 4ea41bb4a021..bc00eb8aa489 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -43,13 +43,13 @@ ViewProviderConstraintInternal::ViewProviderConstraintInternal() { //constraint entiti color ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 421075455UL); // dark grey (25,25,25) + unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 56319UL); float r, g, b; r = ((scol >> 24) & 0xff) / 255.0; g = ((scol >> 16) & 0xff) / 255.0; b = ((scol >> 8) & 0xff) / 255.0; - long unsigned ccol = hGrp->GetUnsigned("FullyConstrainedColor", 421075455UL); + long unsigned ccol = hGrp->GetUnsigned("FullyConstrainedColor", 16711935UL); float r2, g2, b2; r2 = ((ccol >> 24) & 0xff) / 255.0; g2 = ((ccol >> 16) & 0xff) / 255.0; @@ -112,13 +112,13 @@ ViewProviderConstraint::ViewProviderConstraint() : m_selected(false) //constraint entiti color ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 421075455UL); // dark grey (25,25,25) + unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 56319UL); float r, g, b; r = ((scol >> 24) & 0xff) / 255.0; g = ((scol >> 16) & 0xff) / 255.0; b = ((scol >> 8) & 0xff) / 255.0; - long unsigned ccol = hGrp->GetUnsigned("FullyConstrainedColor", 421075455UL); + long unsigned ccol = hGrp->GetUnsigned("FullyConstrainedColor", 16711935UL); float r2, g2, b2; r2 = ((ccol >> 24) & 0xff) / 255.0; g2 = ((ccol >> 16) & 0xff) / 255.0; @@ -367,3 +367,8 @@ TopoDS_Shape ViewProviderConstraint::getConstraintShape(int link) return s2; }; } + +void ViewProviderConstraint::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + ViewProviderDocumentObject::setupContextMenu(menu, receiver, member); +} diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h index 9371a3f1c1f1..2e963bd652c4 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -83,6 +83,9 @@ class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart //needs to be overridden as we use the modeselection node for on and off and not for //hide and show in the normal way virtual bool isShow(void) const; + + //avoid unneeded context menu entrys + virtual void setupContextMenu(QMenu* menu, QObject* receiver, const char* member); private: //we need two seperate visual representations, as both constraint parts have different From 3dafb038b2c9a119225821366e06de13383953b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 13 Aug 2013 18:56:54 +0000 Subject: [PATCH 170/664] remove unneeded display modes from viewprovider --- src/Mod/Assembly/Gui/ViewProviderConstraint.cpp | 15 +++++++++++++++ src/Mod/Assembly/Gui/ViewProviderConstraint.h | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index bc00eb8aa489..19445eba2156 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -103,6 +103,21 @@ void ViewProviderConstraintInternal::switch_node(bool onoff) pcModeSwitch->whichChild = -1; } +void ViewProviderConstraint::setDisplayMode(const char* ModeName) +{ + setDisplayMaskMode("Flat Lines"); + +} + +std::vector ViewProviderConstraint::getDisplayModes(void) const +{ + std::vector StrList; + + // add your own mode + StrList.push_back("Flat Lines"); + return StrList; +} + PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraint, PartGui::ViewProviderPart) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h index 2e963bd652c4..f343b7cc24ea 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -87,6 +87,10 @@ class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart //avoid unneeded context menu entrys virtual void setupContextMenu(QMenu* menu, QObject* receiver, const char* member); + //only flat lines supported + virtual void setDisplayMode(const char* ModeName); + virtual std::vector getDisplayModes(void) const; + private: //we need two seperate visual representations, as both constraint parts have different //placements. From 5ce6c68a572ef36b714e16541b1181cc06ed4750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 13 Aug 2013 19:05:33 +0000 Subject: [PATCH 171/664] avoid transformation of highlighted constraint --- src/Mod/Assembly/Gui/ViewProviderConstraint.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h index f343b7cc24ea..7164968b922c 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -91,6 +91,9 @@ class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart virtual void setDisplayMode(const char* ModeName); virtual std::vector getDisplayModes(void) const; + //avoid transformation on doouble click + virtual bool doubleClicked(void) {return true;}; + private: //we need two seperate visual representations, as both constraint parts have different //placements. From 483357de7766935efb09005f84a3f13415a09376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 15 Aug 2013 17:12:39 +0000 Subject: [PATCH 172/664] set solving precission to 1e-8 --- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 392dc43da0f2..8094e44bda63 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -66,7 +66,7 @@ struct Dogleg { typedef typename Kernel::number_type number_type; number_type tolg, tolx, tolf; - Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-6) { + Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-8) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); From 30e8fc7b8c57333afc592e88aacf57a43aa0f538 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 15 Aug 2013 17:48:44 +0000 Subject: [PATCH 173/664] revert solving precission to 1e-6 dou to too much cases failing --- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 8094e44bda63..392dc43da0f2 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -66,7 +66,7 @@ struct Dogleg { typedef typename Kernel::number_type number_type; number_type tolg, tolx, tolf; - Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-8) { + Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-6) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); From 6a6997087f7f29005044d68972fe596a4e31fb81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 1 Sep 2013 18:01:06 +0000 Subject: [PATCH 174/664] windows: add type specifier --- .../App/opendcm/modulePart/module.hpp | 89 ++++++++++--------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp index 3e13ec294c0e..38457fec11b7 100644 --- a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -98,9 +98,9 @@ struct ModulePart { } Transform& m_transform; }; - - //collect all clustergraph upstream cluster transforms - void transform_traverse(Transform& t, boost::shared_ptr c); + + //collect all clustergraph upstream cluster transforms + void transform_traverse(Transform& t, boost::shared_ptr c); public: using Object::m_system; @@ -116,14 +116,14 @@ struct ModulePart { template void set(const T& geometry); - - //access the parts transformation - template + + //access the parts transformation + template T& get(); - - //get the transformation from part local to overall global. In multi layer systems - //this means the successive transformation from this part to the toplevel cluster - template + + //get the transformation from part local to overall global. In multi layer systems + //this means the successive transformation from this part to the toplevel cluster + template T getGlobal(); virtual boost::shared_ptr clone(Sys& newSys); @@ -136,9 +136,9 @@ struct ModulePart { void finishCalculation(); void fix(bool fix_value); - public: - //we hold a transform and need therefore a aligned new operator - EIGEN_MAKE_ALIGNED_OPERATOR_NEW + public: + //we hold a transform and need therefore a aligned new operator + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; struct Part_id : public Part_base { @@ -169,9 +169,9 @@ struct ModulePart { friend struct PrepareCluster; friend struct EvaljuateCluster; - public: - //we hold a transform and need therefore a aligned new operator - EIGEN_MAKE_ALIGNED_OPERATOR_NEW + public: + //we hold a transform and need therefore a aligned new operator + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; @@ -281,16 +281,16 @@ ModulePart::type::Part_base::Part_base(const T& geometry, Sys #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Part3D")); -#endif - +#endif + (typename geometry_traits::modell()).template extract::accessor >(geometry, m_transform); cluster->template setClusterProperty(false); - + //the the clustermath transform m_cluster->template getClusterProperty().getTransform() = m_transform; - + #ifdef USE_LOGGING BOOST_LOG(log) << "Init: "< typename ModulePart::template type::Part_base::Geom ModulePart::type::Part_base::addGeometry3D(const T& geom, CoordinateFrame frame) { Geom g(new Geometry3D(geom, *m_system)); - + if(frame == Local) { - //we need to collect all transforms up to this part! - Transform t; - transform_traverse(t, m_cluster); - - g->transform(t); + //we need to collect all transforms up to this part! + Transform t; + transform_traverse(t, m_cluster); + + g->transform(t); } fusion::vector res = m_cluster->addVertex(); @@ -328,15 +328,15 @@ ModulePart::type::Part_base::addGeometry3D(const T& geom, Coo template template -void ModulePart::type::Part_base::transform_traverse(ModulePart::type::Part_base::Transform& t, - boost::shared_ptr::type::Part_base::Cluster> c) { - +void ModulePart::type::Part_base::transform_traverse(typename ModulePart::template type::Part_base::Transform& t, + boost::shared_ptr::template type::Part_base::Cluster> c) { + t *= c->template getClusterProperty().m_transform; - + if(c->isRoot()) - return; - - transform_traverse(t, c->parent()); + return; + + transform_traverse(t, c->parent()); } template @@ -346,7 +346,7 @@ void ModulePart::type::Part_base::set(const T& geometry) { Part_base::m_geometry = geometry; (typename geometry_traits::modell()).template extract::accessor >(geometry, Part_base::m_transform); - + //set the clustermath transform m_cluster->template getClusterProperty().getTransform() = m_transform; }; @@ -367,12 +367,12 @@ T ModulePart::type::Part_base::getGlobal() { //get the successive transform Transform t; transform_traverse(t, m_cluster); - + //put it into the user type T ut; (typename geometry_traits::modell()).template inject::accessor >(ut, t); - + typename geometry_traits::accessor >(ut, t); + return ut; }; @@ -403,7 +403,7 @@ ModulePart::type::Part_base::clone(Sys& newSys) { template template void ModulePart::type::Part_base::finishCalculation() { - + m_transform.normalize(); apply_visitor vis(m_transform); apply(vis); @@ -411,7 +411,7 @@ void ModulePart::type::Part_base::finishCalculation() { #ifdef USE_LOGGING BOOST_LOG(log) << "New Value: "<(((Part*)this)->shared_from_this()); }; @@ -453,7 +453,8 @@ template template bool ModulePart::type::Part_id::hasGeometry3D(Identifier id) { typename Part_base::Geom g = Part_base::m_system->getGeometry3D(id); - if(!g) return false; + if(!g) + return false; //get the global vertex and check if it is a child of the part cluster GlobalVertex v = g->template getProperty(); @@ -505,7 +506,7 @@ ModulePart::type::inheriter_base::createPart(const T& geometr std::pair, LocalVertex> res = m_this->m_cluster->createCluster(); Partptr p(new Part(geometry, * ((Sys*) this), res.first)); - m_this->m_cluster->template setObject (res.second, p); + m_this->m_cluster->template setObject (res.second, p); m_this->push_back(p); res.first->template setClusterProperty(clusterPart); @@ -566,7 +567,8 @@ ModulePart::type::inheriter_id::createPart(const T& geometry, template template bool ModulePart::type::inheriter_id::hasPart(Identifier id) { - if(getPart(id)) return true; + if(getPart(id)) + return true; return false; }; @@ -577,7 +579,8 @@ ModulePart::type::inheriter_id::getPart(Identifier id) { std::vector< Partptr >& vec = inheriter_base::m_this->template objectVector(); typedef typename std::vector::iterator iter; for(iter it=vec.begin(); it!=vec.end(); it++) { - if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + if(compare_traits::compare((*it)->getIdentifier(), id)) + return *it; }; return Partptr(); }; From 5d39df88ee02be8bcb1ca63b92d6df38bc7b707c Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 22 Aug 2013 19:50:50 +0200 Subject: [PATCH 175/664] Prevent user from selecting a sketch plane that is not in the active body --- src/Mod/PartDesign/Gui/Command.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 47cbfecd96e5..8361bfd1683c 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -767,9 +767,10 @@ void CmdPartDesignNewSketch::activated(int iMsg) else if (FaceFilter.match() || PlaneFilter.match()) { // get the selected object std::string supportString; + Part::Feature* feat; if (FaceFilter.match()) { - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + feat = static_cast(FaceFilter.Result[0][0].getObject()); // FIXME: Reject or warn about feature that is outside of active body, and feature // that comes after the current insert point (Tip) const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); @@ -780,7 +781,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) return; } // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getValue(); + const Part::TopoShape &shape = feat->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); const TopoDS_Face& face = TopoDS::Face(sh); if (face.IsNull()){ @@ -799,9 +800,19 @@ void CmdPartDesignNewSketch::activated(int iMsg) supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); } else { - Part::Feature *plane = static_cast(PlaneFilter.Result[0][0].getObject()); + feat = static_cast(PlaneFilter.Result[0][0].getObject()); // TODO: Find out whether the user picked front or back of this plane - supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", ['front'])"; + supportString = std::string("(App.activeDocument().") + feat->getNameInDocument() + ", ['front'])"; + } + + if (!pcActiveBody->hasFeature(feat)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from other body"), + QObject::tr("You have to select a face or plane from the active body!")); + return; + } else if (pcActiveBody->isAfterTip(feat)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from inactive feature"), + QObject::tr("You have to select a face or plane before the current insert point, or move the insert point")); + return; } // create Sketch on Face or Plane @@ -842,12 +853,11 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (base) continue; // Check whether this plane belongs to the active body - PartDesign::Body* body = PartDesignGui::getBody(); - if (!body->hasFeature(*p)) { + if (!pcActiveBody->hasFeature(*p)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; } else { - if (body->isAfterTip(*p)) + if (pcActiveBody->isAfterTip(*p)) status.push_back(PartDesignGui::FeaturePickDialog::afterTip); continue; } From f9b0e5908ab8adb38c07e1731301fc034caf7e3f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 22 Aug 2013 21:08:21 +0200 Subject: [PATCH 176/664] Allow transforming a Pattern feature into a MultiTransform feature --- src/Mod/PartDesign/App/Body.cpp | 15 + src/Mod/PartDesign/App/Body.h | 3 + src/Mod/PartDesign/Gui/Command.cpp | 93 ++- src/Mod/PartDesign/Gui/Command.cpp.orig | 741 ++++++++++++------ .../Gui/TaskLinearPatternParameters.cpp | 2 +- .../PartDesign/Gui/TaskMirroredParameters.cpp | 2 +- .../Gui/TaskMultiTransformParameters.cpp | 2 +- .../Gui/TaskPolarPatternParameters.cpp | 2 +- .../Gui/TaskTransformedParameters.cpp | 34 +- .../Gui/TaskTransformedParameters.h | 4 +- src/Mod/PartDesign/Gui/Workbench.cpp | 10 +- 11 files changed, 631 insertions(+), 277 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 7b33bc7fb762..0e65ba269950 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -126,6 +126,21 @@ const Part::TopoShape Body::getTipShape() return static_cast(link)->Shape.getShape(); } +App::DocumentObject* Body::getPrevFeature(App::DocumentObject *start) const +{ + std::vector features = Model.getValues(); + if (features.empty()) return NULL; + App::DocumentObject* st = (start == NULL ? Tip.getValue() : start); + if (st == NULL) + return st; // Tip is NULL + + std::vector::iterator it = std::find(features.begin(), features.end(), st); + if (it == features.end()) return NULL; // Invalid start object + + it--; + return *it; +} + App::DocumentObject* Body::getPrevSolidFeature(App::DocumentObject *start, const bool inclusive) { std::vector features = Model.getValues(); diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index 0d3d0e1ee3f2..a07f0111263b 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -58,6 +58,9 @@ class PartDesignExport Body : public Part::BodyBase /// Get the tip shape const Part::TopoShape getTipShape(); + /// Return the previous feature + App::DocumentObject* getPrevFeature(App::DocumentObject *start = NULL) const; + /** * Return the solid feature before the given feature, or before the Tip feature * That is, sketches and datum features are skipped diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 8361bfd1683c..c25290ed59da 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -70,6 +70,8 @@ #include #include #include +#include +#include #include #include #include @@ -1741,7 +1743,7 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() { sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); - sMenuText = QT_TR_NOOP("MultiTransform"); + sMenuText = QT_TR_NOOP("Create MultiTransform"); sToolTipText = QT_TR_NOOP("Create a multitransform feature"); sWhatsThis = "PartDesign_MultiTransform"; sStatusTip = sToolTipText; @@ -1750,28 +1752,79 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { - std::string FeatName, selNames; + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) return; + std::vector features; - std::vector selList; - prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); - if (features.empty()) - return; - PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); - if (!pcActiveBody) - return; - updateActive(); - doCommand(Doc,selNames.c_str()); - - // Make sure the user isn't presented with an empty screen because no transformations are defined yet... - App::DocumentObject* prevSolid = pcActiveBody->getPrevSolidFeature(NULL, true); - if (prevSolid != NULL) { - Part::Feature* feat = static_cast(prevSolid); - doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", - FeatName.c_str(), feat->getNameInDocument()); - } + // Check if a Transformed feature has been selected, convert it to MultiTransform + features = getSelection().getObjectsOfType(PartDesign::Transformed::getClassTypeId()); + if (!features.empty()) { + // Throw out MultiTransform features, we don't want to nest them + for (std::vector::iterator f = features.begin(); f != features.end(); ) { + if ((*f)->getTypeId().isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) + f = features.erase(f); + else + f++; + } - finishFeature(this, FeatName); + if (features.empty()) return; + // Note: If multiple Transformed features were selected, only the first one is used + PartDesign::Transformed* trFeat = static_cast(features.front()); + + // Move the insert point back one feature + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + App::DocumentObject* prevFeature = pcActiveBody->getPrevFeature(trFeat); + Gui::Selection().clearSelection(); + if (prevFeature != NULL) + Gui::Selection().addSelection(prevFeature->getDocument()->getName(), prevFeature->getNameInDocument()); + openCommand("Convert to MultiTransform feature"); + doCommand(Gui, "FreeCADGui.runCommand('PartDesign_MoveTip')"); + + // Remove the Transformed feature from the Body + doCommand(Doc, "App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), trFeat->getNameInDocument()); + + // Create a MultiTransform feature and move the Transformed feature inside it + std::string FeatName = getUniqueObjectName("MultiTransform"); + doCommand(Doc, "App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")", FeatName.c_str()); + doCommand(Doc, "App.activeDocument().%s.Originals = App.activeDocument().%s.Originals", FeatName.c_str(), trFeat->getNameInDocument()); + doCommand(Doc, "App.activeDocument().%s.Originals = []", trFeat->getNameInDocument()); + doCommand(Doc, "App.activeDocument().%s.Transformations = [App.activeDocument().%s]", FeatName.c_str(), trFeat->getNameInDocument()); + + // Add the MultiTransform into the Body at the current insert point + finishFeature(this, FeatName); + + // Restore the insert point + if (oldTip != trFeat) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); + } // otherwise the insert point remains at the new MultiTransform, which is fine + } else { + std::string FeatName, selNames; + std::vector selList; + prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); + if (features.empty()) + return; + + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) + return; + updateActive(); + doCommand(Doc,selNames.c_str()); + + // Make sure the user isn't presented with an empty screen because no transformations are defined yet... + App::DocumentObject* prevSolid = pcActiveBody->getPrevSolidFeature(NULL, true); + if (prevSolid != NULL) { + Part::Feature* feat = static_cast(prevSolid); + doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", + FeatName.c_str(), feat->getNameInDocument()); + } + + finishFeature(this, FeatName); + } } bool CmdPartDesignMultiTransform::isActive(void) diff --git a/src/Mod/PartDesign/Gui/Command.cpp.orig b/src/Mod/PartDesign/Gui/Command.cpp.orig index e8d3ba8e22cf..0b3d31bffe9a 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp.orig +++ b/src/Mod/PartDesign/Gui/Command.cpp.orig @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -63,21 +64,24 @@ #include #include -#include #include #include #include #include #include #include +#include +#include +#include +#include +#include #include "FeaturePickDialog.h" #include "Workbench.h" using namespace std; - -const char* BasePlaneNames[3] = {"Body_PlaneXY", "Body_PlaneYZ", "Body_PlaneXZ"}; +#include "ReferenceSelection.h" //=========================================================================== // PartDesign_Body @@ -108,7 +112,7 @@ void CmdPartDesignBody::activated(int iMsg) std::vector planes = getDocument()->getObjectsOfType(App::Plane::getClassTypeId()); for (std::vector::const_iterator p = planes.begin(); p != planes.end(); p++) { for (unsigned i = 0; i < 3; i++) { - if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*p)->getNameInDocument()) == 0) { found = true; break; } @@ -118,29 +122,30 @@ void CmdPartDesignBody::activated(int iMsg) if (!found) { // Add the planes ... - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[0]); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XY-Plane'"); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[1]); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[0]); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XY-Plane").toStdString().c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[1]); + doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),-90))"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("XZ-Plane").toStdString().c_str()); + doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", PartDesignGui::BaseplaneNames[2]); doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(0,1,0),90))"); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'YZ-Plane'"); - doCommand(Doc,"App.activeDocument().addObject('App::Plane','%s')", BasePlaneNames[2]); - doCommand(Doc,"App.activeDocument().ActiveObject.Placement = App.Placement(App.Vector(),App.Rotation(App.Vector(1,0,0),90))"); - doCommand(Doc,"App.activeDocument().ActiveObject.Label = 'XZ-Plane'"); + doCommand(Doc,"App.activeDocument().ActiveObject.Label = '%s'", QObject::tr("YZ-Plane").toStdString().c_str()); // ... and put them in the 'Origin' group - doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','Origin')"); + doCommand(Doc,"App.activeDocument().addObject('App::DocumentObjectGroup','%s')", QObject::tr("Origin").toStdString().c_str()); for (unsigned i = 0; i < 3; i++) - doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", BasePlaneNames[i]); + doCommand(Doc,"App.activeDocument().Origin.addObject(App.activeDocument().getObject('%s'))", PartDesignGui::BaseplaneNames[i]); // TODO: Fold the group (is that possible through the Python interface?) } // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Model = []",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Tip = None",FeatName.c_str()); doCommand(Doc,"import PartDesignGui"); - doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.ActiveObject)"); + doCommand(Gui,"PartDesignGui.setActivePart(App.ActiveDocument.%s)", FeatName.c_str()); // Make the "Create sketch" prompt appear in the task panel doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.ActiveObject)"); + doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s)", FeatName.c_str()); updateActive(); } @@ -172,37 +177,289 @@ void CmdPartDesignMoveTip::activated(int iMsg) PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); if(!pcActiveBody) return; + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + App::DocumentObject* selFeature; + + if (features.empty()) { + // Insert at the beginning of this body + selFeature = NULL; + } else { + selFeature = features.front(); + if (selFeature->getTypeId().isDerivedFrom(PartDesign::Body::getClassTypeId())) { + // Insert at the beginning of this body + selFeature = NULL; + } else if (!pcActiveBody->hasFeature(selFeature)) { + // Switch to other body + pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); + if (pcActiveBody != NULL) + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", + pcActiveBody->getNameInDocument()); + else + return; + } + } + + openCommand("Move insert point to selected feature"); + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + if (oldTip != NULL) { + if (!oldTip->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if (prevSolidFeature != NULL) + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + } + + if (selFeature == NULL) { + doCommand(Doc,"App.activeDocument().%s.Tip = None", pcActiveBody->getNameInDocument()); + } else { + doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); + + // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + } + + // TOOD: Hide all datum features after the Tip feature? But the user might have already hidden some and wants to see + // others, so we would have to remember their state somehow +} + +bool CmdPartDesignMoveTip::isActive(void) +{ + return hasActiveDocument(); +} + +//=========================================================================== +// PartDesign_DuplicateSelection +//=========================================================================== + +DEF_STD_CMD_A(CmdPartDesignDuplicateSelection); + +CmdPartDesignDuplicateSelection::CmdPartDesignDuplicateSelection() + :Command("PartDesign_DuplicateSelection") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Duplicate selected object"); + sToolTipText = QT_TR_NOOP("Duplicates the selected object and adds it to the active body"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = ""; +} + +void CmdPartDesignDuplicateSelection::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); if (features.empty()) return; App::DocumentObject* selFeature = features.front(); if (!pcActiveBody->hasFeature(selFeature)) { + // NOTE: We assume all selected features will be in the same document // Switch to other body - pcActiveBody = PartDesign::Body::findBodyOf(selFeature); + pcActiveBody = static_cast(Part::BodyBase::findBodyOf(selFeature)); if (pcActiveBody != NULL) Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", pcActiveBody->getNameInDocument()); + else + return; } - App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", oldTip->getNameInDocument()); - App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); - if (prevSolidFeature != NULL) - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + std::vector beforeFeatures = PartDesignGui::ActiveAppDoc->getObjects(); - openCommand("Move insert point to selected feature"); - doCommand(Doc,"App.activeDocument().%s.Tip = App.activeDocument().%s",pcActiveBody->getNameInDocument(), selFeature->getNameInDocument()); + openCommand("Duplicate a PartDesign object"); + doCommand(Doc,"FreeCADGui.runCommand('Std_DuplicateSelection')"); + + // Find the features that were added + std::vector afterFeatures = PartDesignGui::ActiveAppDoc->getObjects(); + std::vector newFeatures; + std::set_difference(afterFeatures.begin(), afterFeatures.end(), beforeFeatures.begin(), beforeFeatures.end(), + std::back_inserter(newFeatures)); + + for (std::vector::const_iterator f = newFeatures.begin(); f != newFeatures.end(); f++) { + if (PartDesign::Body::isAllowed(*f)) { + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", (*f)->getNameInDocument()); + } + } - // Adjust visibility to show only the Tip feature and (if the Tip feature is not solid) the solid feature prior to the Tip - doCommand(Gui,"Gui.activeDocument().show(\"%s\")", selFeature->getNameInDocument()); - prevSolidFeature = pcActiveBody->getPrevSolidFeature(); + // Adjust visibility of features + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", newFeatures.back()->getNameInDocument()); + App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(); if ((prevSolidFeature != NULL) && !PartDesign::Body::isSolidFeature(selFeature)) doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); } -bool CmdPartDesignMoveTip::isActive(void) +bool CmdPartDesignDuplicateSelection::isActive(void) { - return hasActiveDocument(); + if (getActiveGuiDocument()) + return true; + else + return false; +} + +//=========================================================================== +// PartDesign_MoveFeature +//=========================================================================== + +DEF_STD_CMD_A(CmdPartDesignMoveFeature); + +CmdPartDesignMoveFeature::CmdPartDesignMoveFeature() + :Command("PartDesign_MoveFeature") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Move object to other body"); + sToolTipText = QT_TR_NOOP("Moves the selected object to another body"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = ""; +} + +void CmdPartDesignMoveFeature::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + + // Create a list of all bodies in this part + std::vector bodies = getDocument()->getObjectsOfType(Part::BodyBase::getClassTypeId()); + + // Ask user to select the target body + bool ok; + QStringList items; + for (std::vector::iterator it = bodies.begin(); it != bodies.end(); ++it) + items.push_back(QString::fromUtf8((*it)->Label.getValue())); + QString text = QInputDialog::getItem(Gui::getMainWindow(), + qApp->translate(className(), "Select body"), + qApp->translate(className(), "Select a body from the list"), + items, 0, false, &ok); + if (!ok) return; + int index = items.indexOf(text); + + PartDesign::Body* target = static_cast(bodies[index]); + + openCommand("Move an object"); + + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + // Find body of this feature + Part::BodyBase* source = PartDesign::Body::findBodyOf(*f); + if (source == target) continue; + bool featureIsTip = (source->Tip.getValue() == *f); + + // Remove from source body + doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + source->getNameInDocument(), (*f)->getNameInDocument()); + // Add to target body (always at the Tip) + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + target->getNameInDocument(), (*f)->getNameInDocument()); + // Recompute to update the shape + doCommand(Gui,"App.activeDocument().recompute()"); + + // Adjust visibility of features + if (PartDesign::Body::isSolidFeature(*f)) { + // If we removed the tip of the source body, make the new tip visible + if (featureIsTip) { + App::DocumentObject* prevSolidFeature = source->getPrevSolidFeature(); + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", prevSolidFeature->getNameInDocument()); + } + + // Hide old tip and show new tip (the moved feature) of the target body + App::DocumentObject* prevSolidFeature = target->getPrevSolidFeature(); + doCommand(Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); + doCommand(Gui,"Gui.activeDocument().show(\"%s\")", (*f)->getNameInDocument()); + } + } +} + +bool CmdPartDesignMoveFeature::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + +DEF_STD_CMD_A(CmdPartDesignMoveFeatureInTree); + +CmdPartDesignMoveFeatureInTree::CmdPartDesignMoveFeatureInTree() + :Command("PartDesign_MoveFeatureInTree") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Move object after other object"); + sToolTipText = QT_TR_NOOP("Moves the selected object and insert it after another object"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = ""; +} + +void CmdPartDesignMoveFeatureInTree::activated(int iMsg) +{ + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if(!pcActiveBody) return; + + std::vector features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); + if (features.empty()) return; + + // Create a list of all features in this body + std::vector model = pcActiveBody->Model.getValues(); + + // Ask user to select the target feature + bool ok; + QStringList items; + for (std::vector::iterator it = model.begin(); it != model.end(); ++it) + items.push_back(QString::fromUtf8((*it)->Label.getValue())); + QString text = QInputDialog::getItem(Gui::getMainWindow(), + qApp->translate(className(), "Select feature"), + qApp->translate(className(), "Select a feature from the list"), + items, 0, false, &ok); + if (!ok) return; + int index = items.indexOf(text); + PartDesign::Feature* target = static_cast(model[index]); + + openCommand("Move an object inside tree"); + + // Set insert point at the selected feature + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + Gui::Selection().clearSelection(); + if (target != NULL) + Gui::Selection().addSelection(target->getDocument()->getName(), target->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + + for (std::vector::const_iterator f = features.begin(); f != features.end(); f++) { + if (*f == target) continue; + + // Remove and re-insert the feature from the Body + // Note: If the tip was moved then the new tip will be at the moved position, that is, at the same + // feature as before! + doCommand(Doc,"App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), (*f)->getNameInDocument()); + } + + // Recompute to update the shape + doCommand(Gui,"App.activeDocument().recompute()"); + // Set insert point where it was before + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); +} + +bool CmdPartDesignMoveFeatureInTree::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; } //=========================================================================== @@ -217,19 +474,27 @@ const QString getReferenceString(Gui::Command* cmd) if(!pcActiveBody) return QString::fromAscii(""); Gui::SelectionFilter GeometryFilter("SELECT Part::Feature SUBELEMENT Face COUNT 1"); + Gui::SelectionFilter DatumFilter ("SELECT PartDesign::Plane COUNT 1"); Gui::SelectionFilter EdgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1"); + Gui::SelectionFilter LineFilter ("SELECT PartDesign::Line COUNT 1"); Gui::SelectionFilter VertexFilter ("SELECT Part::Feature SUBELEMENT Vertex COUNT 1"); + Gui::SelectionFilter PointFilter ("SELECT PartDesign::Point COUNT 1"); Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); - Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); + if (EdgeFilter.match()) GeometryFilter = EdgeFilter; else if (VertexFilter.match()) GeometryFilter = VertexFilter; - if (PlaneFilter2.match()) - PlaneFilter = PlaneFilter2; - if (GeometryFilter.match() || PlaneFilter.match()) { + if (LineFilter.match()) + DatumFilter = LineFilter; + else if (PointFilter.match()) + DatumFilter = PointFilter; + else if (PlaneFilter.match()) + DatumFilter = PlaneFilter; + + if (GeometryFilter.match() || DatumFilter.match()) { // get the selected object if (GeometryFilter.match()) { Part::Feature *part = static_cast(GeometryFilter.Result[0][0].getObject()); @@ -258,7 +523,7 @@ const QString getReferenceString(Gui::Command* cmd) return referenceString; } else { - Part::Feature *part = static_cast(PlaneFilter.Result[0][0].getObject()); + Part::Feature *part = static_cast(DatumFilter.Result[0][0].getObject()); return QString::fromAscii("[(App.activeDocument().") + QString::fromAscii(part->getNameInDocument()) + QString::fromAscii(",'')]"); } @@ -281,7 +546,7 @@ const QString getReferenceString(Gui::Command* cmd) // Check whether this reference is a base plane bool base = false; for (unsigned i = 0; i < 3; i++) { - if (strcmp(BasePlaneNames[i], (*r)->getNameInDocument()) == 0) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*r)->getNameInDocument()) == 0) { status.push_back(PartDesignGui::FeaturePickDialog::basePlane); if (chosenRefs.empty()) chosenRefs.push_back(*r); @@ -297,9 +562,8 @@ const QString getReferenceString(Gui::Command* cmd) if (!body->hasFeature(*r)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; - } else { - if (body->isAfterTip(*r)) - status.push_back(PartDesignGui::FeaturePickDialog::afterTip); + } else if (body->isAfterTip(*r)) { + status.push_back(PartDesignGui::FeaturePickDialog::afterTip); continue; } @@ -312,7 +576,7 @@ const QString getReferenceString(Gui::Command* cmd) if (validRefs == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No valid references in this document"), - QObject::tr("Please select a face, edge or vertex")); + QObject::tr("Please select a datum feature, or a face, edge or vertex")); return QString::fromAscii(""); } @@ -325,11 +589,13 @@ const QString getReferenceString(Gui::Command* cmd) Base::Console().Warning("You have chosen more than three references for a datum feature. The extra references are being ignored"); } + // TODO: Allow user to choose front or back of the plane + referenceString = QString::fromAscii("["); for (int i = 0; i < chosenRefs.size(); i++) { referenceString += QString::fromAscii(i == 0 ? "" : ",") + QString::fromAscii("(App.activeDocument().") + QString::fromUtf8(chosenRefs[i]->getNameInDocument()) + - QString::fromAscii(",'')"); + QString::fromAscii(",'front')"); } referenceString += QString::fromAscii("]"); @@ -364,7 +630,8 @@ void CmdPartDesignPlane::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('PartDesign::Plane','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Offset = 0.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Angle = 0.0",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -405,7 +672,6 @@ void CmdPartDesignLine::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('PartDesign::Line','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -446,7 +712,6 @@ void CmdPartDesignPoint::activated(int iMsg) doCommand(Doc,"App.activeDocument().addObject('PartDesign::Point','%s')",FeatName.c_str()); if (refStr.length() > 0) doCommand(Doc,"App.activeDocument().%s.References = %s",FeatName.c_str(),refStr.toStdString().c_str()); - doCommand(Doc,"App.activeDocument().%s.Values = [10.0]",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); doCommand(Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references @@ -491,20 +756,23 @@ void CmdPartDesignNewSketch::activated(int iMsg) Gui::SelectionFilter SketchFilter("SELECT Sketcher::SketchObject COUNT 1"); Gui::SelectionFilter FaceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1"); - Gui::SelectionFilter PlaneFilter1 ("SELECT App::Plane COUNT 1"); + Gui::SelectionFilter PlaneFilter ("SELECT App::Plane COUNT 1"); Gui::SelectionFilter PlaneFilter2 ("SELECT PartDesign::Plane COUNT 1"); + if (PlaneFilter2.match()) + PlaneFilter = PlaneFilter2; if (SketchFilter.match()) { Sketcher::SketchObject *Sketch = static_cast(SketchFilter.Result[0][0].getObject()); openCommand("Edit Sketch"); doCommand(Gui,"Gui.activeDocument().setEdit('%s')",Sketch->getNameInDocument()); } - else if (FaceFilter.match() || PlaneFilter1.match() || PlaneFilter2.match()) { + else if (FaceFilter.match() || PlaneFilter.match()) { // get the selected object std::string supportString; + Part::Feature* feat; if (FaceFilter.match()) { - Part::Feature *part = static_cast(FaceFilter.Result[0][0].getObject()); + feat = static_cast(FaceFilter.Result[0][0].getObject()); // FIXME: Reject or warn about feature that is outside of active body, and feature // that comes after the current insert point (Tip) const std::vector &sub = FaceFilter.Result[0][0].getSubNames(); @@ -515,7 +783,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) return; } // get the selected sub shape (a Face) - const Part::TopoShape &shape = part->Shape.getValue(); + const Part::TopoShape &shape = feat->Shape.getValue(); TopoDS_Shape sh = shape.getSubShape(sub[0].c_str()); const TopoDS_Face& face = TopoDS::Face(sh); if (face.IsNull()){ @@ -534,13 +802,22 @@ void CmdPartDesignNewSketch::activated(int iMsg) supportString = FaceFilter.Result[0][0].getAsPropertyLinkSubString(); } else { - if (PlaneFilter1.match()) - supportString = PlaneFilter1.Result[0][0].getAsPropertyLinkSubString(); - else - supportString = PlaneFilter2.Result[0][0].getAsPropertyLinkSubString(); + feat = static_cast(PlaneFilter.Result[0][0].getObject()); + // TODO: Find out whether the user picked front or back of this plane + supportString = std::string("(App.activeDocument().") + feat->getNameInDocument() + ", ['front'])"; + } + + if (!pcActiveBody->hasFeature(feat)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from other body"), + QObject::tr("You have to select a face or plane from the active body!")); + return; + } else if (pcActiveBody->isAfterTip(feat)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from inactive feature"), + QObject::tr("You have to select a face or plane before the current insert point, or move the insert point")); + return; } - // create Sketch on Face + // create Sketch on Face or Plane std::string FeatName = getUniqueObjectName("Sketch"); openCommand("Create a Sketch on Face"); @@ -566,7 +843,7 @@ void CmdPartDesignNewSketch::activated(int iMsg) // Check whether this plane is a base plane bool base = false; for (unsigned i = 0; i < 3; i++) { - if (strcmp(BasePlaneNames[i], (*p)->getNameInDocument()) == 0) { + if (strcmp(PartDesignGui::BaseplaneNames[i], (*p)->getNameInDocument()) == 0) { status.push_back(PartDesignGui::FeaturePickDialog::basePlane); if (firstValidPlane == planes.end()) firstValidPlane = p; @@ -578,12 +855,11 @@ void CmdPartDesignNewSketch::activated(int iMsg) if (base) continue; // Check whether this plane belongs to the active body - PartDesign::Body* body = PartDesignGui::getBody(); - if (!body->hasFeature(*p)) { + if (!pcActiveBody->hasFeature(*p)) { status.push_back(PartDesignGui::FeaturePickDialog::otherBody); continue; } else { - if (body->isAfterTip(*p)) + if (pcActiveBody->isAfterTip(*p)) status.push_back(PartDesignGui::FeaturePickDialog::afterTip); continue; } @@ -602,24 +878,24 @@ void CmdPartDesignNewSketch::activated(int iMsg) } // If there is more than one possibility, show dialog and let user pick plane + bool reversed = false; if (validPlanes > 1) { PartDesignGui::FeaturePickDialog Dlg(planes, status); if ((Dlg.exec() != QDialog::Accepted) || (planes = Dlg.getFeatures()).empty()) return; // Cancelled or nothing selected firstValidPlane = planes.begin(); + reversed = Dlg.getReverse(); } - App::Plane* plane = static_cast(*firstValidPlane); - Base::Vector3d p = plane->Placement.getValue().getPosition(); - Base::Rotation r = plane->Placement.getValue().getRotation(); - + App::Plane* plane = static_cast(*firstValidPlane); std::string FeatName = getUniqueObjectName("Sketch"); - std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + ", [])"; + std::string supportString = std::string("(App.activeDocument().") + plane->getNameInDocument() + + ", ['" + (reversed ? "back" : "front") + "'])"; openCommand("Create a new Sketch"); doCommand(Doc,"App.activeDocument().addObject('Sketcher::SketchObject','%s')",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Support = %s",FeatName.c_str(),supportString.c_str()); - doCommand(Doc,"App.activeDocument().%s.Placement = App.Placement(App.Vector(%f,%f,%f),App.Rotation(%f,%f,%f,%f))",FeatName.c_str(),p.x,p.y,p.z,r[0],r[1],r[2],r[3]); + updateActive(); // Make sure the Support's Placement property is updated doCommand(Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", pcActiveBody->getNameInDocument(), FeatName.c_str()); //doCommand(Gui,"Gui.activeDocument().activeView().setCamera('%s')",cam.c_str()); @@ -639,7 +915,7 @@ bool CmdPartDesignNewSketch::isActive(void) // Common utility functions for all features creating solids //=========================================================================== -void finishFeature(const Gui::Command* cmd, const std::string& FeatName) +void finishFeature(const Gui::Command* cmd, const std::string& FeatName, const bool hidePrevSolid = true) { PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); @@ -648,7 +924,7 @@ void finishFeature(const Gui::Command* cmd, const std::string& FeatName) if (cmd->isActiveObjectValid() && (pcActiveBody != NULL)) { App::DocumentObject* prevSolidFeature = pcActiveBody->getPrevSolidFeature(NULL, false); - if (prevSolidFeature != NULL) + if (hidePrevSolid && (prevSolidFeature != NULL)) cmd->doCommand(cmd->Gui,"Gui.activeDocument().hide(\"%s\")", prevSolidFeature->getNameInDocument()); } cmd->updateActive(); @@ -955,16 +1231,18 @@ void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), -<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 - QObject::tr("Fillet works only on parts.")); -======= - QString::fromStdString(which) + QObject::tr(" works only on parts")); ->>>>>>> Made the rest of the PartDesign features aware of the Body + QString::fromStdString(which) + QObject::tr(" works only on parts.")); return; } Part::Feature *base = static_cast(selection[0].getObject()); + if (base != pcActiveBody->getPrevSolidFeature(NULL, true)) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), + QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); + return; + } + const Part::TopoShape& TopShape = base->Shape.getShape(); if (TopShape._Shape.IsNull()){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), @@ -1039,11 +1317,7 @@ void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) if (SubNames.size() == 0) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), -<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 - QObject::tr("No fillet possible on selected faces/edges.")); -======= - QString::fromStdString(which) + QObject::tr(" not possible on selected faces/edges")); ->>>>>>> Made the rest of the PartDesign features aware of the Body + QString::fromStdString(which) + QObject::tr(" not possible on selected faces/edges.")); return; } @@ -1064,23 +1338,10 @@ void makeChamferOrFillet(Gui::Command* cmd, const std::string& which) std::string FeatName = cmd->getUniqueObjectName(which.c_str()); -<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 - openCommand("Make Fillet"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Fillet\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } -======= cmd->openCommand((std::string("Make ") + which).c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().addObject(\"PartDesign::%s\",\"%s\")",which.c_str(), FeatName.c_str()); cmd->doCommand(cmd->Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - + doCommand(Gui,"Gui.Selection.clearSelection()"); finishFeature(cmd, FeatName); } @@ -1100,7 +1361,6 @@ CmdPartDesignFillet::CmdPartDesignFillet() sStatusTip = sToolTipText; sPixmap = "PartDesign_Fillet"; } ->>>>>>> Made the rest of the PartDesign features aware of the Body void CmdPartDesignFillet::activated(int iMsg) { @@ -1131,137 +1391,8 @@ CmdPartDesignChamfer::CmdPartDesignChamfer() void CmdPartDesignChamfer::activated(int iMsg) { -<<<<<<< d0dc709387e4342aa59fbcd35921c3f85009a247 - std::vector selection = getSelection().getSelectionEx(); - - if (selection.size() != 1) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select an edge, face or body. Only one body is allowed.")); - return; - } - - if (!selection[0].isObjectTypeOf(Part::Feature::getClassTypeId())){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong object type"), - QObject::tr("Chamfer works only on parts.")); - return; - } - - Part::Feature *base = static_cast(selection[0].getObject()); - - const Part::TopoShape& TopShape = base->Shape.getShape(); - - if (TopShape._Shape.IsNull()){ - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Shape of selected part is empty.")); - return; - } - - TopTools_IndexedMapOfShape mapOfEdges; - TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; - TopExp::MapShapesAndAncestors(TopShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); - TopExp::MapShapes(TopShape._Shape, TopAbs_EDGE, mapOfEdges); - - std::vector SubNames = std::vector(selection[0].getSubNames()); - - unsigned int i = 0; - - while(i < SubNames.size()) - { - std::string aSubName = static_cast(SubNames.at(i)); - - if (aSubName.size() > 4 && aSubName.substr(0,4) == "Edge") { - TopoDS_Edge edge = TopoDS::Edge(TopShape.getSubShape(aSubName.c_str())); - const TopTools_ListOfShape& los = mapEdgeFace.FindFromKey(edge); - - if(los.Extent() != 2) - { - SubNames.erase(SubNames.begin()+i); - continue; - } - - const TopoDS_Shape& face1 = los.First(); - const TopoDS_Shape& face2 = los.Last(); - GeomAbs_Shape cont = BRep_Tool::Continuity(TopoDS::Edge(edge), - TopoDS::Face(face1), - TopoDS::Face(face2)); - if (cont != GeomAbs_C0) { - SubNames.erase(SubNames.begin()+i); - continue; - } - - i++; - } - else if(aSubName.size() > 4 && aSubName.substr(0,4) == "Face") { - TopoDS_Face face = TopoDS::Face(TopShape.getSubShape(aSubName.c_str())); - - TopTools_IndexedMapOfShape mapOfFaces; - TopExp::MapShapes(face, TopAbs_EDGE, mapOfFaces); - - for(int j = 1; j <= mapOfFaces.Extent(); ++j) { - TopoDS_Edge edge = TopoDS::Edge(mapOfFaces.FindKey(j)); - - int id = mapOfEdges.FindIndex(edge); - - std::stringstream buf; - buf << "Edge"; - buf << id; - - if(std::find(SubNames.begin(),SubNames.end(),buf.str()) == SubNames.end()) - { - SubNames.push_back(buf.str()); - } - - } - - SubNames.erase(SubNames.begin()+i); - } - // empty name or any other sub-element - else { - SubNames.erase(SubNames.begin()+i); - } - } - - if (SubNames.size() == 0) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("No chamfer possible on selected faces/edges.")); - return; - } - - std::string SelString; - SelString += "(App."; - SelString += "ActiveDocument";//getObject()->getDocument()->getName(); - SelString += "."; - SelString += selection[0].getFeatName(); - SelString += ",["; - for(std::vector::const_iterator it = SubNames.begin();it!=SubNames.end();++it){ - SelString += "\""; - SelString += *it; - SelString += "\""; - if(it != --SubNames.end()) - SelString += ","; - } - SelString += "])"; - - std::string FeatName = getUniqueObjectName("Chamfer"); - - openCommand("Make Chamfer"); - doCommand(Doc,"App.activeDocument().addObject(\"PartDesign::Chamfer\",\"%s\")",FeatName.c_str()); - doCommand(Doc,"App.activeDocument().%s.Base = %s",FeatName.c_str(),SelString.c_str()); - doCommand(Gui,"Gui.Selection.clearSelection()"); - doCommand(Gui,"Gui.activeDocument().hide(\"%s\")",selection[0].getFeatName()); - doCommand(Gui,"Gui.activeDocument().setEdit('%s')",FeatName.c_str()); - App::DocumentObjectGroup* grp = base->getGroup(); - if (grp) { - doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)" - ,grp->getNameInDocument(),FeatName.c_str()); - } - - copyVisual(FeatName.c_str(), "ShapeColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "LineColor", selection[0].getFeatName()); - copyVisual(FeatName.c_str(), "PointColor", selection[0].getFeatName()); -======= makeChamferOrFillet(this, "Chamfer"); ->>>>>>> Made the rest of the PartDesign features aware of the Body + doCommand(Gui,"Gui.Selection.clearSelection()"); } bool CmdPartDesignChamfer::isActive(void) @@ -1307,7 +1438,7 @@ void CmdPartDesignDraft::activated(int iMsg) Part::Feature *base = static_cast(selection[0].getObject()); - if (base != pcActiveBody->Tip.getValue()) { + if (base != pcActiveBody->getPrevSolidFeature(NULL, true)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong base feature"), QObject::tr("Only the current Tip of the active Body can be selected as the base feature")); return; @@ -1612,7 +1743,11 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() { sAppModule = "PartDesign"; sGroup = QT_TR_NOOP("PartDesign"); +<<<<<<< 7296e4f7ad6f07270ba640d4816ec51e5a23b2c9 sMenuText = QT_TR_NOOP("MultiTransform"); +======= + sMenuText = QT_TR_NOOP("Create MultiTransform"); +>>>>>>> Allow transforming a Pattern feature into a MultiTransform feature sToolTipText = QT_TR_NOOP("Create a multitransform feature"); sWhatsThis = "PartDesign_MultiTransform"; sStatusTip = sToolTipText; @@ -1621,28 +1756,79 @@ CmdPartDesignMultiTransform::CmdPartDesignMultiTransform() void CmdPartDesignMultiTransform::activated(int iMsg) { - std::string FeatName, selNames; + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) return; + std::vector features; - std::vector selList; - prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); - if (features.empty()) - return; - PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); - if (!pcActiveBody) - return; - updateActive(); - doCommand(Doc,selNames.c_str()); - - // Make sure the user isn't presented with an empty screen because no transformations are defined yet... - App::DocumentObject* prevSolid = pcActiveBody->getPrevSolidFeature(NULL, true); - if (prevSolid != NULL) { - Part::Feature* feat = static_cast(prevSolid); - doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", - FeatName.c_str(), feat->getNameInDocument()); - } + // Check if a Transformed feature has been selected, convert it to MultiTransform + features = getSelection().getObjectsOfType(PartDesign::Transformed::getClassTypeId()); + if (!features.empty()) { + // Throw out MultiTransform features, we don't want to nest them + for (std::vector::iterator f = features.begin(); f != features.end(); ) { + if ((*f)->getTypeId().isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) + f = features.erase(f); + else + f++; + } - finishFeature(this, FeatName); + if (features.empty()) return; + // Note: If multiple Transformed features were selected, only the first one is used + PartDesign::Transformed* trFeat = static_cast(features.front()); + + // Move the insert point back one feature + App::DocumentObject* oldTip = pcActiveBody->Tip.getValue(); + App::DocumentObject* prevFeature = pcActiveBody->getPrevFeature(trFeat); + Gui::Selection().clearSelection(); + if (prevFeature != NULL) + Gui::Selection().addSelection(prevFeature->getDocument()->getName(), prevFeature->getNameInDocument()); + openCommand("Convert to MultiTransform feature"); + doCommand(Gui, "FreeCADGui.runCommand('PartDesign_MoveTip')"); + + // Remove the Transformed feature from the Body + doCommand(Doc, "App.activeDocument().%s.removeFeature(App.activeDocument().%s)", + pcActiveBody->getNameInDocument(), trFeat->getNameInDocument()); + + // Create a MultiTransform feature and move the Transformed feature inside it + std::string FeatName = getUniqueObjectName("MultiTransform"); + doCommand(Doc, "App.activeDocument().addObject(\"PartDesign::MultiTransform\",\"%s\")", FeatName.c_str()); + doCommand(Doc, "App.activeDocument().%s.Originals = App.activeDocument().%s.Originals", FeatName.c_str(), trFeat->getNameInDocument()); + doCommand(Doc, "App.activeDocument().%s.Originals = []", trFeat->getNameInDocument()); + doCommand(Doc, "App.activeDocument().%s.Transformations = [App.activeDocument().%s]", FeatName.c_str(), trFeat->getNameInDocument()); + + // Add the MultiTransform into the Body at the current insert point + finishFeature(this, FeatName); + + // Restore the insert point + if (oldTip != trFeat) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); + } // otherwise the insert point remains at the new MultiTransform, which is fine + } else { + std::string FeatName, selNames; + std::vector selList; + prepareTransformed(this, "MultiTransform", features, FeatName, selList, selNames); + if (features.empty()) + return; + + PartDesign::Body *pcActiveBody = PartDesignGui::getBody(); + if (!pcActiveBody) + return; + updateActive(); + doCommand(Doc,selNames.c_str()); + + // Make sure the user isn't presented with an empty screen because no transformations are defined yet... + App::DocumentObject* prevSolid = pcActiveBody->getPrevSolidFeature(NULL, true); + if (prevSolid != NULL) { + Part::Feature* feat = static_cast(prevSolid); + doCommand(Doc,"App.activeDocument().%s.Shape = App.activeDocument().%s.Shape", + FeatName.c_str(), feat->getNameInDocument()); + } + + finishFeature(this, FeatName); + } } bool CmdPartDesignMultiTransform::isActive(void) @@ -1650,6 +1836,74 @@ bool CmdPartDesignMultiTransform::isActive(void) return hasActiveDocument(); } +//=========================================================================== +// PartDesign_Boolean +//=========================================================================== + +/* Boolean commands =======================================================*/ +DEF_STD_CMD_A(CmdPartDesignBoolean); + +CmdPartDesignBoolean::CmdPartDesignBoolean() + :Command("PartDesign_Boolean") +{ + sAppModule = "PartDesign"; + sGroup = QT_TR_NOOP("PartDesign"); + sMenuText = QT_TR_NOOP("Boolean operation"); + sToolTipText = QT_TR_NOOP("Boolean operation with two or more boies"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Boolean"; +} + + +void CmdPartDesignBoolean::activated(int iMsg) +{ + Gui::SelectionFilter BodyFilter("SELECT PartDesign::Body COUNT 1.."); + PartDesign::Body* body; + std::string bodyString(""); + + if (BodyFilter.match()) { + body = static_cast(BodyFilter.Result[0][0].getObject()); + std::vector bodies; + std::vector >::iterator i = BodyFilter.Result.begin(); + i++; + for (; i != BodyFilter.Result.end(); i++) { + for (std::vector::iterator j = i->begin(); j != i->end(); j++) { + bodies.push_back(j->getObject()); + } + } + bodyString = PartDesignGui::getPythonStr(bodies); + } else { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No body selected"), + QObject::tr("Please select a body for the boolean operation")); + return; + } + + openCommand("Create Boolean"); + + // Make sure we are working on the selected body + if (body != PartDesignGui::ActivePartObject) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(body->getDocument()->getName(), body->Tip.getValue()->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + } + + std::string FeatName = getUniqueObjectName("Boolean"); + + doCommand(Doc,"App.activeDocument().addObject('PartDesign::Boolean','%s')",FeatName.c_str()); + if (!bodyString.empty()) + doCommand(Doc,"App.activeDocument().%s.Bodies = %s",FeatName.c_str(),bodyString.c_str()); + finishFeature(this, FeatName, false); +} + +bool CmdPartDesignBoolean::isActive(void) +{ + if (getActiveGuiDocument()) + return true; + else + return false; +} + //=========================================================================== // Initialization @@ -1661,20 +1915,31 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignBody()); rcCmdMgr.addCommand(new CmdPartDesignMoveTip()); + + rcCmdMgr.addCommand(new CmdPartDesignDuplicateSelection()); + rcCmdMgr.addCommand(new CmdPartDesignMoveFeature()); + rcCmdMgr.addCommand(new CmdPartDesignMoveFeatureInTree()); + rcCmdMgr.addCommand(new CmdPartDesignPlane()); rcCmdMgr.addCommand(new CmdPartDesignLine()); rcCmdMgr.addCommand(new CmdPartDesignPoint()); + rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); + rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); rcCmdMgr.addCommand(new CmdPartDesignGroove()); + rcCmdMgr.addCommand(new CmdPartDesignFillet()); rcCmdMgr.addCommand(new CmdPartDesignDraft()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); + rcCmdMgr.addCommand(new CmdPartDesignMirrored()); rcCmdMgr.addCommand(new CmdPartDesignLinearPattern()); rcCmdMgr.addCommand(new CmdPartDesignPolarPattern()); //rcCmdMgr.addCommand(new CmdPartDesignScaled()); rcCmdMgr.addCommand(new CmdPartDesignMultiTransform()); + + rcCmdMgr.addCommand(new CmdPartDesignBoolean()); } diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 42478242e24f..300c3f8cebb9 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -338,7 +338,7 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { else if (num == ui->comboDirection->count() - 1) { // enter reference selection mode hideObject(); - showOriginals(); + showBase(); referenceSelectionMode = true; Gui::Selection().clearSelection(); addReferenceSelectionGate(true, true); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index f7e5f99f10b6..4812f2f9f784 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -264,7 +264,7 @@ void TaskMirroredParameters::onPlaneChanged(int num) { else if (num == ui->comboPlane->count() - 1) { // enter reference selection mode hideObject(); - showOriginals(); + showBase(); referenceSelectionMode = true; Gui::Selection().clearSelection(); addReferenceSelectionGate(false, true); diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp index 1642fcd13d64..ec818a961e2b 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp @@ -291,7 +291,7 @@ void TaskMultiTransformParameters::finishAdd(std::string &newFeatName) if (row < 0) { // Happens when first row (first transformation) is created // Hide all the originals now (hiding them in Command.cpp presents the user with an empty screen!) - hideOriginals(); + hideBase(); } // Insert new transformation after the selected row diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index 9de3a6bcb86b..bb0591a21370 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -274,7 +274,7 @@ void TaskPolarPatternParameters::onAxisChanged(int num) { else if (num == ui->comboAxis->count() - 1) { // enter reference selection mode hideObject(); - showOriginals(); + showBase(); referenceSelectionMode = true; Gui::Selection().clearSelection(); addReferenceSelectionGate(true, false); diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 34e4aed8c950..3cd7331bd16b 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -194,23 +194,35 @@ void TaskTransformedParameters::showObject() } } -void TaskTransformedParameters::hideOriginals() +void TaskTransformedParameters::hideBase() { Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - std::vector originals = getOriginals(); - for (std::vector::iterator it = originals.begin(); it != originals.end(); ++it) - doc->setHide((*it)->getNameInDocument()); + PartDesign::Body* pcActiveBody = PartDesignGui::getBody(); + if (doc && pcActiveBody) { + App::DocumentObject* prevFeature; + if (insideMultiTransform) { + prevFeature = pcActiveBody->getPrevSolidFeature(parentTask->TransformedView->getObject(), false); + } else { + prevFeature = pcActiveBody->getPrevSolidFeature(TransformedView->getObject(), false); + } + + doc->setHide(prevFeature->getNameInDocument()); } } -void TaskTransformedParameters::showOriginals() +void TaskTransformedParameters::showBase() { Gui::Document* doc = Gui::Application::Instance->activeDocument(); - if (doc) { - std::vector originals = getOriginals(); - for (std::vector::iterator it = originals.begin(); it != originals.end(); ++it) - doc->setShow((*it)->getNameInDocument()); + PartDesign::Body* pcActiveBody = PartDesignGui::getBody(); + if (doc && pcActiveBody) { + App::DocumentObject* prevFeature; + if (insideMultiTransform) { + prevFeature = pcActiveBody->getPrevSolidFeature(parentTask->TransformedView->getObject(), false); + } else { + prevFeature = pcActiveBody->getPrevSolidFeature(TransformedView->getObject(), false); + } + + doc->setShow(prevFeature->getNameInDocument()); } } @@ -220,7 +232,7 @@ void TaskTransformedParameters::exitSelectionMode() referenceSelectionMode = false; Gui::Selection().rmvSelectionGate(); showObject(); - hideOriginals(); + hideBase(); } void TaskTransformedParameters::addReferenceSelectionGate(bool edge, bool face) diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index 6c66db7cd973..cbb9d93b6df3 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -83,8 +83,8 @@ protected Q_SLOTS: void hideObject(); void showObject(); - void hideOriginals(); - void showOriginals(); + void hideBase(); + void showBase(); void addReferenceSelectionGate(bool edge, bool face); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index def22f8c13bd..9b522fbb8ec7 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -388,9 +388,15 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) - *item << "PartDesign_MoveTip" - << "PartDesign_MoveFeature" + *item << "PartDesign_MoveTip"; + if (Gui::Selection().countObjectsOfType(PartDesign::Feature::getClassTypeId()) + + Gui::Selection().countObjectsOfType(Part::Datum::getClassTypeId()) + + Gui::Selection().countObjectsOfType(Part::Part2DObject::getClassTypeId()) > 0 ) + *item << "PartDesign_MoveFeature" << "PartDesign_MoveFeatureInTree"; + if (Gui::Selection().countObjectsOfType(PartDesign::Transformed::getClassTypeId()) - + Gui::Selection().countObjectsOfType(PartDesign::MultiTransform::getClassTypeId()) == 1 ) + *item << "PartDesign_MultiTransform"; } } From c21f21666fced3be2b34f7304d65d39965ca1e61 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 23 Aug 2013 14:03:07 +0200 Subject: [PATCH 177/664] Fixed bug that didn't clean up the Body when deleting an object from it --- src/Mod/PartDesign/Gui/ViewProvider.cpp | 19 +++++++++++++++++++ src/Mod/PartDesign/Gui/ViewProvider.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 6249768fbae7..2b4858b87a67 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -108,3 +108,22 @@ void ViewProvider::updateData(const App::Property* prop) } inherited::updateData(prop); } + +bool ViewProvider::onDelete(const std::vector &) +{ + // Body feature housekeeping + Part::BodyBase* body = Part::BodyBase::findBodyOf(getObject()); + if (body != NULL) { + body->removeFeature(getObject()); + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = body->Tip.getValue(); + App::DocumentObject* prev = body->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + return true; +} diff --git a/src/Mod/PartDesign/Gui/ViewProvider.h b/src/Mod/PartDesign/Gui/ViewProvider.h index 32926f154b0e..6e859a22ed10 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.h +++ b/src/Mod/PartDesign/Gui/ViewProvider.h @@ -45,6 +45,8 @@ class PartDesignGuiExport ViewProvider : public PartGui::ViewProviderPart { protected: virtual void unsetEdit(int ModNum); + virtual bool onDelete(const std::vector &); + std::string oldWb; App::DocumentObject* oldTip; }; From 92d51a6e1d39958443d479420c37f3d27efb65ec Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 23 Aug 2013 14:48:01 +0200 Subject: [PATCH 178/664] Fixed bug that prevented proper switching to PartDesign workbench --- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 2 +- src/Mod/PartDesign/Gui/Workbench.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 318884ae2ab4..03b58297aa3b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -104,7 +104,7 @@ bool ViewProviderBody::doubleClicked(void) // assure the PartDesign workbench Gui::Command::assureWorkbench("PartDesignWorkbench"); Gui::Command::addModule(Gui::Command::Gui,"PartDesignGui"); - Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(App.activeDocument().%s)",this->getObject()->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)",this->getObject()->getNameInDocument()); return true; } diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 9b522fbb8ec7..a4d88cfca80c 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -332,7 +332,7 @@ void switchToDocument(const App::Document* doc) activeBody = static_cast(bodies.front()); if (activeBody != NULL) { - //Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); + Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(App.activeDocument().%s)", activeBody->getNameInDocument()); } else { QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Could not create body"), @@ -595,7 +595,7 @@ void Workbench::deactivated() removeTaskWatcher(); // reset the active Body Gui::Command::doCommand(Gui::Command::Doc,"import PartDesignGui"); - Gui::Command::doCommand(Gui::Command::Doc,"PartDesignGui.setActivePart(None)"); + Gui::Command::doCommand(Gui::Command::Gui,"PartDesignGui.setActivePart(None)"); Gui::Workbench::deactivated(); From 8a041ffc8ea0d44f8ffc3a463909ee3fff4ec54b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 25 Aug 2013 17:31:02 +0200 Subject: [PATCH 179/664] Fix bug that didn't allow to select base plane to create a sketch on it --- src/Mod/PartDesign/Gui/Command.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index c25290ed59da..9b6e6d634ea8 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -808,9 +808,18 @@ void CmdPartDesignNewSketch::activated(int iMsg) } if (!pcActiveBody->hasFeature(feat)) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from other body"), - QObject::tr("You have to select a face or plane from the active body!")); - return; + bool isBasePlane = false; + for (unsigned i = 0; i < 3; i++) { + if (strcmp(PartDesignGui::BaseplaneNames[i], feat->getNameInDocument()) == 0) { + isBasePlane = true; + break; + } + } + if (!isBasePlane) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from other body"), + QObject::tr("You have to select a face or plane from the active body!")); + return; + } } else if (pcActiveBody->isAfterTip(feat)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Selection from inactive feature"), QObject::tr("You have to select a face or plane before the current insert point, or move the insert point")); From 010761d1627a62c24ad6af50b0a6a7fc9a8431ca Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sun, 25 Aug 2013 18:50:02 +0200 Subject: [PATCH 180/664] Fix bug that did not show the correct shape to select a reference (e.g. face) from when editing a SketchBased feature in the tree --- .../Gui/TaskSketchBasedParameters.cpp | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 08097599e07f..76203ad2960a 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -91,26 +91,28 @@ const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChan void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar) { // Note: Even if there is no solid, App::Plane and Part::Datum can still be selected - App::DocumentObject* solid = PartDesignGui::ActivePartObject->getPrevSolidFeature(NULL, false); - PartDesign::SketchBased* pcSketchBased = static_cast(vp->getObject()); + App::DocumentObject* prevSolid = PartDesignGui::ActivePartObject->getPrevSolidFeature(vp->getObject(), false); + App::DocumentObject* curSolid = PartDesignGui::ActivePartObject->getPrevSolidFeature(); if (pressed) { Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { - doc->setHide(pcSketchBased->getNameInDocument()); - if (solid) - doc->setShow(solid->getNameInDocument()); + if (curSolid) + doc->setHide(curSolid->getNameInDocument()); + if (prevSolid) + doc->setShow(prevSolid->getNameInDocument()); } Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate - (new ReferenceSelection(solid, edge, face, planar)); + (new ReferenceSelection(prevSolid, edge, face, planar)); } else { Gui::Selection().rmvSelectionGate(); Gui::Document* doc = Gui::Application::Instance->activeDocument(); if (doc) { - doc->setShow(pcSketchBased->getNameInDocument()); - if (solid) - doc->setHide(solid->getNameInDocument()); + if (curSolid) + doc->setShow(curSolid->getNameInDocument()); + if (prevSolid) + doc->setHide(prevSolid->getNameInDocument()); } } } From 9dba4c01e2c4885c357344487b962f8fe1147a0f Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 26 Aug 2013 14:38:16 +0200 Subject: [PATCH 181/664] Added some comments about things to be fixed in the future --- src/Mod/PartDesign/App/FeaturePocket.cpp | 8 ++++++-- src/Mod/PartDesign/App/FeatureSketchBased.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 43e07b69a6bc..e111a07238e8 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -153,8 +153,12 @@ App::DocumentObjectExecReturn *Pocket::execute(void) } getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue()); - // Special treatment because often the created stand-alone prism is invalid (empty) because - // BRepFeat_MakePrism(..., 2, 1) is buggy + // BRepFeat_MakePrism(..., 2, 1) in combination with PerForm(upToFace) is buggy when the + // prism that is being created is contained completely inside the base solid + // In this case the resulting shape is empty. This is not a problem for the Pad or Pocket itself + // but it leads to an invalid SubShape + // The bug only occurs when the upToFace is limited (by a wire), not for unlimited upToFace. But + // other problems occur with unlimited concave upToFace so it is not an option to always unlimit upToFace // Check supportface for limits, otherwise Perform() throws an exception TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index b5f3633b6ec5..b3604a45ae31 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -628,8 +628,10 @@ void SketchBased::generatePrism(TopoDS_Shape& prism, const bool SketchBased::checkWireInsideFace(const TopoDS_Wire& wire, const TopoDS_Face& face, const gp_Dir& dir) { // Project wire onto the face (face, not surface! So limits of face apply) - // FIXME: For a user-selected upToFace, sometimes this returns a non-closed wire for no apparent reason - // Check again after introduction of "robust" reference for upToFace + // FIXME: The results of BRepProj_Projection do not seem to be very stable. Sometimes they return no result + // even in the simplest projection case. + // FIXME: Checking for Closed() is wrong because this has nothing to do with the wire itself being closed + // But ShapeAnalysis_Wire::CheckClosed() doesn't give correct results either. BRepProj_Projection proj(wire, face, dir); return (proj.More() && proj.Current().Closed()); } From 99fe9b61782cfccddb8bd1b27a772280d5515842 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 2 Sep 2013 16:16:17 +0200 Subject: [PATCH 182/664] Moved Body::isAfterTip() to BodyBase --- src/Mod/Part/App/BodyBase.cpp | 11 +++++++++++ src/Mod/Part/App/BodyBase.h | 4 +++- src/Mod/PartDesign/App/Body.cpp | 11 ----------- src/Mod/PartDesign/App/Body.h | 3 --- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/Mod/Part/App/BodyBase.cpp b/src/Mod/Part/App/BodyBase.cpp index 8474a0de71a9..701d0e6a54ae 100644 --- a/src/Mod/Part/App/BodyBase.cpp +++ b/src/Mod/Part/App/BodyBase.cpp @@ -78,4 +78,15 @@ BodyBase* BodyBase::findBodyOf(const App::DocumentObject* f) return NULL; } +const bool BodyBase::isAfterTip(const App::DocumentObject *f) const { + App::DocumentObject* tipFeature = Tip.getValue(); + if (tipFeature == NULL) + return true; + + std::vector features = Model.getValues(); + std::vector::const_iterator it = std::find(features.begin(), features.end(), f); + std::vector::const_iterator tip = std::find(features.begin(), features.end(), tipFeature); + return (it > tip); +} + } diff --git a/src/Mod/Part/App/BodyBase.h b/src/Mod/Part/App/BodyBase.h index dc0b2dfbaff8..c8c1d42e7012 100644 --- a/src/Mod/Part/App/BodyBase.h +++ b/src/Mod/Part/App/BodyBase.h @@ -72,10 +72,12 @@ class PartExport BodyBase : public Part::Feature virtual App::DocumentObject *getPrevSolidFeature(App::DocumentObject *start = NULL, const bool inclusive = true) { return NULL; } + /// Return true if the feature is located after the current Tip feature + const bool isAfterTip(const App::DocumentObject *f) const; + /// Return the body which this feature belongs too, or NULL static BodyBase* findBodyOf(const App::DocumentObject* f); - }; } //namespace Part diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 0e65ba269950..42dda0394d36 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -191,17 +191,6 @@ App::DocumentObject* Body::getNextSolidFeature(App::DocumentObject *start, const return *it; } -const bool Body::isAfterTip(const App::DocumentObject *f) { - App::DocumentObject* tipFeature = Tip.getValue(); - if (tipFeature == NULL) - return true; - - std::vector features = Model.getValues(); - std::vector::const_iterator it = std::find(features.begin(), features.end(), f); - std::vector::const_iterator tip = std::find(features.begin(), features.end(), tipFeature); - return (it > tip); -} - const bool Body::isMemberOfMultiTransform(const App::DocumentObject* f) { if (f == NULL) diff --git a/src/Mod/PartDesign/App/Body.h b/src/Mod/PartDesign/App/Body.h index a07f0111263b..6d3c27f25b57 100644 --- a/src/Mod/PartDesign/App/Body.h +++ b/src/Mod/PartDesign/App/Body.h @@ -78,9 +78,6 @@ class PartDesignExport Body : public Part::BodyBase // Return the shape of the feature preceding this feature //const Part::TopoShape getPreviousSolid(const PartDesign::Feature* f); - /// Return true if the feature is located after the current Tip feature - const bool isAfterTip(const App::DocumentObject *f); - /// Add the feature into the body at the current insert point (Tip feature) void addFeature(App::DocumentObject* feature); From 2c377232177609217b951cd19ec0dfdb453f5ee7 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 2 Sep 2013 16:18:19 +0200 Subject: [PATCH 183/664] Fixed bug in external geometry selection of sketcher --- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 35 ++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index b60ef85f99e6..c859ab92ed49 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4474,22 +4474,31 @@ namespace SketcherGui { bool allow(App::Document *pDoc, App::DocumentObject *pObj, const char *sSubName) { + // Selection outside of the Document is NOT allowed Sketcher::SketchObject *sketch = static_cast(object); - App::DocumentObject *support = sketch->Support.getValue(); - - // for the moment we allow external constraints only from the support and datum features - if(pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || - pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - return true; + if (sketch->getDocument() != pDoc) + return false; - if (pObj != support) { - // Selection outside of support not allowed - if (!sketch->allowOtherBody) - return false; + App::DocumentObject *support = sketch->Support.getValue(); + Part::BodyBase* body = Part::BodyBase::findBodyOf(support); + if (body != NULL) { + if (Part::BodyBase::findBodyOf(pObj) == body) { + // Don't allow selection after the Tip feature in the same body + if (body->isAfterTip(pObj)) + return false; + } else { + // Selection outside of body not allowed if flag is not set + if (!sketch->allowOtherBody) + return false; + } - // Selection outside of support allowed if from other body - // TODO: There is still a possibility of creating cyclic references here - if (Part::BodyBase::findBodyOf(pObj) == Part::BodyBase::findBodyOf(support)) + // Datum features are always allowed + if(pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + return true; + } else { + // Legacy parts - don't allow selection outside of the support + if (pObj != support) return false; } From be9365679fd2016ca80d3dd220901b8284a7eedd Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 11 Sep 2013 19:46:27 +0200 Subject: [PATCH 184/664] Centralize the check for valid external geometry to ensure consistency --- src/Mod/Sketcher/App/SketchObject.cpp | 35 ++++++++++++++++++++--- src/Mod/Sketcher/App/SketchObject.h | 4 ++- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 26 +++-------------- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 7f669ae0df45..040e7989b1f7 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -68,6 +68,7 @@ #include #include +#include #include "SketchObject.h" #include "SketchObjectPy.h" @@ -1700,6 +1701,34 @@ int SketchObject::trim(int GeoId, const Base::Vector3d& point) return -1; } +bool SketchObject::isExternalAllowed(App::Document *pDoc, App::DocumentObject *pObj) const +{ + // Externals outside of the Document are NOT allowed + if (this->getDocument() != pDoc) + return false; + + App::DocumentObject *support = this->Support.getValue(); + Part::BodyBase* body = Part::BodyBase::findBodyOf(support); + if (body != NULL) { + if (Part::BodyBase::findBodyOf(pObj) != body) { + // Selection outside of body not allowed if flag is not set + if (!this->allowOtherBody) + return false; + } + + // Datum features are always allowed + if(pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + return true; + } else { + // Legacy parts - don't allow selection outside of the support + if (pObj != support) + return false; + } + + return true; +} + int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, Sketcher::PointPos refPosId/*=Sketcher::none*/) { const std::vector< Part::Geometry * > &geovals = getInternalGeometry(); @@ -2718,10 +2747,8 @@ int SketchObject::DeleteUnusedInternalGeometry(int GeoId) int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName) { // so far only externals to the support of the sketch and datum features - if (!allowOtherBody && (Support.getValue() != Obj)) - if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) && - !Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - return -1; + if (!isExternalAllowed(Obj->getDocument(), Obj)) + return -1; // get the actual lists of the externals std::vector Objects = ExternalGeometry.getValues(); diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 7224417eee65..15c38670caa3 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -259,8 +259,10 @@ class SketcherExport SketchObject : public Part::Part2DObject /// gets the solved sketch as a reference inline Sketch &getSolvedSketch(void) {return solvedSketch;} - // Flag to allow external geometry from other bodies than the one this sketch belongs to + /// Flag to allow external geometry from other bodies than the one this sketch belongs to bool allowOtherBody; + /// Return true if this object is allowed as external geometry for the sketch + bool isExternalAllowed(App::Document *pDoc, App::DocumentObject *pObj) const; protected: /// get called by the container when a property has changed diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index c859ab92ed49..067c3069e3ed 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4474,33 +4474,15 @@ namespace SketcherGui { bool allow(App::Document *pDoc, App::DocumentObject *pObj, const char *sSubName) { - // Selection outside of the Document is NOT allowed Sketcher::SketchObject *sketch = static_cast(object); - if (sketch->getDocument() != pDoc) + if (!sketch->isExternalAllowed(pDoc, pObj)) return false; App::DocumentObject *support = sketch->Support.getValue(); Part::BodyBase* body = Part::BodyBase::findBodyOf(support); - if (body != NULL) { - if (Part::BodyBase::findBodyOf(pObj) == body) { - // Don't allow selection after the Tip feature in the same body - if (body->isAfterTip(pObj)) - return false; - } else { - // Selection outside of body not allowed if flag is not set - if (!sketch->allowOtherBody) - return false; - } - - // Datum features are always allowed - if(pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || - pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) - return true; - } else { - // Legacy parts - don't allow selection outside of the support - if (pObj != support) - return false; - } + if ((body != NULL) && (Part::BodyBase::findBodyOf(pObj) == body) && body->isAfterTip(pObj)) + // Don't allow selection after the Tip feature in the same body + return false; if (!sSubName || sSubName[0] == '\0') return false; From 02ce7395aa856f7dd024808980f9b09efff5678d Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 11 Sep 2013 19:57:50 +0200 Subject: [PATCH 185/664] Centralize the check for valid external geometry to ensure consistency (part 2) --- src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index d9cc5bf9103a..55009ac0f9a3 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -384,20 +384,10 @@ PyObject* SketchObjectPy::addExternal(PyObject *args) PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } - // check if it is a datum feature - // TODO: Allow selection only from Body which this sketch belongs to? - if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { - // OK - } else if (Obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - if (!skObj->allowOtherBody && (skObj->Support.getValue() != Obj)) { - std::stringstream str; - str << ObjectName << " is not supported by this sketch"; - PyErr_SetString(PyExc_ValueError, str.str().c_str()); - return 0; - } - } else if (!Obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + // check if this type of external geometry is allowed + if (!skObj->isExternalAllowed(Obj->getDocument(), Obj)) { std::stringstream str; - str << ObjectName << " must be a Part feature or a datum feature"; + str << ObjectName << " is not allowed as external geometry of this sketch"; PyErr_SetString(PyExc_ValueError, str.str().c_str()); return 0; } From a4ad9a6a55cf57b575c20e2ca5e71bc4f1266179 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 14 Sep 2013 08:11:59 +0200 Subject: [PATCH 186/664] ViewProviderBody::claimChildren() : Claim all children not claimed by another object --- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 03b58297aa3b..eaeddc8e2430 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -115,20 +115,10 @@ std::vector ViewProviderBody::claimChildren(void)const // search for objects handled (claimed) by the features for(std::vector::const_iterator it = Model.begin();it!=Model.end();++it){ - // sketches of SketchBased features get claimed under the feature so has to be removed from the Body - if ((*it)->isDerivedFrom(PartDesign::SketchBased::getClassTypeId())){ - App::DocumentObject* sketch = static_cast(*it)->Sketch.getValue(); - if (sketch != NULL) - OutSet.insert(sketch); - } - - // Transformations of a MultiTransform feature get claimed under the feature, too - if ((*it)->isDerivedFrom(PartDesign::MultiTransform::getClassTypeId())) { - std::vector trfs = static_cast(*it)->Transformations.getValues(); - for (std::vector::const_iterator t = trfs.begin(); t != trfs.end(); t++) - if ((*t) != NULL) - OutSet.insert(*t); - } + std::vector children = Gui::Application::Instance->getViewProvider(*it)->claimChildren(); + for (std::vector::const_iterator ch = children.begin(); ch != children.end(); ch++) + if ((*ch) != NULL) + OutSet.insert(*ch); } // remove the otherwise handled objects, preserving their order so the order in the TreeWidget is correct From 22e3aaa2d6646608139ca8d4855d6fab1d87d099 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 16 Sep 2013 20:21:15 +0200 Subject: [PATCH 187/664] Fix bug in SketchObject::execute() that throws exception instead of returning an error --- src/Mod/Sketcher/App/SketchObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 040e7989b1f7..1d2373e9967e 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -130,7 +130,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) try { App::DocumentObject* support = Support.getValue(); if (support == NULL) - throw Base::Exception("Sketch support has been deleted"); + return new App::DocumentObjectExecReturn("Sketch support has been deleted"); this->positionBySupport(); } From b6932b0bdb0058c57f6601b5afd42adeb4da0f44 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 16 Sep 2013 20:36:00 +0200 Subject: [PATCH 188/664] Allow datum points and lines to have offsets from their references --- src/Mod/Part/App/DatumFeature.cpp | 2 + src/Mod/Part/App/DatumFeature.h | 10 +- src/Mod/PartDesign/App/DatumLine.cpp | 141 ++++++++++++++++-- src/Mod/PartDesign/App/DatumPlane.cpp | 11 +- src/Mod/PartDesign/App/DatumPoint.cpp | 93 ++++++++++-- .../PartDesign/Gui/TaskDatumParameters.cpp | 78 +++++++++- src/Mod/PartDesign/Gui/TaskDatumParameters.h | 4 + src/Mod/PartDesign/Gui/TaskDatumParameters.ui | 56 ++++++- 8 files changed, 359 insertions(+), 36 deletions(-) diff --git a/src/Mod/Part/App/DatumFeature.cpp b/src/Mod/Part/App/DatumFeature.cpp index 05ec5bf480ea..f4b66afaa6f4 100644 --- a/src/Mod/Part/App/DatumFeature.cpp +++ b/src/Mod/Part/App/DatumFeature.cpp @@ -74,6 +74,8 @@ Datum::Datum(void) { ADD_PROPERTY_TYPE(References,(0,0),"References",(App::PropertyType)(App::Prop_None),"References defining the datum feature"); ADD_PROPERTY(Offset,(0.0)); + ADD_PROPERTY(Offset2,(0.0)); + ADD_PROPERTY(Offset3,(0.0)); ADD_PROPERTY(Angle,(0.0)); touch(); } diff --git a/src/Mod/Part/App/DatumFeature.h b/src/Mod/Part/App/DatumFeature.h index d2796b6edac3..76ec9289a6a6 100644 --- a/src/Mod/Part/App/DatumFeature.h +++ b/src/Mod/Part/App/DatumFeature.h @@ -42,11 +42,14 @@ class PartExport Datum : public Part::Feature public: Datum(); virtual ~Datum(); + //short mustExecute(); /// The references defining the datum object, e.g. three planes for a point, two planes for a line App::PropertyLinkSubList References; - /// Offset and angle for defining planes + /// Offsets and angle for defining planes App::PropertyFloat Offset; + App::PropertyFloat Offset2; + App::PropertyFloat Offset3; App::PropertyFloat Angle; /// recalculate the feature @@ -55,7 +58,10 @@ class PartExport Datum : public Part::Feature /// returns the type name of the view provider virtual const char* getViewProviderName(void) const = 0; - virtual const std::set getHint() = 0; + virtual const std::set getHint() const = 0; + + /// Return the number of offset values that make sense for the current reference combination + virtual const int offsetsAllowed() const = 0; /// Return a shape including Placement representing the datum feature TopoDS_Shape getShape() const; diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index 66c233b09d46..4379bf71a547 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -32,15 +32,20 @@ # include # include # include +# include # include # include +# include +# include # include # include +# include # include # include # include # include # include +# include # include # include # include @@ -101,12 +106,22 @@ void Line::initHints() key.clear(); value.clear(); key.insert(PLANE); value.insert(PLANE); - hints[key] = value; // PLANE -> PLANE + value.insert(LINE); + hints[key] = value; // PLANE -> LINE or PLANE key.clear(); value.clear(); key.insert(PLANE); key.insert(PLANE); hints[key] = DONE; // {PLANE, PLANE} -> DONE. Line from two planes or faces + key.clear(); value.clear(); + key.insert(PLANE); key.insert(LINE); + value.insert(LINE); + hints[key] = value; // {PLANE, LINE} -> LINE + + key.clear(); value.clear(); + key.insert(PLANE); key.insert(LINE); key.insert(LINE); + hints[key] = DONE; // {PLANE, LINE, LINE} -> DONE. Line from plane with distance (default zero) to two lines + key.clear(); value.clear(); value.insert(POINT); value.insert(LINE); value.insert(PLANE); hints[key] = value; @@ -132,10 +147,12 @@ Line::~Line() void Line::onChanged(const App::Property *prop) { - if (prop == &References) { + if ((prop == &References) || (prop == &Offset) || (prop == &Offset2)) { refTypes.clear(); std::vector refs = References.getValues(); std::vector refnames = References.getSubValues(); + if (refs.size() != refnames.size()) + return; for (int r = 0; r < refs.size(); r++) refTypes.insert(getRefType(refs[r], refnames[r])); @@ -152,6 +169,7 @@ void Line::onChanged(const App::Property *prop) gp_Lin* line = NULL; Handle_Geom_Surface s1 = NULL; Handle_Geom_Surface s2 = NULL; + Handle_Geom_Surface s3 = NULL; for (int i = 0; i < refs.size(); i++) { if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { @@ -162,16 +180,41 @@ void Line::onChanged(const App::Property *prop) p2 = new Base::Vector3d (p->getPoint()); } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Line::getClassTypeId())) { PartDesign::Line* l = static_cast(refs[i]); - base = new Base::Vector3d (l->getBasePoint()); - direction = new Base::Vector3d (l->getDirection()); + if (s1.IsNull()) { + base = new Base::Vector3d (l->getBasePoint()); + direction = new Base::Vector3d (l->getDirection()); + } else { + // Create plane through line normal to s1 + Handle_Geom_Plane pl = Handle_Geom_Plane::DownCast(s1); + if (pl.IsNull()) + return; // Non-planar first surface + gp_Dir ldir = gp_Dir(l->getDirection().x, l->getDirection().y, l->getDirection().z); + gp_Dir normal = ldir.Crossed(pl->Axis().Direction()); + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + gp_Pnt base = gp_Pnt(l->getBasePoint().x, l->getBasePoint().y, l->getBasePoint().z); + if (s2.IsNull()) { + base.Translate(offset1 * normal); + s2 = new Geom_Plane(base, normal); + } else { + base.Translate(offset2 * normal); + s3 = new Geom_Plane(base, normal); + } + } } else if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Plane::getClassTypeId())) { PartDesign::Plane* p = static_cast(refs[i]); Base::Vector3d base = p->getBasePoint(); Base::Vector3d normal = p->getNormal(); - if (s1.IsNull()) + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + + if (s1.IsNull()) { + base += normal * offset1; s1 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); - else + } else { + base += normal * offset2; s2 = new Geom_Plane(gp_Pnt(base.x, base.y, base.z), gp_Dir(normal.x, normal.y, normal.z)); + } } else if (refs[i]->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { App::Plane* p = static_cast(refs[i]); // Note: We only handle the three base planes here @@ -184,10 +227,16 @@ void Line::onChanged(const App::Property *prop) else if (strcmp(p->getNameInDocument(), "BaseplaneXZ") == 0) normal = gp_Dir(0,1,0); - if (s1.IsNull()) + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + + if (s1.IsNull()) { + base = gp_Pnt(normal.X() * offset1, normal.Y() * offset1, normal.Z() * offset1); s1 = new Geom_Plane(base, normal); - else + } else { + base = gp_Pnt(normal.X() * offset2, normal.Y() * offset2, normal.Z() * offset2); s2 = new Geom_Plane(base, normal); + } } else if (refs[i]->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { Part::Feature* feature = static_cast(refs[i]); const TopoDS_Shape& sh = feature->Shape.getValue(); @@ -208,15 +257,57 @@ void Line::onChanged(const App::Property *prop) } else if (subshape.ShapeType() == TopAbs_EDGE) { TopoDS_Edge e = TopoDS::Edge(subshape); BRepAdaptor_Curve adapt(e); - if (adapt.GetType() != GeomAbs_Line) + if (adapt.GetType() == GeomAbs_Circle) { + circle = new gp_Circ(adapt.Circle()); + } else if (adapt.GetType() == GeomAbs_Line) { + if (s1.IsNull()) { + line = new gp_Lin(adapt.Line()); + } else { + // Create plane through line normal to s1 + Handle_Geom_Plane pl = Handle_Geom_Plane::DownCast(s1); + if (pl.IsNull()) + return; // Non-planar first surface + gp_Dir normal = adapt.Line().Direction().Crossed(pl->Axis().Direction()); + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + gp_Pnt base = adapt.Line().Location(); + if (s2.IsNull()) { + base.Translate(offset1 * normal); + s2 = new Geom_Plane(base, normal); + } else { + base.Translate(offset2 * normal); + s3 = new Geom_Plane(base, normal); + } + } + } else { return; // Non-linear edge - line = new gp_Lin(adapt.Line()); + } } else if (subshape.ShapeType() == TopAbs_FACE) { TopoDS_Face f = TopoDS::Face(subshape); - if (s1.IsNull()) + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + BRepAdaptor_Surface adapt(f); + + if (s1.IsNull()) { + if (adapt.GetType() == GeomAbs_Cylinder) { + circle = new gp_Circ(gp_Ax2(adapt.Cylinder().Location(), adapt.Cylinder().Axis().Direction()), + adapt.Cylinder().Radius()); + } else if (adapt.GetType() == GeomAbs_Plane) { + gp_Trsf mov; + mov.SetTranslation(offset1 * gp_Vec(adapt.Plane().Axis().Direction())); + TopLoc_Location loc(mov); + f.Move(loc); + } s1 = BRep_Tool::Surface(f); - else + } else { + if (adapt.GetType() == GeomAbs_Plane) { + gp_Trsf mov; + mov.SetTranslation(offset2 * gp_Vec(adapt.Plane().Axis().Direction())); + TopLoc_Location loc(mov); + f.Move(loc); + } s2 = BRep_Tool::Surface(f); + } } } else { return; //"PartDesign::Point: Invalid reference type" @@ -233,12 +324,21 @@ void Line::onChanged(const App::Property *prop) // Line from gp_lin base = new Base::Vector3d(line->Location().X(), line->Location().Y(), line->Location().Z()); direction = new Base::Vector3d(line->Direction().X(), line->Direction().Y(), line->Direction().Z()); - } else if (!s1.IsNull() && !s2.IsNull()) { + } else if (circle != NULL) { + // Line from center of circle or cylinder + gp_Pnt centre = circle->Axis().Location(); + base = new Base::Vector3d(centre.X(), centre.Y(), centre.Z()); + gp_Dir dir = circle->Axis().Direction(); + direction = new Base::Vector3d(dir.X(), dir.Y(), dir.Z()); + } else if (!s1.IsNull() && !s2.IsNull()) { + if (!s3.IsNull()) + s1 = s3; // Line from a plane and two lines/edges + // Line from two surfaces GeomAPI_IntSS intersectorSS(s1, s2, Precision::Confusion()); if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) return; if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Base::Console().Warning("More than one intersection curve for datum line from surfaces\n"); Handle_Geom_Line l = Handle_Geom_Line::DownCast(intersectorSS.Line(1)); if (l.IsNull()) return; // non-linear intersection curve @@ -269,6 +369,19 @@ const std::set Line::getHint() return std::set(); } +const int Line::offsetsAllowed() const +{ + int planes = 0; + int lines = 0; + for (std::multiset::const_iterator r = refTypes.begin(); r != refTypes.end(); r++) { + if (*r == PLANE) planes++; + if (*r == LINE) lines++; + } + if (lines == 0) return planes; + if ((planes == 1) && (lines == 2)) return 2; + return 0; +} + Base::Vector3d Line::getBasePoint() const { return Placement.getValue().getPosition(); diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index 9f95deb7fc99..6415b5e1f17d 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -179,7 +179,7 @@ void Plane::onChanged(const App::Property *prop) refTypes.erase(ANGLE); } - if (prop == &References) { + if ((prop == &References) || (prop == &Offset)) { refTypes.clear(); std::vector refs = References.getValues(); std::vector refnames = References.getSubValues(); @@ -315,11 +315,11 @@ void Plane::onChanged(const App::Property *prop) if (!intersector.IsDone() || (intersector.NbPoints() == 0)) return; if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum plane from cylinder and plane"); + Base::Console().Warning("More than one intersection point for datum plane from cylinder and plane\n"); gp_Pnt inter = intersector.Point(1); p1 = new Base::Vector3d(inter.X(), inter.Y(), inter.Z()); - // TODO: Allow to control which side of the cylinder the plane is create on - there are always two possibilities + // TODO: Allow to control which side of the cylinder the plane is created on - there are always two possibilities } else if ((p1 != NULL) && (normal != NULL)) { // plane from other plane. Nothing to be done } else if ((p1 != NULL) && (p2 != NULL) && (p3 != NULL)) { @@ -366,6 +366,11 @@ const std::set Plane::getHint() return std::set(); } +const int Plane::offsetsAllowed() const +{ + return 1; +} + Base::Vector3d Plane::getBasePoint() { return Placement.getValue().getPosition(); diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp index b61d81633aa8..1e99f1920977 100644 --- a/src/Mod/PartDesign/App/DatumPoint.cpp +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -147,7 +147,7 @@ Point::~Point() void Point::onChanged(const App::Property* prop) { - if (prop == &References) { + if ((prop == &References) || (prop == &Offset) || (prop == &Offset2) || (prop == &Offset3)) { refTypes.clear(); std::vector refs = References.getValues(); std::vector refnames = References.getSubValues(); @@ -230,12 +230,36 @@ void Point::onChanged(const App::Property* prop) c2 = BRep_Tool::Curve(e, first, last); } else if (subshape.ShapeType() == TopAbs_FACE) { TopoDS_Face f = TopoDS::Face(subshape); - if (s1.IsNull()) + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + double offset3 = Offset3.getValue(); + BRepAdaptor_Surface adapt(f); + + if (s1.IsNull()) { + if (adapt.GetType() == GeomAbs_Plane) { + gp_Trsf mov; + mov.SetTranslation(offset1 * gp_Vec(adapt.Plane().Axis().Direction())); + TopLoc_Location loc(mov); + f.Move(loc); + } s1 = BRep_Tool::Surface(f); - else if (s2.IsNull()) + } else if (s2.IsNull()) { + if (adapt.GetType() == GeomAbs_Plane) { + gp_Trsf mov; + mov.SetTranslation(offset2 * gp_Vec(adapt.Plane().Axis().Direction())); + TopLoc_Location loc(mov); + f.Move(loc); + } s2 = BRep_Tool::Surface(f); - else + } else { + if (adapt.GetType() == GeomAbs_Plane) { + gp_Trsf mov; + mov.SetTranslation(offset3 * gp_Vec(adapt.Plane().Axis().Direction())); + TopLoc_Location loc(mov); + f.Move(loc); + } s3 = BRep_Tool::Surface(f); + } } } else { return; //"PartDesign::Point: Invalid reference type" @@ -244,22 +268,47 @@ void Point::onChanged(const App::Property* prop) if (point != NULL) { // Point from vertex or other point. Nothing to be done + } else if (circle != NULL) { + // Point from center of circle (or arc) + gp_Pnt centre = circle->Axis().Location(); + point = new Base::Vector3d(centre.X(), centre.Y(), centre.Z()); } else if (!c1.IsNull()) { if (!c2.IsNull()) { - // Point from intersection of two curves + // Point from intersection of two curves GeomAPI_ExtremaCurveCurve intersector(c1, c2); if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) return; // No intersection // Note: We don't check for multiple intersection points gp_Pnt p, p2; intersector.Points(1, p, p2); + + // Apply offset if the curves are linear (meaning they define a plane that contains them both) + if ((c1->DynamicType() == STANDARD_TYPE(Geom_Line)) && (c2->DynamicType() == STANDARD_TYPE(Geom_Line))) { + // Get translation vectors + Handle_Geom_Line lin1 = Handle_Geom_Line::DownCast(c1); + Handle_Geom_Line lin2 = Handle_Geom_Line::DownCast(c2); + gp_Dir normal = lin1->Lin().Direction().Crossed(lin2->Lin().Direction()); // normal of the plane + gp_Dir trans1 = normal.Crossed(lin1->Lin().Direction()); + gp_Dir trans2 = normal.Crossed(lin2->Lin().Direction()); + double offset1 = Offset.getValue(); + double offset2 = Offset2.getValue(); + c1->Translate(offset1 * gp_Vec(trans1)); + c2->Translate(offset2 * gp_Vec(trans2)); + // Intersect again + intersector = GeomAPI_ExtremaCurveCurve(c1, c2); + if ((intersector.LowerDistance() > Precision::Confusion()) || (intersector.NbExtrema() == 0)) + return; // No intersection + // Note: We don't check for multiple intersection points + intersector.Points(1, p, p2); + } + point = new Base::Vector3d(p.X(), p.Y(), p.Z()); } else if (!s1.IsNull()) { GeomAPI_IntCS intersector(c1, s1); if (!intersector.IsDone() || (intersector.NbPoints() == 0)) return; if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from curve and surface"); + Base::Console().Warning("More than one intersection point for datum point from curve and surface\n"); gp_Pnt p = intersector.Point(1); point = new Base::Vector3d(p.X(), p.Y(), p.Z()); @@ -270,14 +319,14 @@ void Point::onChanged(const App::Property* prop) if (!intersectorSS.IsDone() || (intersectorSS.NbLines() == 0)) return; if (intersectorSS.NbLines() > 1) - Base::Console().Warning("More than one intersection line for datum point from surfaces"); + Base::Console().Warning("More than one intersection line for datum point from surfaces\n"); Handle_Geom_Curve line = intersectorSS.Line(1); GeomAPI_IntCS intersector(line, s3); if (!intersector.IsDone() || (intersector.NbPoints() == 0)) return; if (intersector.NbPoints() > 1) - Base::Console().Warning("More than one intersection point for datum point from surfaces"); + Base::Console().Warning("More than one intersection point for datum point from surfaces\n"); gp_Pnt p = intersector.Point(1); point = new Base::Vector3d(p.X(), p.Y(), p.Z()); @@ -307,6 +356,19 @@ const std::set Point::getHint() return std::set(); } +const int Point::offsetsAllowed() const +{ + int numlines = 0, numplanes = 0; + for (std::multiset::const_iterator r = refTypes.begin(); r != refTypes.end(); r++) { + if (*r == LINE) numlines++; + else if (*r == PLANE) numplanes++; + } + + if (numlines == 2) return 2; // Special case: Two intersecting lines. TODO: Check for co-planarity + return numplanes; +} + + namespace PartDesign { const QString getRefType(const App::DocumentObject* obj, const std::string& subname) @@ -320,13 +382,16 @@ const QString getRefType(const App::DocumentObject* obj, const std::string& subn else if (type == PartDesign::Point::getClassTypeId()) return POINT; else if (type.isDerivedFrom(Part::Feature::getClassTypeId())) { - if (subname.size() > 4 && subname.substr(0,4) == "Face") { - const Part::Feature* feature = static_cast(obj); - Part::TopoShape topShape = feature->Shape.getShape(); - TopoDS_Shape shape = topShape.getSubShape(subname.c_str()); - if (shape.IsNull() || (shape.ShapeType() != TopAbs_FACE)) + const Part::Feature* feature = static_cast(obj); + const Part::TopoShape& topShape = feature->Shape.getShape(); + if (topShape.isNull()) + return QString::fromAscii("EMPTYSHAPE"); // Can happen on file loading + + if (subname.size() > 4 && subname.substr(0,4) == "Face") { + TopoDS_Shape face = topShape.getSubShape(subname.c_str()); + if (face.IsNull() || (face.ShapeType() != TopAbs_FACE)) throw Base::Exception("Part::Datum::getRefType(): No valid subshape could be extracted"); - BRepAdaptor_Surface adapt(TopoDS::Face(shape)); + BRepAdaptor_Surface adapt(TopoDS::Face(face)); if (adapt.GetType() == GeomAbs_Plane) return PLANE; else if (adapt.GetType() == GeomAbs_Cylinder) diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 1c0876310fa0..7d953bf4992d 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -108,6 +108,10 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p connect(ui->spinOffset, SIGNAL(valueChanged(double)), this, SLOT(onOffsetChanged(double))); + connect(ui->spinOffset2, SIGNAL(valueChanged(double)), + this, SLOT(onOffset2Changed(double))); + connect(ui->spinOffset3, SIGNAL(valueChanged(double)), + this, SLOT(onOffset3Changed(double))); connect(ui->spinAngle, SIGNAL(valueChanged(double)), this, SLOT(onAngleChanged(double))); connect(ui->checkBoxFlip, SIGNAL(toggled(bool)), @@ -129,6 +133,8 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p // Temporarily prevent unnecessary feature recomputes ui->spinOffset->blockSignals(true); + ui->spinOffset2->blockSignals(true); + ui->spinOffset3->blockSignals(true); ui->spinAngle->blockSignals(true); ui->checkBoxFlip->blockSignals(true); ui->buttonRef1->blockSignals(true); @@ -145,10 +151,14 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p //bool checked1 = pcDatum->Checked.getValue(); double offset = pcDatum->Offset.getValue(); + double offset2 = pcDatum->Offset2.getValue(); + double offset3 = pcDatum->Offset3.getValue(); double angle = pcDatum->Angle.getValue(); // Fill data into dialog elements ui->spinOffset->setValue(offset); + ui->spinOffset2->setValue(offset2); + ui->spinOffset3->setValue(offset3); ui->spinAngle->setValue(angle); //ui->checkBoxFlip->setChecked(checked1); std::vector refstrings; @@ -162,6 +172,8 @@ TaskDatumParameters::TaskDatumParameters(ViewProviderDatum *DatumView,QWidget *p // activate and de-activate dialog elements as appropriate ui->spinOffset->blockSignals(false); + ui->spinOffset2->blockSignals(false); + ui->spinOffset3->blockSignals(false); ui->spinAngle->blockSignals(false); ui->checkBoxFlip->blockSignals(false); ui->buttonRef1->blockSignals(false); @@ -198,11 +210,41 @@ const QString makeRefText(std::set hint) void TaskDatumParameters::updateUI() { ui->checkBoxFlip->setVisible(false); + + int numOffsets = static_cast(DatumView->getObject())->offsetsAllowed(); + if (numOffsets == 0) { + ui->labelOffset->setVisible(false); + ui->spinOffset->setVisible(false); + ui->labelOffset2->setVisible(false); + ui->spinOffset2->setVisible(false); + ui->labelOffset3->setVisible(false); + ui->spinOffset3->setVisible(false); + } else if (numOffsets == 1) { + ui->labelOffset->setVisible(true); + ui->spinOffset->setVisible(true); + ui->labelOffset2->setVisible(false); + ui->spinOffset2->setVisible(false); + ui->labelOffset3->setVisible(false); + ui->spinOffset3->setVisible(false); + } else if (numOffsets == 2) { + ui->labelOffset->setVisible(true); + ui->spinOffset->setVisible(true); + ui->labelOffset2->setVisible(true); + ui->spinOffset2->setVisible(true); + ui->labelOffset3->setVisible(false); + ui->spinOffset3->setVisible(false); + } else if (numOffsets == 3) { + ui->labelOffset->setVisible(true); + ui->spinOffset->setVisible(true); + ui->labelOffset2->setVisible(true); + ui->spinOffset2->setVisible(true); + ui->labelOffset3->setVisible(true); + ui->spinOffset3->setVisible(true); + } + if (DatumView->datumType != QObject::tr("Plane")) { ui->labelAngle->setVisible(false); - ui->labelOffset->setVisible(false); ui->spinAngle->setVisible(false); - ui->spinOffset->setVisible(false); } Part::Datum* pcDatum = static_cast(DatumView->getObject()); @@ -357,6 +399,22 @@ void TaskDatumParameters::onOffsetChanged(double val) updateUI(); } +void TaskDatumParameters::onOffset2Changed(double val) +{ + Part::Datum* pcDatum = static_cast(DatumView->getObject()); + pcDatum->Offset2.setValue(val); + pcDatum->getDocument()->recomputeFeature(pcDatum); + updateUI(); +} + +void TaskDatumParameters::onOffset3Changed(double val) +{ + Part::Datum* pcDatum = static_cast(DatumView->getObject()); + pcDatum->Offset3.setValue(val); + pcDatum->getDocument()->recomputeFeature(pcDatum); + updateUI(); +} + void TaskDatumParameters::onAngleChanged(double val) { Part::Datum* pcDatum = static_cast(DatumView->getObject()); @@ -518,6 +576,16 @@ double TaskDatumParameters::getOffset() const return ui->spinOffset->value(); } +double TaskDatumParameters::getOffset2() const +{ + return ui->spinOffset2->value(); +} + +double TaskDatumParameters::getOffset3() const +{ + return ui->spinOffset3->value(); +} + double TaskDatumParameters::getAngle() const { return ui->spinAngle->value(); @@ -561,6 +629,8 @@ void TaskDatumParameters::changeEvent(QEvent *e) TaskBox::changeEvent(e); if (e->type() == QEvent::LanguageChange) { ui->spinOffset->blockSignals(true); + ui->spinOffset2->blockSignals(true); + ui->spinOffset3->blockSignals(true); ui->spinAngle->blockSignals(true); ui->checkBoxFlip->blockSignals(true); ui->buttonRef1->blockSignals(true); @@ -580,6 +650,8 @@ void TaskDatumParameters::changeEvent(QEvent *e) // TODO: Translate DatumView->datumType ? ui->spinOffset->blockSignals(false); + ui->spinOffset2->blockSignals(false); + ui->spinOffset3->blockSignals(false); ui->spinAngle->blockSignals(false); ui->checkBoxFlip->blockSignals(false); ui->buttonRef1->blockSignals(false); @@ -634,6 +706,8 @@ bool TaskDlgDatumParameters::accept() try { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset = %f",name.c_str(),parameter->getOffset()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset2 = %f",name.c_str(),parameter->getOffset2()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Offset3 = %f",name.c_str(),parameter->getOffset3()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle()); //Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Checked = %i",name.c_str(),parameter->getCheckBox1()?1:0); diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.h b/src/Mod/PartDesign/Gui/TaskDatumParameters.h index dc9a4fea4ff5..e2a8e61a2837 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.h @@ -55,12 +55,16 @@ class TaskDatumParameters : public Gui::TaskView::TaskBox, public Gui::Selection QString getReference(const int idx) const; double getOffset(void) const; + double getOffset2(void) const; + double getOffset3(void) const; double getAngle(void) const; bool getFlip(void) const; const bool isCompleted() const { return completed; } private Q_SLOTS: void onOffsetChanged(double); + void onOffset2Changed(double); + void onOffset3Changed(double); void onAngleChanged(double); void onCheckFlip(bool); void onRefName1(const QString& text); diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui b/src/Mod/PartDesign/Gui/TaskDatumParameters.ui index b780526d132d..0bd70d495803 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.ui @@ -7,7 +7,7 @@ 0 0 272 - 215 + 285 @@ -83,6 +83,60 @@ + + + + + + Offset + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + 5.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + Offset + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + 5.000000000000000 + + + 0.000000000000000 + + + + + From cdb49c28e55c4affd99513d632e076df9e157cb8 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 16 Sep 2013 20:38:03 +0200 Subject: [PATCH 189/664] Allow datum point and line from circular reference --- src/Mod/PartDesign/App/DatumLine.cpp | 6 ++++ src/Mod/PartDesign/App/DatumPoint.cpp | 34 +++++++++++++++---- .../PartDesign/Gui/TaskDatumParameters.cpp | 2 ++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index 4379bf71a547..368226579815 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -79,6 +79,7 @@ using namespace PartDesign; // Note: We don't distinguish between e.g. datum lines and edges here #define PLANE QObject::tr("DPLANE") #define LINE QObject::tr("DLINE") +#define CIRCLE QObject::tr("DCIRCLE") #define POINT QObject::tr("DPOINT") #define ANGLE QObject::tr("Angle") @@ -94,6 +95,10 @@ void Line::initHints() key.insert(LINE); hints[key] = DONE; // LINE -> DONE. Line from another line or edge + key.clear(); value.clear(); + key.insert(CIRCLE); + hints[key] = DONE; // CIRCLE -> DONE. Line from center of circle or arc or axis of cylinder or cylinder segment + key.clear(); value.clear(); key.insert(POINT); value.insert(POINT); @@ -167,6 +172,7 @@ void Line::onChanged(const App::Property *prop) Base::Vector3d* p1 = NULL; Base::Vector3d* p2 = NULL; gp_Lin* line = NULL; + gp_Circ* circle = NULL; Handle_Geom_Surface s1 = NULL; Handle_Geom_Surface s2 = NULL; Handle_Geom_Surface s3 = NULL; diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp index 1e99f1920977..b60412fe7fea 100644 --- a/src/Mod/PartDesign/App/DatumPoint.cpp +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -34,9 +34,11 @@ # include # include # include +# include # include # include # include +# include # include # include # include @@ -77,6 +79,7 @@ using namespace PartDesign; #define CYLINDER QObject::tr("DCYLINDER") #define LINE QObject::tr("DLINE") #define POINT QObject::tr("DPOINT") +#define CIRCLE QObject::tr("DCIRCLE") #define ANGLE QObject::tr("Angle") // ================================ Initialize the hints ===================== @@ -93,6 +96,10 @@ void Point::initHints() key.insert(POINT); hints[key] = DONE; // POINT -> DONE. Point from another point or vertex + key.clear(); value.clear(); + key.insert(CIRCLE); + hints[key] = DONE; // CIRCLE -> DONE. Point from center of circle or arc + key.clear(); value.clear(); key.insert(LINE); value.insert(LINE); value.insert(PLANE); @@ -166,6 +173,7 @@ void Point::onChanged(const App::Property* prop) Handle_Geom_Surface s1 = NULL; Handle_Geom_Surface s2 = NULL; Handle_Geom_Surface s3 = NULL; + gp_Circ* circle = NULL; for (int i = 0; i < refs.size(); i++) { if (refs[i]->getTypeId().isDerivedFrom(PartDesign::Point::getClassTypeId())) { @@ -223,11 +231,16 @@ void Point::onChanged(const App::Property* prop) point = new Base::Vector3d(p.X(), p.Y(), p.Z()); } else if (subshape.ShapeType() == TopAbs_EDGE) { TopoDS_Edge e = TopoDS::Edge(subshape); - Standard_Real first, last; - if (c1.IsNull()) - c1 = BRep_Tool::Curve(e, first, last); - else - c2 = BRep_Tool::Curve(e, first, last); + BRepAdaptor_Curve adapt(e); + if (adapt.GetType() == GeomAbs_Circle) { + circle = new gp_Circ(adapt.Circle()); + } else { + Standard_Real first, last; + if (c1.IsNull()) + c1 = BRep_Tool::Curve(e, first, last); + else + c2 = BRep_Tool::Curve(e, first, last); + } } else if (subshape.ShapeType() == TopAbs_FACE) { TopoDS_Face f = TopoDS::Face(subshape); double offset1 = Offset.getValue(); @@ -337,6 +350,7 @@ void Point::onChanged(const App::Property* prop) Placement.setValue(Base::Placement(*point, Base::Rotation())); delete point; + if (circle != NULL) delete circle; } Part::Datum::onChanged(prop); @@ -399,8 +413,14 @@ const QString getRefType(const App::DocumentObject* obj, const std::string& subn else throw Base::Exception("Part::Datum::getRefType(): Only planar and cylindrical faces are allowed"); } else if (subname.size() > 4 && subname.substr(0,4) == "Edge") { - // Note: For now, only linear references are possible - return LINE; + TopoDS_Shape edge = topShape.getSubShape(subname.c_str()); + if (edge.IsNull() || (edge.ShapeType() != TopAbs_EDGE)) + throw Base::Exception("Part::Datum::getRefType(): No valid subshape could be extracted"); + BRepAdaptor_Curve adapt(TopoDS::Edge(edge)); + if (adapt.GetType() == GeomAbs_Circle) + return CIRCLE; + else // We don't check for other types yet + return LINE; } else if (subname.size() > 6 && subname.substr(0,6) == "Vertex") { return POINT; } diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 7d953bf4992d..ef3a49f637ff 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -194,6 +194,8 @@ const QString makeRefText(std::set hint) tText = QObject::tr("Plane"); else if (((*t) == QObject::tr("DLINE")) || ((*t) == QObject::tr("Line"))) tText = QObject::tr("Line"); + else if (((*t) == QObject::tr("DCIRCLE")) || ((*t) == QObject::tr("Circle"))) + tText = QObject::tr("Circle"); else if (((*t) == QObject::tr("DPOINT")) || ((*t) == QObject::tr("Point"))) tText = QObject::tr("Point"); else if (((*t) == QObject::tr("DCYLINDER")) || ((*t) == QObject::tr("Cylinder"))) From 4623f3a7d309110deb14d3d0b09a9cf9941e4fa0 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 16 Sep 2013 20:38:39 +0200 Subject: [PATCH 190/664] Some code cosmetics --- src/Mod/PartDesign/App/DatumLine.cpp | 3 ++- src/Mod/PartDesign/App/DatumLine.h | 3 ++- src/Mod/PartDesign/App/DatumPlane.cpp | 2 +- src/Mod/PartDesign/App/DatumPlane.h | 3 ++- src/Mod/PartDesign/App/DatumPoint.cpp | 2 +- src/Mod/PartDesign/App/DatumPoint.h | 3 ++- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Mod/PartDesign/App/DatumLine.cpp b/src/Mod/PartDesign/App/DatumLine.cpp index 368226579815..1134344fe478 100644 --- a/src/Mod/PartDesign/App/DatumLine.cpp +++ b/src/Mod/PartDesign/App/DatumLine.cpp @@ -362,12 +362,13 @@ void Line::onChanged(const App::Property *prop) if (p1 != NULL) delete p1; if (p2 != NULL) delete p2; if (line != NULL) delete line; + if (circle != NULL) delete circle; } Part::Datum::onChanged(prop); } -const std::set Line::getHint() +const std::set Line::getHint() const { if (hints.find(refTypes) != hints.end()) return hints[refTypes]; diff --git a/src/Mod/PartDesign/App/DatumLine.h b/src/Mod/PartDesign/App/DatumLine.h index 14eaf3ef1538..b6785364924f 100644 --- a/src/Mod/PartDesign/App/DatumLine.h +++ b/src/Mod/PartDesign/App/DatumLine.h @@ -45,7 +45,8 @@ class PartDesignExport Line : public Part::Datum } static void initHints(); - const std::set getHint(); + const std::set getHint() const; + const int offsetsAllowed() const; Base::Vector3d getBasePoint() const; Base::Vector3d getDirection() const; diff --git a/src/Mod/PartDesign/App/DatumPlane.cpp b/src/Mod/PartDesign/App/DatumPlane.cpp index 6415b5e1f17d..0ab7582b0d14 100644 --- a/src/Mod/PartDesign/App/DatumPlane.cpp +++ b/src/Mod/PartDesign/App/DatumPlane.cpp @@ -358,7 +358,7 @@ void Plane::onChanged(const App::Property *prop) } -const std::set Plane::getHint() +const std::set Plane::getHint() const { if (hints.find(refTypes) != hints.end()) return hints[refTypes]; diff --git a/src/Mod/PartDesign/App/DatumPlane.h b/src/Mod/PartDesign/App/DatumPlane.h index d64ed690044d..3d78165b6407 100644 --- a/src/Mod/PartDesign/App/DatumPlane.h +++ b/src/Mod/PartDesign/App/DatumPlane.h @@ -44,7 +44,8 @@ class PartDesignExport Plane : public Part::Datum } static void initHints(); - const std::set getHint(); + const std::set getHint() const; + const int offsetsAllowed() const; Base::Vector3d getBasePoint(); Base::Vector3d getNormal(); diff --git a/src/Mod/PartDesign/App/DatumPoint.cpp b/src/Mod/PartDesign/App/DatumPoint.cpp index b60412fe7fea..1a3d9b667cc0 100644 --- a/src/Mod/PartDesign/App/DatumPoint.cpp +++ b/src/Mod/PartDesign/App/DatumPoint.cpp @@ -362,7 +362,7 @@ Base::Vector3d Point::getPoint() } -const std::set Point::getHint() +const std::set Point::getHint() const { if (hints.find(refTypes) != hints.end()) return hints[refTypes]; diff --git a/src/Mod/PartDesign/App/DatumPoint.h b/src/Mod/PartDesign/App/DatumPoint.h index 8f9be2b2da87..0a23e064d276 100644 --- a/src/Mod/PartDesign/App/DatumPoint.h +++ b/src/Mod/PartDesign/App/DatumPoint.h @@ -45,7 +45,8 @@ class PartDesignExport Point : public Part::Datum } static void initHints(); - const std::set getHint(); + const std::set getHint() const; + const int offsetsAllowed() const; Base::Vector3d getPoint(); From e993480ca00c3ee4f1b44a786f32cc7912879c82 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 20 Sep 2013 20:00:21 +0200 Subject: [PATCH 191/664] Made Body::claimChildren() stabler against NULL items --- src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index eaeddc8e2430..1279c3308b91 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -115,10 +115,14 @@ std::vector ViewProviderBody::claimChildren(void)const // search for objects handled (claimed) by the features for(std::vector::const_iterator it = Model.begin();it!=Model.end();++it){ - std::vector children = Gui::Application::Instance->getViewProvider(*it)->claimChildren(); - for (std::vector::const_iterator ch = children.begin(); ch != children.end(); ch++) + if (*it == NULL) continue; + Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(*it); + if (vp == NULL) continue; + std::vector children = vp->claimChildren(); + for (std::vector::const_iterator ch = children.begin(); ch != children.end(); ch++) { if ((*ch) != NULL) OutSet.insert(*ch); + } } // remove the otherwise handled objects, preserving their order so the order in the TreeWidget is correct From 853adf7d9df740c10fd79b119bd587a919267d57 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 20 Sep 2013 20:35:09 +0200 Subject: [PATCH 192/664] Highlighting for datum features --- .../PartDesign/Gui/ViewProviderDatumLine.cpp | 47 +++----- .../PartDesign/Gui/ViewProviderDatumPlane.cpp | 103 ++++++++++++------ .../PartDesign/Gui/ViewProviderDatumPoint.cpp | 41 +++---- 3 files changed, 98 insertions(+), 93 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp index 79426eaff90d..fa0bd4931d05 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp @@ -25,17 +25,8 @@ #ifndef _PreComp_ # include -# include -# include # include -# include -# include -# include -# include -# include -# include -# include -# include +# include # include # include # include @@ -49,6 +40,9 @@ #include "ViewProviderDatumLine.h" #include "TaskDatumParameters.h" #include "Workbench.h" +#include +#include +#include #include #include #include @@ -101,29 +95,24 @@ void ViewProviderDatumLine::updateData(const App::Property* prop) } // Display the line - SoMFVec3f v; - v.setNum(2); - v.set1Value(0, p1.x, p1.y, p1.z); - v.set1Value(1, p2.x, p2.y, p2.z); - SoMFInt32 idx; - idx.setNum(1); - idx.set1Value(0, 2); - - SoLineSet* lineSet; - SoVertexProperty* vprop; + PartGui::SoBrepEdgeSet* lineSet; + SoCoordinate3* coord; if (pShapeSep->getNumChildren() == 1) { - lineSet = new SoLineSet(); - vprop = new SoVertexProperty(); - vprop->vertex = v; - lineSet->vertexProperty = vprop; - lineSet->numVertices = idx; + coord = new SoCoordinate3(); + coord->point.setNum(2); + coord->point.set1Value(0, p1.x, p1.y, p1.z); + coord->point.set1Value(1, p2.x, p2.y, p2.z); + pShapeSep->addChild(coord); + lineSet = new PartGui::SoBrepEdgeSet(); + lineSet->coordIndex.setNum(2); + lineSet->coordIndex.set1Value(0, 0); + lineSet->coordIndex.set1Value(1, 1); pShapeSep->addChild(lineSet); } else { - lineSet = static_cast(pShapeSep->getChild(1)); - vprop = static_cast(lineSet->vertexProperty.getValue()); - vprop->vertex = v; - lineSet->numVertices = idx; + coord = static_cast(pShapeSep->getChild(1)); + coord->point.set1Value(0, p1.x, p1.y, p1.z); + coord->point.set1Value(1, p2.x, p2.y, p2.z); } } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index d8fbec81fcba..7305f6962825 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -25,17 +25,9 @@ #ifndef _PreComp_ # include -# include -# include # include -# include -# include -# include +# include # include -# include -# include -# include -# include # include # include # include @@ -50,6 +42,9 @@ #include "TaskDatumParameters.h" #include "Workbench.h" #include +#include +#include +#include #include #include #include @@ -185,38 +180,74 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) } // Display the plane - SoMFVec3f v; - v.setNum(points.size()); - for (int p = 0; p < points.size(); p++) - v.set1Value(p, points[p].x, points[p].y, points[p].z); - SoMFInt32 idx; - idx.setNum(1); - idx.set1Value(0, points.size()); - - SoFaceSet* faceSet; - SoLineSet* lineSet; - SoVertexProperty* vprop; + // Note: To achieve different colours on the two sides of the plane, see: + // http://doc.coin3d.org/Coin/classSoIndexedFaceSet.html + SoCoordinate3* coord; + PartGui::SoBrepFaceSet* faceSet; + SoIndexedLineSet* lineSet; if (pShapeSep->getNumChildren() == 1) { - faceSet = new SoFaceSet(); - vprop = new SoVertexProperty(); - vprop->vertex = v; - faceSet->vertexProperty = vprop; - faceSet->numVertices = idx; + // The polygon must be split up into triangles because the SoBRepFaceSet only handles those + if (points.size() < 3) + return; + coord = new SoCoordinate3(); + coord->point.setNum(points.size()); + for (int p = 0; p < points.size(); p++) + coord->point.set1Value(p, points[p].x, points[p].y, points[p].z); + pShapeSep->addChild(coord); + + faceSet = new PartGui::SoBrepFaceSet(); + faceSet->partIndex.setNum(1); // One face + faceSet->partIndex.set1Value(0, points.size()-3 + 1); // with this many triangles + faceSet->coordIndex.setNum(4 + 4*(points.size()-3)); + // The first triangle + faceSet->coordIndex.set1Value(0, 0); + faceSet->coordIndex.set1Value(1, 1); + faceSet->coordIndex.set1Value(2, 2); + faceSet->coordIndex.set1Value(3, SO_END_FACE_INDEX); + // One more triangle for every extra polygon point + for (int p = 3; p < points.size(); p++) { + faceSet->coordIndex.set1Value(4 + 4*(p-3), 0); + faceSet->coordIndex.set1Value(4 + 4*(p-3) + 1, p-1); + faceSet->coordIndex.set1Value(4 + 4*(p-3) + 2, p); + faceSet->coordIndex.set1Value(4 + 4*(p-3) + 3, SO_END_FACE_INDEX); + } pShapeSep->addChild(faceSet); - lineSet = new SoLineSet(); - lineSet->vertexProperty = vprop; - lineSet->numVertices = idx; + + lineSet = new SoIndexedLineSet(); + lineSet->coordIndex.setNum(points.size()+2); + for (int p = 0; p < points.size(); p++) + lineSet->coordIndex.set1Value(p, p); + lineSet->coordIndex.set1Value(points.size(), 0); + lineSet->coordIndex.set1Value(points.size()+1, SO_END_LINE_INDEX); pShapeSep->addChild(lineSet); } else { - faceSet = static_cast(pShapeSep->getChild(1)); - vprop = static_cast(faceSet->vertexProperty.getValue()); - vprop->vertex = v; - faceSet->numVertices = idx; - lineSet = static_cast(pShapeSep->getChild(2)); - vprop = static_cast(lineSet->vertexProperty.getValue()); - vprop->vertex = v; - lineSet->numVertices = idx; + coord = static_cast(pShapeSep->getChild(1)); + coord->point.setNum(points.size()); + for (int p = 0; p < points.size(); p++) + coord->point.set1Value(p, points[p].x, points[p].y, points[p].z); + faceSet = static_cast(pShapeSep->getChild(2)); + faceSet->partIndex.setNum(1); // One face + faceSet->partIndex.set1Value(0, points.size()-3 + 1); // with this many triangles + faceSet->coordIndex.setNum(4 + 4*(points.size()-3)); + // The first triangle + faceSet->coordIndex.set1Value(0, 0); + faceSet->coordIndex.set1Value(1, 1); + faceSet->coordIndex.set1Value(2, 2); + faceSet->coordIndex.set1Value(3, SO_END_FACE_INDEX); + // One more triangle for every extra polygon point + for (int p = 3; p < points.size(); p++) { + faceSet->coordIndex.set1Value(4 + 4*(p-3), 0); + faceSet->coordIndex.set1Value(4 + 4*(p-3) + 1, p-1); + faceSet->coordIndex.set1Value(4 + 4*(p-3) + 2, p); + faceSet->coordIndex.set1Value(4 + 4*(p-3) + 3, SO_END_FACE_INDEX); + } + lineSet = static_cast(pShapeSep->getChild(3)); + lineSet->coordIndex.setNum(points.size()+2); + for (int p = 0; p < points.size(); p++) + lineSet->coordIndex.set1Value(p, p); + lineSet->coordIndex.set1Value(points.size(), 0); + lineSet->coordIndex.set1Value(points.size()+1, SO_END_LINE_INDEX); } } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp index 00885839237f..b5ad2eaa05cc 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPoint.cpp @@ -25,35 +25,15 @@ #ifndef _PreComp_ # include -# include -# include -# include -# include # include # include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include #endif #include "ViewProviderDatumPoint.h" -#include "TaskDatumParameters.h" -#include "Workbench.h" +#include +#include +#include #include -#include -#include -#include -#include using namespace PartDesignGui; @@ -61,16 +41,21 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPoint,PartDesignGui::ViewProvide ViewProviderDatumPoint::ViewProviderDatumPoint() { - SoMarkerSet* points = new SoMarkerSet(); - points->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; SoMFVec3f v; v.setNum(1); v.set1Value(0, 0,0,0); SoVertexProperty* vprop = new SoVertexProperty(); vprop->vertex = v; + // Using a marker gives a larger point but it doesn't do highlighting automatically like the SoBrepPointSet + SoMarkerSet* marker = new SoMarkerSet(); + marker->markerIndex = SoMarkerSet::DIAMOND_FILLED_9_9; + marker->vertexProperty = vprop; + marker->numPoints = 1; + PartGui::SoBrepPointSet* points = new PartGui::SoBrepPointSet(); points->vertexProperty = vprop; points->numPoints = 1; pShapeSep->addChild(points); + pShapeSep->addChild(marker); } ViewProviderDatumPoint::~ViewProviderDatumPoint() @@ -81,10 +66,10 @@ void ViewProviderDatumPoint::updateData(const App::Property* prop) { if (strcmp(prop->getName(),"Placement") == 0) { // The only reason to do this is to display the point in the correct position after loading the document - SoMarkerSet* points = static_cast(pShapeSep->getChild(0)); + SoMarkerSet* marker = static_cast(pShapeSep->getChild(1)); + marker->touch(); + PartGui::SoBrepPointSet* points = static_cast(pShapeSep->getChild(0)); points->touch(); - //points->numPoints = 0; - //points->numPoints = 1; } ViewProviderDatum::updateData(prop); From 8e1ea4ac14a4d773d768c8355df3b31c577f78f2 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 23 Sep 2013 19:58:52 +0200 Subject: [PATCH 193/664] Removed some old code --- src/Mod/Part/App/PartFeature.cpp | 11 +---------- src/Mod/Part/App/PartFeature.h | 6 ------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 4ca176884d2a..2843cecb8b55 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include "PartFeature.h" #include "PartFeaturePy.h" @@ -232,15 +232,6 @@ ShapeHistory Feature::joinHistory(const ShapeHistory& oldH, const ShapeHistory& return join; } -const TopoDS_Shape Feature::findOriginOf(const TopoDS_Shape& reference) { -/* Base::Console().Error("Looking for origin of face in %s\n", this->getName()); - if (reference.ShapeType() == TopAbs_FACE) { - // Find index of reference in the history - } -*/ - return TopoDS_Shape(); -} - /// returns the type name of the ViewProvider const char* Feature::getViewProviderName(void) const { return "PartGui::ViewProviderPart"; diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index d724cf6acd64..46898c123393 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -68,12 +68,6 @@ class PartExport Feature : public App::GeoFeature virtual PyObject* getPyObject(void); virtual std::vector getPySubObjects(const std::vector&) const; - /** - * Find the origin of a reference, e.g. the vertex or edge in a sketch that - * produced a face - */ - const TopoDS_Shape findOriginOf(const TopoDS_Shape& reference); - protected: void onChanged(const App::Property* prop); TopLoc_Location getLocation() const; From ae1890f56baf57e9ef7f16e49aad4332666335c1 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 31 Aug 2013 16:52:28 +0200 Subject: [PATCH 194/664] Python functions to intersect curves and surfaces --- src/Mod/Part/App/GeometryCurvePy.xml | 21 ++++ src/Mod/Part/App/GeometryCurvePyImp.cpp | 120 +++++++++++++++++++++ src/Mod/Part/App/GeometrySurfacePy.xml | 17 +++ src/Mod/Part/App/GeometrySurfacePyImp.cpp | 125 ++++++++++++++++++++++ 4 files changed, 283 insertions(+) diff --git a/src/Mod/Part/App/GeometryCurvePy.xml b/src/Mod/Part/App/GeometryCurvePy.xml index a70c115fbaa2..039578f8a4a2 100644 --- a/src/Mod/Part/App/GeometryCurvePy.xml +++ b/src/Mod/Part/App/GeometryCurvePy.xml @@ -89,6 +89,27 @@ length([uMin,uMax,Tol]) -> Float of the nearest orthogonal projection of the point. + + + + Returns all intersection points and curve segments between the curve and the curve/surface. + + + + + + + Returns all intersection points and curve segments between the curve and the surface. + + + + + + + Returns all intersection points between this curve and the given curve. + + + diff --git a/src/Mod/Part/App/GeometryCurvePyImp.cpp b/src/Mod/Part/App/GeometryCurvePyImp.cpp index ca96b9b77be4..77378944d6f3 100644 --- a/src/Mod/Part/App/GeometryCurvePyImp.cpp +++ b/src/Mod/Part/App/GeometryCurvePyImp.cpp @@ -51,6 +51,8 @@ # include # include # include +# include +# include #endif #include @@ -62,6 +64,7 @@ #include "RectangularTrimmedSurfacePy.h" #include "BSplineSurfacePy.h" #include "PlanePy.h" +#include "PointPy.h" #include "BSplineCurvePy.h" #include "OCCError.h" @@ -69,6 +72,9 @@ #include "TopoShapePy.h" #include "TopoShapeEdgePy.h" +// TODO: This should be somewhere globally, but where? Currently located in GeometrySurfacePyImp.cpp +extern const Py::Object makeGeometryCurvePy(const Handle_Geom_Curve& c); + using namespace Part; // returns a string which represents the object e.g. when printed in python @@ -606,3 +612,117 @@ int GeometryCurvePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/ { return 0; } + +// Specialized intersection functions + +PyObject* GeometryCurvePy::intersectCS(PyObject *args) +{ + Handle_Geom_Curve curve = Handle_Geom_Curve::DownCast(getGeometryPtr()->handle()); + try { + if (!curve.IsNull()) { + PyObject *p; + double prec = Precision::Confusion(); + if (!PyArg_ParseTuple(args, "O!|d", &(Part::GeometrySurfacePy::Type), &p, &prec)) + return 0; + Handle_Geom_Surface surf = Handle_Geom_Surface::DownCast(static_cast(p)->getGeometryPtr()->handle()); + GeomAPI_IntCS intersector(curve, surf); + if (!intersector.IsDone()) { + PyErr_SetString(PyExc_Exception, "Intersection of curve and surface failed"); + return 0; + } + + Py::List points; + for (int i = 1; i <= intersector.NbPoints(); i++) { + gp_Pnt p = intersector.Point(i); + points.append(Py::Object(new PointPy(new GeomPoint(Base::Vector3d(p.X(), p.Y(), p.Z()))))); + } + Py::List segments; + for (int i = 1; i <= intersector.NbSegments(); i++) { + Handle_Geom_Curve seg = intersector.Segment(i); + segments.append(makeGeometryCurvePy(seg)); + } + + Py::Tuple tuple(2); + tuple.setItem(0, points); + tuple.setItem(1, segments); + return Py::new_reference_to(tuple); + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + + PyErr_SetString(PyExc_Exception, "Geometry is not a curve"); + return 0; +} + +PyObject* GeometryCurvePy::intersectCC(PyObject *args) +{ + Handle_Geom_Curve curve1 = Handle_Geom_Curve::DownCast(getGeometryPtr()->handle()); + try { + if (!curve1.IsNull()) { + PyObject *p; + double prec = Precision::Confusion(); + if (!PyArg_ParseTuple(args, "O!|d", &(Part::GeometrySurfacePy::Type), &p, &prec)) + return 0; + Handle_Geom_Curve curve2 = Handle_Geom_Curve::DownCast(static_cast(p)->getGeometryPtr()->handle()); + GeomAPI_ExtremaCurveCurve intersector(curve1, curve2); + if (intersector.LowerDistance() > Precision::Confusion()) { + // No intersection + return Py::new_reference_to(Py::List()); + } + + Py::List points; + for (int i = 1; i <= intersector.NbExtrema(); i++) { + if (intersector.Distance(i) > Precision::Confusion()) + continue; + gp_Pnt p1, p2; + intersector.Points(i, p1, p2); + points.append(Py::Object(new PointPy(new GeomPoint(Base::Vector3d(p1.X(), p1.Y(), p1.Z()))))); + } + + return Py::new_reference_to(points); + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + + PyErr_SetString(PyExc_Exception, "Geometry is not a curve"); + return 0; +} + +// General intersection function + +PyObject* GeometryCurvePy::intersect(PyObject *args) +{ + Handle_Geom_Curve curve = Handle_Geom_Curve::DownCast(getGeometryPtr()->handle()); + try { + if (!curve.IsNull()) { + PyObject *p; + double prec = Precision::Confusion(); + try { + if (PyArg_ParseTuple(args, "O!|d", &(Part::GeometryCurvePy::Type), &p, &prec)) + return intersectCC(args); + } catch(...) {} + PyErr_Clear(); + + if (PyArg_ParseTuple(args, "O!|d", &(Part::GeometrySurfacePy::Type), &p, &prec)) + return intersectCS(args); + else + return 0; + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + + PyErr_SetString(PyExc_Exception, "Geometry is not a curve"); + return 0; +} diff --git a/src/Mod/Part/App/GeometrySurfacePy.xml b/src/Mod/Part/App/GeometrySurfacePy.xml index 3090e5cb0040..ddc964d793fe 100644 --- a/src/Mod/Part/App/GeometrySurfacePy.xml +++ b/src/Mod/Part/App/GeometrySurfacePy.xml @@ -105,5 +105,22 @@ The required arguments are: + + + + Returns all intersection points/curves between the surface and the curve/surface. + + + + + + + Returns all intersection curves of this surface and the given surface. +The required arguments are: +* Second surface +* precision code (optional, default=0) + + + diff --git a/src/Mod/Part/App/GeometrySurfacePyImp.cpp b/src/Mod/Part/App/GeometrySurfacePyImp.cpp index 8e10a218e2cc..792d6f158479 100644 --- a/src/Mod/Part/App/GeometrySurfacePyImp.cpp +++ b/src/Mod/Part/App/GeometrySurfacePyImp.cpp @@ -34,6 +34,7 @@ # include # include # include +# include #endif #include @@ -43,12 +44,62 @@ #include "Geometry.h" #include "GeometrySurfacePy.h" #include "GeometrySurfacePy.cpp" +#include "GeometryCurvePy.h" #include "BSplineSurfacePy.h" #include "TopoShape.h" #include "TopoShapePy.h" #include "TopoShapeFacePy.h" +// TODO: This should be somewhere globally, but where? +// ------------------------------ +# include +# include +# include +# include +# include +# include +# include + +const Py::Object makeGeometryCurvePy(const Handle_Geom_Curve& c) +{ + if (c->IsKind(STANDARD_TYPE(Geom_Circle))) { + Handle_Geom_Circle circ = Handle_Geom_Circle::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomCircle(circ))); + } else if (c->IsKind(STANDARD_TYPE(Geom_Ellipse))) { + Handle_Geom_Ellipse ell = Handle_Geom_Ellipse::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomEllipse(ell))); + } else if (c->IsKind(STANDARD_TYPE(Geom_Hyperbola))) { + Handle_Geom_Hyperbola hyp = Handle_Geom_Hyperbola::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomHyperbola(hyp))); + } else if (c->IsKind(STANDARD_TYPE(Geom_Line))) { + Handle_Geom_Line lin = Handle_Geom_Line::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomLine(lin))); + } else if (c->IsKind(STANDARD_TYPE(Geom_OffsetCurve))) { + Handle_Geom_OffsetCurve oc = Handle_Geom_OffsetCurve::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomOffsetCurve(oc))); + } else if (c->IsKind(STANDARD_TYPE(Geom_Parabola))) { + Handle_Geom_Parabola par = Handle_Geom_Parabola::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomParabola(par))); + } else if (c->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) { + Handle_Geom_TrimmedCurve trc = Handle_Geom_TrimmedCurve::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomTrimmedCurve(trc))); + } else/* if (c->IsKind(STANDARD_TYPE(Geom_BoundedCurve))) { + Handle_Geom_BoundedCurve bc = Handle_Geom_BoundedCurve::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomBoundedCurve(bc))); + } else */if (c->IsKind(STANDARD_TYPE(Geom_BezierCurve))) { + Handle_Geom_BezierCurve bezier = Handle_Geom_BezierCurve::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomBezierCurve(bezier))); + } else if (c->IsKind(STANDARD_TYPE(Geom_BSplineCurve))) { + Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c); + return Py::Object(new GeometryCurvePy(new GeomBSplineCurve(bspline))); + } + + PyErr_SetString(PyExc_Exception, "Unknown curve type"); + return Py::Object(); +} +// --------------------------------------- + using namespace Part; // returns a string which represents the object e.g. when printed in python @@ -388,3 +439,77 @@ int GeometrySurfacePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj { return 0; } + +// Specialized intersection functions + +PyObject* GeometrySurfacePy::intersectSS(PyObject *args) +{ + Handle_Geom_Surface surf1 = Handle_Geom_Surface::DownCast(getGeometryPtr()->handle()); + try { + if (!surf1.IsNull()) { + PyObject *p; + double prec = Precision::Confusion(); + if (!PyArg_ParseTuple(args, "O!|d", &(Part::GeometrySurfacePy::Type), &p, &prec)) + return 0; + Handle_Geom_Surface surf2 = Handle_Geom_Surface::DownCast(static_cast(p)->getGeometryPtr()->handle()); + GeomAPI_IntSS intersector(surf1, surf2, prec); + if (!intersector.IsDone()) { + PyErr_SetString(PyExc_Exception, "Intersection of surfaces failed"); + return 0; + } + + Py::List result; + for (int i = 1; i <= intersector.NbLines(); i++) { + Handle_Geom_Curve line = intersector.Line(i); + result.append(makeGeometryCurvePy(line)); + } + + return Py::new_reference_to(result); + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + + PyErr_SetString(PyExc_Exception, "intersectSS(): Geometry is not a surface"); + return 0; +} + +// General intersection function + +PyObject* GeometrySurfacePy::intersect(PyObject *args) +{ + Handle_Geom_Surface surf = Handle_Geom_Surface::DownCast(getGeometryPtr()->handle()); + try { + if (!surf.IsNull()) { + PyObject *p; + double prec = Precision::Confusion(); + + try { + if (PyArg_ParseTuple(args, "O!|d", &(Part::GeometrySurfacePy::Type), &p, &prec)) + return intersectSS(args); + } catch(...) {}; + PyErr_Clear(); + + if (PyArg_ParseTuple(args, "O!|d", &(Part::GeometryCurvePy::Type), &p, &prec)) { + GeometryCurvePy* curve = static_cast(p); + PyObject* t = PyTuple_New(2); + PyTuple_SetItem(t, 0, this); + PyTuple_SetItem(t, 1, PyFloat_FromDouble(prec)); + return curve->intersectCS(t); + } else { + return 0; + } + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + + PyErr_SetString(PyExc_Exception, "intersect(): Geometry is not a surface"); + return 0; +} From f7874306b99cac64feb030b2e656bf0184991a0e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 31 Aug 2013 17:00:44 +0200 Subject: [PATCH 195/664] Allow Pyton features inside bodies --- src/Mod/PartDesign/App/Body.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 42dda0394d36..c895843540e1 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -218,20 +218,15 @@ const bool Body::isAllowed(const App::DocumentObject* f) if (f == NULL) return false; + // TODO: Should we introduce a PartDesign::FeaturePython class? This should then also return true for isSolidFeature() return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || f->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || - f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())); + f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId()) || + f->getTypeId().isDerivedFrom(Part::FeaturePython::getClassTypeId())); } void Body::addFeature(App::DocumentObject *feature) { - /* - // Remove this test if Workbench::slotNewObject() has been tested sufficiently in respect to Undo() and - // the addFeature() calls have been removed in Command.cpp - if (hasFeature(feature)) - return; - */ - // Set the BaseFeature property if (feature->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId())) { App::DocumentObject* prevSolidFeature = getPrevSolidFeature(NULL, true); From 5c18e947e6330cca549d8f1298e8b03fde64dda4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 31 Aug 2013 17:01:39 +0200 Subject: [PATCH 196/664] getActivePart() python function as complement to setActivePart() --- src/Mod/Assembly/App/AppAssemblyPy.cpp | 12 ++++ src/Mod/Assembly/App/AppAssemblyPy.cpp.orig | 75 +++++++++++++-------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp b/src/Mod/Assembly/App/AppAssemblyPy.cpp index bee08c236b16..56b9271ca014 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp @@ -78,10 +78,22 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) Py_Return; } +static PyObject * getActivePart(PyObject *, PyObject *) +{ + if (PartDesignGui::ActivePartObject == NULL) { + return Py::_None(); + } + + return PartDesignGui::ActivePartObject->getPyObject(); +} + /* registration table */ struct PyMethodDef Assembly_methods[] = { {"setActivePart" ,setActivePart ,METH_VARARGS, "setActivePart(BodyObject) -- Set the PartBody object in work."}, + {"getActivePart" ,getActivePart ,METH_NOARGS, + "getActivePart() -- Get the PartBody object in work."}, + {NULL, NULL} /* end of table marker */ }; diff --git a/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig b/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig index fa76945b129e..3e706cabbc53 100644 --- a/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig +++ b/src/Mod/Assembly/App/AppAssemblyPy.cpp.orig @@ -22,31 +22,33 @@ #include "PreCompiled.h" -#ifndef _PreComp_ -# include +#ifndef _PreComp_ +# include #endif -<<<<<<< 8ef3abc971814e64ef79a85812dd1a5827ba955f:src/Mod/Assembly/App/AppAssemblyPy.cpp -/* registration table */ -struct PyMethodDef Assembly_methods[] = { - {NULL, NULL} /* end of table marker */ -======= #include #include #include #include -#include #include #include +#include "ViewProviderBody.h" + +namespace PartDesignGui { + // pointer to the active assembly object PartDesign::Body *ActivePartObject =0; -Gui::Document *ActiveGuiDoc =0; -Gui::ViewProviderDocumentObject *ActiveVp =0; +Gui::Document *ActiveGuiDoc =0; +App::Document *ActiveAppDoc =0; +Gui::ViewProviderDocumentObject *ActiveVp =0; +// The names of the base planes. Note: The user-visible label is different from this +const char* BaseplaneNames[3] = {"BaseplaneXY", "BaseplaneXZ", "BaseplaneYZ"}; +} static PyObject * setActivePart(PyObject *self, PyObject *args) { @@ -56,31 +58,50 @@ static PyObject * setActivePart(PyObject *self, PyObject *args) // Should be set! assert(Item); - // get the gui document of the Assembly Item - if(ActivePartObject){ - - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); - ActivePartObject = 0; - - } - ActivePartObject = Item; - ActiveGuiDoc = Gui::Application::Instance->getDocument(Item->getDocument()); - ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); - - }else{ - ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); - ActivePartObject = 0; + // Set old body inactive if we are activating another body in the same document + if ((PartDesignGui::ActivePartObject != NULL) && + (PartDesignGui::ActivePartObject->getDocument() == Item->getDocument())) + PartDesignGui::ActivePartObject->IsActive.setValue(false); + PartDesignGui::ActivePartObject = Item; + PartDesignGui::ActiveAppDoc = Item->getDocument(); + PartDesignGui::ActiveGuiDoc = Gui::Application::Instance->getDocument(PartDesignGui::ActiveAppDoc); + PartDesignGui::ActiveVp = dynamic_cast (PartDesignGui::ActiveGuiDoc->getViewProvider(Item)); + PartDesignGui::ActiveVp->show(); + Item->IsActive.setValue(true); + } else { + // This handles the case of deactivating the workbench + PartDesignGui::ActivePartObject=0; + PartDesignGui::ActiveGuiDoc =0; + PartDesignGui::ActiveAppDoc =0; + PartDesignGui::ActiveVp =0; } Py_Return; } +<<<<<<< 35072e8d22a22eaf711a74958d47b351d55292ae:src/Mod/Assembly/App/AppAssemblyPy.cpp +======= +static PyObject * getActivePart(PyObject *, PyObject *) +{ + if (PartDesignGui::ActivePartObject == NULL) { + return Py::_None(); + } + + return PartDesignGui::ActivePartObject->getPyObject(); +} + +>>>>>>> getActivePart() python function as complement to setActivePart():src/Mod/PartDesign/Gui/AppPartDesignGuiPy.cpp /* registration table */ -struct PyMethodDef PartDesignGui_Import_methods[] = { +struct PyMethodDef Assembly_methods[] = { {"setActivePart" ,setActivePart ,METH_VARARGS, "setActivePart(BodyObject) -- Set the PartBody object in work."}, +<<<<<<< 35072e8d22a22eaf711a74958d47b351d55292ae:src/Mod/Assembly/App/AppAssemblyPy.cpp + {NULL, NULL} /* end of table marker */ +======= + {"getActivePart" ,getActivePart ,METH_NOARGS, + "getActivePart() -- Get the PartBody object in work."}, + {NULL, NULL} /* end of table marker */ ->>>>>>> implement active body in PartDesign:src/Mod/PartDesign/Gui/AppPartDesignGuiPy.cpp +>>>>>>> getActivePart() python function as complement to setActivePart():src/Mod/PartDesign/Gui/AppPartDesignGuiPy.cpp }; From 0ab6a7744244d59fe5e1fcd58375631108aa8977 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 12 Sep 2013 16:15:41 +0200 Subject: [PATCH 197/664] Update SketchObject Placement when the Support property changes --- src/Mod/Part/App/Part2DObject.cpp | 8 ++++++++ src/Mod/Part/App/Part2DObject.h | 3 +++ 2 files changed, 11 insertions(+) diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index 8bc7f56242bc..9f224d8e3136 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -367,6 +367,14 @@ void Part2DObject::acceptGeometry() // implemented in sub-classes } +void Part2DObject::onChanged(const App::Property* prop) +{ + // Update the Placement if the Support changes + if ((prop == &Support) && (Support.getValue() != NULL)) + positionBySupport(); + Part::Feature::onChanged(prop); +} + // Python Drawing feature --------------------------------------------------------- namespace App { diff --git a/src/Mod/Part/App/Part2DObject.h b/src/Mod/Part/App/Part2DObject.h index f946e94a83be..e1f131b5205f 100644 --- a/src/Mod/Part/App/Part2DObject.h +++ b/src/Mod/Part/App/Part2DObject.h @@ -107,6 +107,9 @@ class PartExport Part2DObject : public Part::Feature } //@} +protected: + /// get called by the container when a property has changed + virtual void onChanged(const App::Property* /*prop*/); }; typedef App::FeaturePythonT Part2DObjectPython; From 37a8c02bc64ee0f9cddbb46f2533338b6db22e6a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 12 Sep 2013 16:18:08 +0200 Subject: [PATCH 198/664] Improved SketchObject error reporting --- src/Mod/Sketcher/App/PropertyConstraintList.h | 3 +++ src/Mod/Sketcher/App/SketchObject.cpp | 2 ++ src/Mod/Sketcher/App/SketchObjectPyImp.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/Mod/Sketcher/App/PropertyConstraintList.h b/src/Mod/Sketcher/App/PropertyConstraintList.h index 931a99d0ebce..97a4f9b62e75 100644 --- a/src/Mod/Sketcher/App/PropertyConstraintList.h +++ b/src/Mod/Sketcher/App/PropertyConstraintList.h @@ -101,6 +101,9 @@ class SketcherExport PropertyConstraintList : public App::PropertyLists bool scanGeometry(const std::vector &GeoList) const; bool isGeometryInvalid(){return invalidGeometry;} + /// Return status of geometry for better error reporting + bool hasInvalidGeometry() const { return invalidGeometry; } + const Constraint *getConstraint(const App::ObjectIdentifier &path) const; virtual void setPathValue(const App::ObjectIdentifier & path, const boost::any & value); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 1d2373e9967e..a96d83e2e6b2 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -268,6 +268,8 @@ int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) int SketchObject::setDatum(int ConstrId, double Datum) { // set the changed value for the constraint + if (this->Constraints.hasInvalidGeometry()) + return -6; const std::vector &vals = this->Constraints.getValues(); if (ConstrId < 0 || ConstrId >= int(vals.size())) return -1; diff --git a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp index 55009ac0f9a3..06cef9eae44d 100644 --- a/src/Mod/Sketcher/App/SketchObjectPyImp.cpp +++ b/src/Mod/Sketcher/App/SketchObjectPyImp.cpp @@ -540,6 +540,8 @@ PyObject* SketchObjectPy::setDatum(PyObject *args) str << "Negative datum values are not valid for the constraint with index " << Index; else if (err == -5) str << "Zero is not a valid datum for the constraint with index " << Index; + else if (err == -6) + str << "Cannot set the datum because of invalid geometry"; else str << "Unexpected problem at setting datum " << (const char*)Quantity.getUserString().toUtf8() << " for the constraint with index " << Index; PyErr_SetString(PyExc_ValueError, str.str().c_str()); From f6958f391c39bd7947034b92d85a723b958bee9b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 12 Sep 2013 16:18:51 +0200 Subject: [PATCH 199/664] Fix bug where external reference was ignored without an error message --- src/Mod/Sketcher/App/SketchObject.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index a96d83e2e6b2..74344feba983 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -3172,6 +3172,8 @@ void SketchObject::rebuildExternalGeometry(void) } } + } else { + throw Base::Exception("Selected external reference plane must be normal to sketch plane"); } } else { throw Base::Exception("Non-planar faces are not yet supported for external geometry of sketches"); From 45ce3b78227ba64df3d84ea67d34cd4548697f2a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 13 Sep 2013 19:35:36 +0200 Subject: [PATCH 200/664] Enable Python to read the value of a sketcher constraint --- src/Mod/Sketcher/App/ConstraintPy.xml | 8 +++++++- src/Mod/Sketcher/App/ConstraintPyImp.cpp | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Mod/Sketcher/App/ConstraintPy.xml b/src/Mod/Sketcher/App/ConstraintPy.xml index d46c5b471262..06750f994e4c 100644 --- a/src/Mod/Sketcher/App/ConstraintPy.xml +++ b/src/Mod/Sketcher/App/ConstraintPy.xml @@ -14,7 +14,7 @@ - With this objects you can handle sketches + With this object you can handle sketches @@ -28,6 +28,12 @@ + + + Value of the Constraint + + + Name of the constraint diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp index 84b168767843..a7d980956606 100644 --- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp +++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp @@ -503,6 +503,11 @@ void ConstraintPy::setName(Py::String arg) this->getConstraintPtr()->Name = arg; } +Py::Float ConstraintPy::getValue(void) const +{ + return Py::Float(this->getConstraintPtr()->getValue()); +} + PyObject *ConstraintPy::getCustomAttributes(const char* /*attr*/) const { return 0; From 0a743b27dabbb1a8131c11f39104c8bcf466bb20 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 16 Sep 2013 20:15:34 +0200 Subject: [PATCH 201/664] Python code of Hole Feature --- src/Mod/PartDesign/CMakeLists.txt | 32 + src/Mod/PartDesign/FeatureHole/FeatureHole.py | 483 +++++++++++++ src/Mod/PartDesign/FeatureHole/HoleGui.py | 92 +++ .../FeatureHole/PartDesign_Hole.svg | 646 +++++++++++++++++ src/Mod/PartDesign/FeatureHole/Standards.py | 450 ++++++++++++ src/Mod/PartDesign/FeatureHole/TaskHole.py | 659 ++++++++++++++++++ src/Mod/PartDesign/FeatureHole/TaskHole.ui | 598 ++++++++++++++++ .../FeatureHole/ViewProviderHole.py | 98 +++ src/Mod/PartDesign/FeatureHole/__init__.py | 30 + src/Mod/PartDesign/Gui/Workbench.cpp | 4 +- src/Mod/PartDesign/InitGui.py | 1 + src/Mod/PartDesign/InitGui.py.orig | 72 ++ 12 files changed, 3164 insertions(+), 1 deletion(-) create mode 100644 src/Mod/PartDesign/FeatureHole/FeatureHole.py create mode 100644 src/Mod/PartDesign/FeatureHole/HoleGui.py create mode 100644 src/Mod/PartDesign/FeatureHole/PartDesign_Hole.svg create mode 100644 src/Mod/PartDesign/FeatureHole/Standards.py create mode 100644 src/Mod/PartDesign/FeatureHole/TaskHole.py create mode 100644 src/Mod/PartDesign/FeatureHole/TaskHole.ui create mode 100644 src/Mod/PartDesign/FeatureHole/ViewProviderHole.py create mode 100644 src/Mod/PartDesign/FeatureHole/__init__.py create mode 100644 src/Mod/PartDesign/InitGui.py.orig diff --git a/src/Mod/PartDesign/CMakeLists.txt b/src/Mod/PartDesign/CMakeLists.txt index d9ac48c081b4..d9451ce03180 100644 --- a/src/Mod/PartDesign/CMakeLists.txt +++ b/src/Mod/PartDesign/CMakeLists.txt @@ -71,3 +71,35 @@ INSTALL( DESTINATION Mod/PartDesign/WizardShaft ) + +SET(FeatureHole_SRCS + FeatureHole/__init__.py + FeatureHole/HoleGui.py + FeatureHole/FeatureHole.py + FeatureHole/TaskHole.py + FeatureHole/ViewProviderHole.py + FeatureHole/Standards.py + FeatureHole/PartDesign_Hole.svg +) +SOURCE_GROUP("featurehole" FILES ${FeatureHole_SRCS}) + +SET(FeatureHole_UI + FeatureHole/TaskHole.ui +) + +SET(all_featurehole_files ${FeatureHole_SRCS} ${FeatureHole_UI}) + +ADD_CUSTOM_TARGET(FeatureHole ALL + SOURCES ${all_featurehole_files} +) + +SET(all_files ${all_featurehole_files}) + +fc_copy_sources(Mod/PartDesign "${CMAKE_BINARY_DIR}/Mod/PartDesign" ${all_files}) + +INSTALL( + FILES + ${FeatureHole_SRCS} + DESTINATION + Mod/PartDesign/FeatureHole +) diff --git a/src/Mod/PartDesign/FeatureHole/FeatureHole.py b/src/Mod/PartDesign/FeatureHole/FeatureHole.py new file mode 100644 index 000000000000..8e452e8e4db1 --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/FeatureHole.py @@ -0,0 +1,483 @@ +#/****************************************************************************** +# * Copyright (c)2012 Jan Rheinlaender * +# * * +# * 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 * +# * * +# ******************************************************************************/ + +import FreeCAD, FreeCADGui +import Part, Sketcher, PartDesignGui +import math + +def makeVector(point): + if point.__class__ == FreeCAD.Vector: + return point + return FreeCAD.Vector(point.X, point.Y, point.Z) + +class Hole(): + "Hole feature" + App = FreeCAD + Gui = FreeCADGui + + def __init__(self, feature): + self.feature = feature + self.feature.addProperty("App::PropertyString","HoleType","Hole","Type of hole").HoleType="Depth" + self.feature.addProperty("App::PropertyBool","Threaded","Hole","Threaded hole").Threaded=False + self.feature.addProperty("App::PropertyBool","Counterbore","Hole","Counterbore hole").Counterbore=False + self.feature.addProperty("App::PropertyBool","Countersink","Hole","Countersink hole").Countersink=False + self.feature.addProperty("App::PropertyString","Norm","Hole","Name of norm").Norm="Custom" + self.feature.addProperty("App::PropertyString","NormTolerance","Hole","Tolerance field of norm").NormTolerance="medium" + self.feature.addProperty("App::PropertyLength","NormDiameter","Hole","Nominal diameter of hole").NormDiameter=4.0 + self.feature.addProperty("App::PropertyString", "ExtraNorm", "Hole", "Norm of bolt or washer used in hole").ExtraNorm="ISO 4762" + self.feature.addProperty("App::PropertyString", "NormThread", "Hole", "Norm of thread").NormThread="DIN 13-1" + self.feature.addProperty("App::PropertyString", "NormThreadFinish", "Hole", "Norm defining thread finish length").NormThreadFinish="DIN 76-2" + self.feature.addProperty("App::PropertyLength","Diameter","Hole","Diameter of hole").Diameter=5.0 + self.feature.addProperty("App::PropertyLength","Depth","Hole","Depth of hole").Depth=8.0 + self.feature.addProperty("App::PropertyLength","CounterboreDiameter","Hole","Diameter of counterbore").CounterboreDiameter=10.0 + self.feature.addProperty("App::PropertyLength","CounterboreDepth","Hole","Depth of counterbore").CounterboreDepth=4.0 + self.feature.addProperty("App::PropertyLength","CountersinkAngle","Hole","Angle of countersink").CountersinkAngle=45.0; + self.feature.addProperty("App::PropertyLength","ThreadLength","Hole","Length of thread").ThreadLength=5.0; + self.feature.addProperty("App::PropertyString","PositionType","Hole","Type of position references").PositionType="Linear" + self.feature.addProperty("App::PropertyLinkSub","Support","Hole","Support of hole feature").Support=None + self.feature.addProperty("App::PropertyLink","HoleGroove","Hole","Revolution feature creating the hole").HoleGroove=None + # Create new HoleGroove feature + body = PartDesignGui.getActivePart() + self.sketchaxis = self.feature.Document.addObject("PartDesign::Line", "HoleSketchAxis") + body.addFeature(self.sketchaxis) + self.Gui.ActiveDocument.hide(self.sketchaxis.Name) + self.sketchplane = self.feature.Document.addObject("PartDesign::Plane", "HoleSketchPlane") + self.sketchplane.References = (self.sketchaxis, "") + body.addFeature(self.sketchplane) + self.Gui.ActiveDocument.hide(self.sketchplane.Name) + self.sketch = self.feature.Document.addObject("Sketcher::SketchObject","HoleSketch") + self.sketch.Support = (self.sketchplane, ["front"]) + body.addFeature(self.sketch) + self.Gui.ActiveDocument.hide(self.sketch.Name) + feature.HoleGroove = feature.Document.addObject("PartDesign::Groove","HoleGroove") + feature.HoleGroove.Angle = 360.0 + feature.HoleGroove.Sketch = self.sketch + body.addFeature(feature.HoleGroove) + self.Gui.ActiveDocument.hide(feature.HoleGroove.Name) + self.feature.Proxy = self + self.oldCounterbore = False + self.oldCountersink = False + + def execute(self, feature): + if feature.Support != None: + (support, element) = feature.Support + feature.Placement = feature.HoleGroove.Placement + shape = feature.HoleGroove.Shape.copy() + shape.Placement = FreeCAD.Placement() + feature.Shape = shape + + self.Gui.ActiveDocument.hide(support.Name) + # Copy display properties from support + featview = feature.ViewObject + suppview = support.ViewObject + for p in suppview.PropertiesList: + if not p in ["DisplayMode","BoundingBox","Proxy","RootNode","Visibility"]: + if p in featview.PropertiesList: + val = getattr(suppview,p) + setattr(featview,p,val) + if suppview.DisplayMode in featview.listDisplayModes(): + featview.DisplayMode = suppview.DisplayMode + if hasattr(suppview,"DiffuseColor") and hasattr(featview,"DiffuseColor"): + featview.DiffuseColor = suppview.DiffuseColor + + def onChanged(self, fp, prop): + #self.App.Console.PrintMessage("Change property: " + str(prop) + "\n") + if fp == None or fp.Support == None: + return + + if (prop == "HoleType" or prop == "Threaded" or prop == "Counterbore" or prop == "Countersink" + or prop == "Diameter" or prop == "Depth" + or prop == "CounterboreDiameter" or prop == "CounterboreDepth" + or prop == "CountersinkAngle"): + self.executeSketchChanged(fp) + fp.Document.recompute() + elif prop == "Support": + self.executePositionChanged(fp) + fp.Document.recompute() + + def executePositionChanged(self, fp): + "Change the position of the hole" + if fp.Support == None: + return + plane = self.feature.HoleGroove.Sketch.Support[0] + # Get support (face) + (support, elementList) = fp.Support + face = eval("support.Shape." + elementList[0]) + refs = plane.References + if len(refs) == 0: + return + + axis = plane.References[0][0] + firstTime = (len(axis.References) == 0) + if firstTime: + # Try to guess some references (using arcs or lines of the outer wire of the support face) + wire = face.OuterWire + firstLine = None + for e in wire.Edges: + if type(e.Curve) == Part.Line: + if firstLine == None: + firstLine = e + firstDirection = e.Curve.EndPoint - e.Curve.StartPoint + else: + if firstDirection == e.Curve.EndPoint - e.Curve.StartPoint or firstDirection == e.Curve.StartPoint - e.Curve.EndPoint: + continue # Parallel edges + allEdges = support.Shape.Edges + firstLineIndex = -1 + secondLineIndex = -1 + for i in range(len(allEdges)): + try: + if type(allEdges[i].Curve) != Part.Line: + continue + if (allEdges[i].Curve.StartPoint == firstLine.Curve.StartPoint and allEdges[i].Curve.EndPoint == firstLine.Curve.EndPoint) or (allEdges[i].Curve.EndPoint == firstLine.Curve.StartPoint and allEdges[i].Curve.StartPoint == firstLine.Curve.EndPoint): + firstLineIndex = i + elif (allEdges[i].Curve.StartPoint == e.Curve.StartPoint and allEdges[i].Curve.EndPoint == e.Curve.EndPoint) or (allEdges[i].Curve.EndPoint == e.Curve.StartPoint and allEdges[i].Curve.StartPoint == e.Curve.EndPoint): + secondLineIndex = i + if (firstLineIndex > -1) and (secondLineIndex > -1): + break + except: + # Unknown curvetype GeomAbs_OtherCurve + continue + axis.References = [(support, elementList[0]), (support, "Edge" + str(firstLineIndex+1)), (support, "Edge" + str(secondLineIndex+1))] + axis.Offset = 1.0 + axis.Offset2 = 1.0 + self.feature.PositionType = "Linear" + # Place the axis approximately in the center of the face + #p = face.CenterOfMass + #l1 = Part.Line(firstLine.Curve) + #l2 = Part.Line(e.Curve) + #axis.Offset = p.distanceToLine(l1.StartPoint, l1.EndPoint - l1.StartPoint) + #axis.Offset2 = p.distanceToLine(l1.StartPoint, l2.EndPoint - l2.StartPoint) + # TODO: Ensure that the hole is inside the face! + break + elif type(e.Curve) == Part.Circle: + allEdges = support.Shape.Edges + for i in range(len(allEdges)): + try: + if type(allEdges[i].Curve) != Part.Circle: + continue + c = allEdges[i].Curve + if c.Center == e.Curve.Center and c.Axis == e.Curve.Axis and c.Radius == e.Curve.Radius: + axis.References = [(support, "Edge" + str(i+1))] + self.feature.PositionType = "Coaxial" + break + except: + # Unknown curvetype + continue + elif type(e.Curve) == Part.ArcOfCircle: + allEdges = support.Shape.Edges + for i in range(len(allEdges)): + try: + if type(allEdges[i].Curve) != Part.ArcOfCircle: + continue + a = allEdges[i].Curve + if a.Center == e.Curve.Center and a.Axis == e.Curve.Axis and a.Radius == e.Curve.Radius and a.FirstParameter == e.Curve.FirstParameter and a.LastParameter == e.Curve.LastParameter: + axis.References = [(support, "Edge" + str(i+1))] + self.feature.PositionType = "Coaxial" + break + except: + continue + break + + # Grab a point from the wire of the support face + axisbase = axis.Shape.Curve.StartPoint + axisdir = axis.Shape.Curve.EndPoint - axisbase + found = False + if not firstTime and len(refs) > 1: + # Try to keep the old point, to avoid the sketch plane jumping around + (obj, sub) = refs[1] + point = eval("support.Shape." + sub) + if point.Point.distanceToLine(axisbase, axisdir) > 1E-10: # TODO: Precision::Confusion() + found = True + if not found: + for p in face.OuterWire.Vertexes: + if p.Point.distanceToLine(axisbase, axisdir) > 1E-10: # TODO: Precision::Confusion() + point = p + found = True + break + if not found: + point = face.OuterWire.Vertexes[0] # Better this than nothing... and it can't actually happen, can it? + + # Find the index of the point in the support shape + allVertexes = support.Shape.Vertexes + for v in range(len(allVertexes)): + if allVertexes[v].Point == point.Point: + # Use this point and the axis to define the sketch plane + if len(refs) < 2: + refs.append((support, "Vertex" + str(v+1))) + else: + refs[1] = (support, "Vertex" + str(v+1)) + break + plane.References = refs + if firstTime: + fp.Document.recompute() # Update the Sketch Placement property + self.executeSketchChanged(fp) # Build the sketch of the hole + fp.Document.recompute() + else: + self.executeSketchChanged(fp) # Update the sketch of the hole + self.setHoleDirection(fp) + + def setHoleDirection(self, feature): + # Make sure the hole goes into the material, not out of it + sketch = feature.HoleGroove.Sketch + axis = sketch.Support[0].References[0][0] + axisbase = axis.Shape.Curve.StartPoint + axisdir = axis.Shape.Curve.EndPoint - axisbase + p1 = None + p2 = None + for v in sketch.Shape.Vertexes: + # Find the two sketch vertices that are on the sketch axis + if v.Point.distanceToLine(axisbase, axisdir) < 1E-10: # TODO: use Precision::Confusion() + if p1 is None: + p1 = v.Point + else: + p2 = v.Point + break + if p1 is not None and p2 is not None: + (support, elementList) = feature.Support + face = eval("support.Shape." + elementList[0]) + plane = face.Surface + if type(plane) != Part.Plane: + return + # Find the vertex that is on the top of the hole + if p1.distanceToPlane(plane.Position, plane.Axis) < 1E-10: + top = p1 + dir = p2 - p1 + else: + top = p2 + dir = p1 - p2 + if not support.Shape.isInside(top + dir.multiply(1E-8), 1E-10, False): + # Toggle the angle + angle = sketch.Constraints[12].Value + if angle == math.pi: + sketch.setDatum(12, 0.0) + else: + sketch.setDatum(12, math.pi) + + def executeSketchChanged(self, fp): + "Change the sketch shape of the hole" + if self.feature.HoleGroove == None: + return + if fp.HoleType == "Thru": + # TODO: Make this more stable + length = 1E+4 + else: + length = fp.Depth + radius = fp.Diameter / 2.0 + + if fp.Counterbore: + self.createOrUpdateCounterboreSketch(fp, length, radius) + elif fp.Countersink: + self.createOrUpdateCountersinkSketch(fp, length, radius) + else: + self.createOrUpdateStandardSketch(fp, length, radius) + + def createOrUpdateStandardSketch(self, fp, depth, radius): + (support, elements) = fp.Support + if fp.HoleGroove.Sketch.GeometryCount == 0: + #FreeCAD.Console.PrintMessage("Standard sketch\n") + # New sketch + sketch = fp.HoleGroove.Sketch + axis = sketch.Support[0].References[0][0] + # Geo -1,1 is the origin (Point) + # Geo -1 is the X-axis + # Geo -2 is the Y-axis + # First external geometry is -3 + sketch.addExternal(axis.Name,"Line") # Geo -3: Datum axis + sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face + # Note: Creating the sketch first with depth = 100.0 and then changing the constraint later seems to be more stable + tempDepth = 100.0 + # Build the sketch + sketch.addGeometry(Part.Line(self.App.Vector(10.0,50.0,0),self.App.Vector(10.0,-50.0,0))) # Geo0: Rotation axis + sketch.toggleConstruction(0) + sketch.addGeometry(Part.Line(self.App.Vector(10.0,-10.0,0),self.App.Vector(10.0,-30.0,0))) # Geo1: Vertical axis of hole + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,0))# Datum0 + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,2,0))# Datum1 + sketch.addGeometry(Part.Line(self.App.Vector(10.0,-10.0,0),self.App.Vector(20.0,-10.0,0))) # Geo2: Top of hole + sketch.addConstraint(Sketcher.Constraint('Coincident',1,1,2,1)) # Datum2 + sketch.addConstraint(Sketcher.Constraint('Perpendicular',2, 1)) # Datum3 + sketch.addGeometry(Part.Line(self.App.Vector(20.0,-10.0,0),self.App.Vector(20.0,-25.0,0))) # Geo3: Vertical mantle of hole + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # temporary + sketch.addConstraint(Sketcher.Constraint('Parallel',3, 1)) # Datum4 + sketch.addConstraint(Sketcher.Constraint('Distance',3,2,1, 10.0)) # Datum5: Radius + sketch.addConstraint(Sketcher.Constraint('Distance',3,2,2, 15.0)) # Datum6: Depth + sketch.addGeometry(Part.Line(self.App.Vector(10.0,-30.0,0),self.App.Vector(20.0,-25.0,0))) # Geo4: 118 degree tip angle + sketch.addConstraint(Sketcher.Constraint('Coincident',4,1,1,2)) # Datum7 + sketch.addConstraint(Sketcher.Constraint('Coincident',4,2,3,2)) # Datum8 + # TODO: The tip angle of 118 degrees is for steel only. It should be taken from Part material data + # (as soon as that is implemented) + sketch.addConstraint(Sketcher.Constraint('Angle',4,1,1,2, 118.0/2.0 * math.pi / 180.0)) # Datum9 + # Locate at the intersection of the two external geometries + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-3))# Datum10 + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11 + sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, 0.0))# Datum12 + # This datum is specific for this holetype, so move it to the last position + sketch.delConstraint(4) + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13 + fp.HoleGroove.ReferenceAxis = (sketch,['Axis0']) + if self.oldCounterbore == True: + # Remove counterbore from existing sketch + #FreeCAD.Console.PrintMessage("Counter to Standard sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.delConstraint(19) + sketch.delConstraint(18) + sketch.delConstraint(17) + sketch.delConstraint(16) + sketch.delConstraint(15) + sketch.delConstraint(14) + sketch.delConstraint(13) + sketch.delGeometry(6) + sketch.delGeometry(5) + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13 + elif self.oldCountersink == True: + # Remove countersink from existing sketch + #FreeCAD.Console.PrintMessage("Sink to Standard sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.delConstraint(16) + sketch.delConstraint(15) + sketch.delConstraint(14) + sketch.delConstraint(13) + sketch.delGeometry(5) + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13 + else: + # Update existing standard sketch + #FreeCAD.Console.PrintMessage("Update Standard sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.setDatum(5, radius) + sketch.setDatum(6, depth) + if sketch.ExternalGeometry[1] != (support, elements[0]): + # Update the external geometry references + angle = sketch.Constraints[12].Value + sketch.delConstraint(13) + sketch.delConstraint(12) + sketch.delConstraint(11) + sketch.delExternal(1) + sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11 + sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12 + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1)) # Datum13 + + self.setHoleDirection(fp) + self.oldCounterbore = False + self.oldCountersink = False + + def createOrUpdateCounterboreSketch(self, fp, depth, radius): + cradius = fp.CounterboreDiameter / 2.0 + cdepth = fp.CounterboreDepth + (support, elements) = fp.Support + + if self.oldCounterbore == True: + # Update properties of existing counterbore sketch + #FreeCAD.Console.PrintMessage("Update to Counterbore sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.setDatum(5, radius) + sketch.setDatum(6, depth) + sketch.setDatum(13, cradius) + sketch.setDatum(15, cdepth) + if sketch.ExternalGeometry[1] != (support, elements[0]): + # Update the external geometry references + angle = sketch.Constraints[12].Value + sketch.delConstraint(19) + sketch.delConstraint(18) + sketch.delConstraint(17) + sketch.delConstraint(16) + sketch.delConstraint(15) + sketch.delConstraint(14) + sketch.delConstraint(13) + sketch.delConstraint(12) + sketch.delConstraint(11) + sketch.delExternal(1) + sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11 + sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12 + sketch.addConstraint(Sketcher.Constraint('Distance',2, cradius)) # Datum13 + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14 + sketch.addConstraint(Sketcher.Constraint('Distance',3, 1, 2, cdepth)) # Datum15 + sketch.addConstraint(Sketcher.Constraint('Parallel',5, 1)) # Datum16 + sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) # Datum17 + sketch.addConstraint(Sketcher.Constraint('Perpendicular',6, -3)) # Datum18 + sketch.addConstraint(Sketcher.Constraint('Coincident',6,2,3,1)) # Datum19 + else: + # Change standard to counterbore in existing sketch + #FreeCAD.Console.PrintMessage("Standard to Counterbore sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.delConstraint(13) + sketch.addConstraint(Sketcher.Constraint('Distance',2, cradius)) # Datum13 + p2 = sketch.Geometry[2].EndPoint + sketch.addGeometry(Part.Line(p2,self.App.Vector(p2.x,p2.y-20.0,0))) # Geo5: Vertical mantle of counterbore + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14 + sketch.addConstraint(Sketcher.Constraint('Distance',3, 1, 2, cdepth)) # Datum15 + sketch.addConstraint(Sketcher.Constraint('Parallel',5, 1)) # Datum16 + p3 = sketch.Geometry[3].StartPoint + sketch.addGeometry(Part.Line(self.App.Vector(p2.x,p2.y-20.0, 0),p3)) # Geo6: bottom of counterbore + sketch.addConstraint(Sketcher.Constraint('Coincident',5,2,6,1)) # Datum17 + sketch.addConstraint(Sketcher.Constraint('Perpendicular',6, -3)) # Datum18 + sketch.addConstraint(Sketcher.Constraint('Coincident',6,2,3,1)) # Datum19 + + self.setHoleDirection(fp) + self.oldCounterbore = True + self.oldCountersink = False + + def createOrUpdateCountersinkSketch(self, fp, depth, radius): + sradius = fp.CounterboreDiameter / 2.0 + sangle = fp.CountersinkAngle * math.pi / 180.0 + (support, elements) = fp.Support + + if self.oldCountersink == True: + # Update properties of existing countersink sketch + #FreeCAD.Console.PrintMessage("Update to Countersink sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.setDatum(5, radius) + sketch.setDatum(6, depth) + sketch.setDatum(13, sradius) + sketch.setDatum(15, sangle) + if sketch.ExternalGeometry[1] != (support, elements[0]): + # Update the external geometry references + angle = sketch.Constraints[12].Value + sketch.delConstraint(16) + sketch.delConstraint(15) + sketch.delConstraint(14) + sketch.delConstraint(13) + sketch.delConstraint(12) + sketch.delConstraint(11) + sketch.delExternal(1) + sketch.addExternal(support.Name, elements[0]) # Geo -4: Support face + sketch.addConstraint(Sketcher.Constraint('PointOnObject',1,1,-4))# Datum11 + sketch.addConstraint(Sketcher.Constraint('Angle',0,1,-3, 1, angle))# Datum12 + sketch.addConstraint(Sketcher.Constraint('Distance',2, sradius)) # Datum13 + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14 + sketch.addConstraint(Sketcher.Constraint('Angle',5,2, 1,2, sangle)) # Datum15 + sketch.addConstraint(Sketcher.Constraint('Coincident',3,1,5,2)) # Datum16 + else: + # Change standard to countersink in existing sketch + #FreeCAD.Console.PrintMessage("Standard to Countersink sketch\n") + sketch = fp.HoleGroove.Sketch + sketch.delConstraint(13) + sketch.addConstraint(Sketcher.Constraint('Distance',2, sradius)) # Datum13 + p2 = sketch.Geometry[2].EndPoint + sketch.addGeometry(Part.Line(p2,self.App.Vector(p2.x,p2.y-20.0,0))) # Geo5: Chamfer of countersink + sketch.addConstraint(Sketcher.Constraint('Coincident',2,2,5,1)) # Datum14 + sketch.addConstraint(Sketcher.Constraint('Angle',5,2, 1,2, sangle)) # Datum15 + sketch.addConstraint(Sketcher.Constraint('Coincident',3,1,5,2)) # Datum16 + + self.setHoleDirection(fp) + self.oldCounterbore = False + self.oldCountersink = True diff --git a/src/Mod/PartDesign/FeatureHole/HoleGui.py b/src/Mod/PartDesign/FeatureHole/HoleGui.py new file mode 100644 index 000000000000..c2c156ac84ca --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/HoleGui.py @@ -0,0 +1,92 @@ +#/****************************************************************************** +# * Copyright (c)2012 Jan Rheinlaender * +# * * +# * 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 * +# * * +# ******************************************************************************/ + +import FreeCAD, FreeCADGui +import PartDesignGui +from PyQt4 import QtCore, QtGui +from TaskHole import TaskHole +from FeatureHole import Hole +from ViewProviderHole import ViewProviderHole + +class HoleGui: + def getMainWindow(self): + "returns the main window" + # using QtGui.qApp.activeWindow() isn't very reliable because if another + # widget than the mainwindow is active (e.g. a dialog) the wrong widget is + # returned + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + "Create a new hole feature" + def Activated(self): + # Get main window + mw = self.getMainWindow() + + # Get active document + doc = FreeCAD.activeDocument() + if doc == None: + QtGui.QMessageBox.critical(mw, "No document", "A document must be open in order to create a hole feature") + return + + # Check for valid position selection + selection = FreeCADGui.Selection.getSelectionEx() + if len(selection) != 1: + QtGui.QMessageBox.critical(mw, "No position defined", "Please select a face to create the hole feature on") + return + if selection[0].DocumentName != doc.Name: + QtGui.QMessageBox.critical(mw, "Wrong document", "Please select a face in the active document") + # Note: For some reason setting the Support property here breaks all sorts of things. + # It is done in TaskHole.updateUI() instead + + # Show feature preview + body = PartDesignGui.getActivePart() + if body == None: + QtGui.QMessageBox.critical(mw, "No active body", "Please create a body or make a body active") + + feature = doc.addObject("Part::FeaturePython","Hole") + hole = Hole(feature) + body.addFeature(feature) + + ViewProviderHole(feature.ViewObject) + feature.touch() + FreeCAD.ActiveDocument.recompute() + # Fit view (remove after the testing phase) + FreeCADGui.SendMsgToActiveView("ViewFit") + + panel = TaskHole(feature) + + FreeCADGui.Control.showDialog(panel) + if panel.setupUi(): + FreeCADGui.Control.closeDialog(panel) + return None + return panel + + def GetResources(self): + IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/FeatureHole/PartDesign_Hole.svg" + MenuText = 'Create a hole feature' + ToolTip = 'Create a hole feature' + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +FreeCADGui.addCommand('PartDesign_Hole', HoleGui()) diff --git a/src/Mod/PartDesign/FeatureHole/PartDesign_Hole.svg b/src/Mod/PartDesign/FeatureHole/PartDesign_Hole.svg new file mode 100644 index 000000000000..8d25b0919c85 --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/PartDesign_Hole.svg @@ -0,0 +1,646 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/FeatureHole/Standards.py b/src/Mod/PartDesign/FeatureHole/Standards.py new file mode 100644 index 000000000000..e056c58e7907 --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/Standards.py @@ -0,0 +1,450 @@ +# -*- coding: iso-8859-15 -*- +#/****************************************************************************** +# * Copyright (c)2012 Jan Rheinlaender * +# * * +# * 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 * +# * * +# ******************************************************************************/ + +import FreeCAD + +"Standards for bore hole feature" +sources = { + "inet_arcor" : "http://home.arcor.de/maschinenelemente2-din/DIN%20EN%2020273_Durchgangsl%F6cher%20fuer%20Schrauben.PDF", + "inet_duckma" : "http://www.duckma.de/mb14/SiteDocs/DIN%20Grundlagen%20Maschinenbau.pdf", + "klein_14" : "Klein: Einführung in die DIN-Normen, 14. Auflage. Stuttgart, Teubner 2008" +} + +StandardYear = 0 +StandardTitle = 1 +StandardSource = 2 +StandardType = 3 + +standards = { +# "Standard name" : ("Year", "Title", "Source", "Type") + "DIN 13-1" : ("1999", "Metrisches ISO-Gewinde allgemeiner Anwendung (Auszug); Nennmaße für Regelgewinde", "klein_14", "thread"), + "DIN 74-A" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form A", "klein_14", "countersink"), + "DIN 74-E" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form E", "klein_14", "countersink"), + "DIN 74-F" : ("2003", "Senkungen fur Senkschrauben, ausgenommen Senkschrauben mit Kopfen nach DIN EN 27721; Form F", "klein_14", "countersink"), + "DIN 76-2" : ("1984", "Gewindeausläufe und Gewindefreistiche (Auszug); für Metrisches ISO-Gewinde nach DIN 13; Innengewinde (Gewindegrundlöcher)", "klein_14", "threaded"), + "DIN 974-1" : ("1991", "Senkdurchmesser für Schrauben mit Zylinderkopf; Konstruktionsmaße (Auszug)", "klein_14", "counterbore"), + "DIN 974-2" : ("1991", "Senkdurchmesser fur Sechskantschrauben und Sechskantmuttern; Konstruktionsmaße(Auszug)", "klein_14", "counterbore"), + "ISO 273" : ("1979", "Fasteners; Clearance holes for bolts and screws", "inet_arcor", "through"), + "ISO 15065" : ("2005", "Senkungen fur Senkschrauben mit Kopfform nach ISO 7721", "klein_14", "countersink") +} + +aliases = { + "ISO 273" : ("ISO 273:1979", "EN 20273:1991", "DIN EN 20273:1992", "DIN ISO 273", "DIN ISO 273/09.79"), + "ISO 15065" : ("ISO 15065:2005", "EN ISO 15065", "EN ISO 15065:2005", "DIN EN ISO 15065") +} + +standards_tolerance = ("fine", "medium", "coarse") + +standards_through = { +# "Standard name" : (Thread_dia : Hole_dia(Fine, Medium, Coarse)) + "ISO 273" : { + 1.0 : (1.1, 1.2, 1.3), + 1.2 : (1.3, 1.4, 1.5), + 1.4 : (1.5, 1.6, 1.8), + 1.6 : (1.7, 1.8, 2.0), + 1.8 : (2.0, 2.1, 2.2), + 2.0 : (2.2, 2.4, 2.6), + 2.5 : (2.7, 2.9, 3.1), + 3.0 : (3.2, 3.4, 3.6), + 3.5 : (3.7, 3.9, 4.2), + 4.0 : (4.3, 4.5, 4.8), + 4.5 : (4.8, 5.0, 5.3), + 5.0 : (5.3, 5.5, 5.8), + 6.0 : (6.4, 6.6, 7.0), + 7.0 : (7.4, 7.6, 8.0), + 8.0 : (8.4, 9.0, 10), + 10.0: (10.5, 11, 12), + 12.0: (13, 13.5, 14.5), + 14.0: (15, 15.5, 16.5), + 16.0: (17, 17.5, 18.5), + 18.0: (19, 20, 21), + 20.0: (21, 22, 24), + 22.0: (23, 24, 26), + 24.0: (25, 26, 28), + 27.0: (28, 30, 32), + 30.0: (31, 33, 35), + 33.0: (34, 36, 38), + 36.0: (37, 39, 42), + 39.0: (40, 42, 45), + 42.0: (43, 45, 48), + 45.0: (46, 48, 52), + 48.0: (50, 52, 56), + 52.0: (54, 56, 62), + 56.0: (58, 62, 66), + 60.0: (62, 66, 70), + 64.0: (66, 70, 74), + 68.0: (70, 74, 80), + 72.0: (74, 78, 82), + 76.0: (78, 82, 86), + 80.0: (82, 86, 91), + 85.0: (87, 91, 96), + 90.0: (93, 96, 101), + 95.0: (98, 101, 107), + 100.0: (104, 107, 112), + 105.0: (109, 112, 117), + 110.0: (114, 117, 121), + 115.0: (119, 122, 127), + 120.0: (124, 127, 132), + 125.0: (129, 132, 137), + 130.0: (134, 137, 144), + 140.0: (144, 147, 155), + 150.0: (155, 158, 165) + } +} + +standards_counterbore = { +# "Standard name" : {Thread_dia : counterboredia(row1, row2, row3, row4, row5, row6)} + "DIN 974-1" : { + 1.0 : (2.2, None, None, None, None, None), + 1.2 : (2.5, None, None, None, None, None), + 1.4 : (3.0, None, None, None, None, None), + 1.6 : (3.5, 3.5, None, None, None, None), + 1.8 : (3.8, None, None, None, None, None), + 2.0 : (4.4, 5.0, None, 5.5, 6, 6), + 2.5 : (5.5, 6, None, 6, 7, 7), + 3.0 : (6.5, 7, 6.5, 7, 9, 8), + 3.5 : (6.5, 8, 6.5, 8, 9, 9), + 4.0 : (8, 9, 8, 9, 10, 10), + 5.0 : (10, 11, 10, 11, 13, 13), + 6.0 : (11, 13, 11, 13, 15, 15), + 8.0 : (15, 18, 15, 16, 18, 20), + 10.0 : (18, 24, 18, 20, 24, 24), + 12.0 : (20, None, 20, 24, 26, 33), + 14.0 : (24, None, 24, 26, 30, 40), + 16.0 : (26, None, 26, 30, 33, 43), + 18.0 : (30, None, 30, 33, 36, 46), + 20.0 : (33, None, 33, 36, 40, 48), + 22.0 : (36, None, 36, 40, 43, 54), + 24.0 : (40, None, 40, 43, 48, 58), + 27.0 : (46, None, 46, 46, 54, 63), + 30.0 : (50, None, 50, 54, 61, 73), + 33.0 : (54, None, 54, None, 63, None), + 36.0 : (58, None, 58, 63, 69, None), + 42.0 : (69, None, 69, 73, 82, None), + 48.0 : (78, None, 78, 82, 98, None), + 56.0 : (93, None, 93, 93, 112, None), + 64.0 : (107, None, 107, 107, 125, None), + 72.0 : (118, None, 118, 118, 132, None), + 80.0 : (132, None, 132, 132, 150, None), + 90.0 : (145, None, 145, 145, 170, None), + 100.0:(160, None, 160, 160, 182, None) + }, + "DIN 974-2" : { + 3.0 : (11, 11, 9), + 4.0 : (13, 15, 10), + 5.0 : (15, 18, 11), + 6.0 : (18, 20, 13), + 8.0 : (24, 26, 18), + 10.0:(28, 33, 22), + 12.0:(33, 36, 26), + 14.0:(36, 43, 30), + 16.0:(40, 46, 33), + 18.0:(43, 50, 36), + 20.0:(46, 54, 40), + 22.0:(54, 61, 46), + 24.0:(58, 73, 48), + 27.0:(61, 76, 54), + 30.0:(73, 82, 61), + 33.0:(76, 89, 69), + 36.0:(82, 93, 73), + 39.0:(89, 98, 76), + 42.0:(98, 107, 82), + 45.0:(107, 112, 89) + } +} + +standards_counterbore_through = { +# Standard name : Through hole standard name + "DIN 74-A" : "ISO 273", + "DIN 74-E" : "ISO 273", # Note that the standards seems to allow tolerance class "fine" only + "DIN 74-F" : "ISO 273", + "DIN 974-1" : "ISO 273", + "DIN 974-2" : "ISO 273", + "ISO 15065" : "ISO 273" +} + +standards_counterbore_rows = { +# Row index : ( extra standards e.g. bolt used or washer used ) +# Note that DIN 7980 has been cancelled, therefore row three should not be used any more + "DIN 974-1" : { + 1 : ("ISO 1207", "ISO 4762", "DIN 6912", "DIN 7984"), + 2 : ("ISO 1580", "ISO 7045"), + 3 : ("DIN 7980", ""), # single value gives wrong iteration when collecting the standards + 4 : ("ISO 10673 type C", "DIN 6798", "DIN 6907"), + 5 : ("ISO 7089", "ISO 7090", "ISO 10673 type A"), + 6 : ("DIN 6796", "DIN 6908") + }, + "DIN 974-2" : { + 1 : ("DIN 659", "DIN 896", "DIN 3112", "DIN 3124"), + 2 : ("DIN 838", "DIN 897", "DIN 3129"), + 3 : ("tight", "") + } +} + +standards_counterbore_extradepth = { +# max Thread diameter : extra depth + 1.4 : 0.2, + 6.0 : 0.4, + 20.0 : 0.6, + 27.0 : 0.8, + 100.0 : 1.0 +} + +standards_countersink_dia = 0 +standards_countersink_angle = 1 + +standards_countersink = { +# "Standard name" : {Thread_dia : (countersinkdia, head angle)} + "DIN 74-A" : { + 1.6 : (3.7, 90.0), + 2.0 : (4.6, 90.0), + 2.5 : (5.7, 90.0), + 3.0 : (6.5, 90.0), + 3.5 : (7.6, 90.0), + 4.0 : (8.6, 90.0), + 4.5 : (9.5, 90.0), + 5.0 : (10.4, 90.0), + 5.5 : (11.4, 90.0), + 6.0 : (12.4, 90.0), + 7.0 : (14.4, 90.0), + 8.0 : (16.4, 90.0) + }, + "DIN 74-E" : { + 10.0 : (19.0, 75.0), + 12.0 : (24.0, 75.0), + 16.0 : (31.0, 75.0), + 20.0 : (34.0, 60.0), + 22.0 : (37.0, 60.0), + 24.0 : (40.0, 60.0) + }, + "DIN 74-F" : { + 3.0 : (6.94, 90.0), + 4.0 : (9.18, 90.0), + 5.0 : (11.47, 90.0), + 6.0 : (13.71, 90.0), + 8.0 : (18.25, 90.0), + 10.0 : (22.73, 90.0), + 12.0 : (27.21, 90.0), + 14.0 : (31.19, 90.0), + 16.0 : (33.39, 90.0), + 20.0 : (40.71, 90.0) + }, + "ISO 15065" : { + 2.0 : (4.4, 90.0), + 3.0 : (6.3, 90.0), + 4.0 : (9.4, 90.0), + 5.0 : (0.4, 90.0), + 6.0 : (12.6, 90.0), + 8.0 : (17.3, 90.0), + 10.0 : (20.0, 90.0) + } +} + +standards_threaded_types = ("normal", "short", "long") + +standards_threaded = { +# Standard name : { Tread pitch : threadFinish(normal, short, long) } + "DIN 76-2" : { + 0.20 : (1.3, 0.8, 2.0), + 0.25 : (1.5, 1.0, 2.4), + 0.30 : (1.8, 1.2, 2.9), + 0.35 : (2.1, 1.3, 3.3), + 0.40 : (2.3, 1.5, 3.7), + 0.45 : (2.6, 1.6, 4.1), + 0.50 : (2.8, 1.8, 4.5), + 0.60 : (3.4, 2.1, 5.4), + 0.70 : (3.8, 2.4, 6.1), + 0.75 : (4.0 , 2.5, 6.4), + 0.80 : (4.2, 2.7, 6.8), + 1.00 : (5.1, 3.2, 8.2), + 1.25 : (6.2, 3.9, 10), + 1.5 : (7.3, 4.6, 11.6), + 1.75 : (8.3, 5.2, 13.3), + 2.0 : (9.3, 5.8, 14.8), + 2.5 : (11.2, 7.0, 17.9), + 3.0 : (13.1, 8.2, 21.0), + 3.5 : (15.2, 9.5, 24.3), + 4.0 : (16.8, 10.5, 26.9), + 4.5 : (18.4, 11.5, 29.4), + 5.0 : (20.8, 13.0, 33.3), + 5.5 : (22.4, 14.0, 35.8), + 6.0 : (24.0, 15, 38.4) + } +} + +standards_threaded_thread = { +# Standard name for thread attribute : standard name for thread } + "DIN 76-2" : "DIN 13-1" +} + +standards_thread_pitch = 0 +standards_thread_flankdia = 1 +standards_thread_outercoredia = 2 +standards_thread_innercoredia = 3 +standards_thread_outerdepth = 4 +standards_thread_innerdepth = 5 +standards_thread_round = 6 + +standards_thread = { +# Standard name : { Thread diameter : (pitch, flank diameter, core diameter, thread depth outer, thread depth inner, round) } +# Note: This table only has the most common thread diameters + "DIN 13-1" : { + 1.0 : (0.25, 0.838, 0.693, 0.729, 0.153, 0.135, 0.036), + 1.1 : (0.25, 0.938, 0.793, 0.829, 0.153, 0.135, 0.036), + 1.2 : (0.25, 1.038, 0.893, 0.929, 0.153, 0.135, 0.036), + 2.0 : (0.4, 1.740, 1.509, 1.567, 0.245, 0.217, 0.058), + 3.0 : (0.5, 2.675, 2.387, 2.459, 0.307, 0.271, 0.072), + 4.0 : (0.7, 3.545, 3.141, 3.242, 0.429, 0.379, 0.101 ), + 5.0 : (0.8, 4.480, 4.019, 4.134, 0.491, 0.433, 0.115), + 6.0 : (1.0, 5.350, 4.773, 4.917, 0.613, 0.541, 0.144), + 7.0 : (1.0, 6.350, 5.773, 5.917, 0.613, 0.541, 0.144), + 8.0 : (1.25, 7.188, 6.466, 6.647, 0.767, 0.677, 0.180), + 10.0 : (1.5, 9.026, 8.160, 8.376, 0.920, 0.812, 0.217), + 12.0 : (1.75, 10.863, 9.853, 10.106, 1.074, 0.947, 0.253), + 14.0 : (2.0, 12.701, 11.546, 11.835, 1.227, 1.083, 0.289), + 16.0 : (2.0, 14.701, 13.546, 13.835, 1.227, 1.083, 0.289), + 18.0 : (2.5, 16.376, 14.933, 15.294, 1.534, 1.353, 0.361), + 20.0 : (2.5, 18.376, 16.933, 17.294, 1.534, 1.353, 0.361), + 22.0 : (2.5, 20.376, 18.933, 19.294, 1.534, 1.353, 0.361), + 24.0 : (3.0, 22.051, 20.319, 20.752, 1.840, 1.624, 0.433), + 27.0 : (3.0, 25.051, 23.319, 23.752, 1.840, 1.624, 0.433), + 30.0 : (3.5, 27.727, 25.706, 26.211, 2.147, 1.894, 0.505), + 33.0 : (3.5, 30.727, 28.706, 29.211, 2.147, 1.894, 0.505), + 36.0 : (4.0, 33.402, 31.093, 31.670, 2.454, 2.165, 0.577), + 39.0 : (4.0, 36.402, 34.093, 34.670, 2.454, 2.165, 0.577), + 42.0 : (4.5 , 39.077, 36.479, 37.129, 2.760, 2.436, 0.650), + 45.0 : (4.5, 42.077, 39.479, 40.129, 2.760, 2.436, 0.650) + } +} + +def getStandards(holetype): + "Return the names of all available standards for the given hole type" + result = [] + for key, value in standards.items(): + if value[StandardType] == holetype: + result.append(key) + + #FreeCAD.Console.PrintMessage("Number of matching standards: " + str(len(result)) + "\n") + return sorted(result) + +def getBaseDiameters(standard): + "Return the base diameters of all holes defined in the given norm" + if not standard in standards.keys(): + return [] + #FreeCAD.Console.PrintMessage("Getting diameters for " + standard + "\n") + if standards[standard][StandardType] == "through": + return standards_through[standard].keys() + elif standards[standard][StandardType] == "counterbore": + return standards_counterbore[standard].keys() + elif standards[standard][StandardType] == "countersink": + return standards_countersink[standard].keys() + elif standards[standard][StandardType] == "thread": + return standards_thread[standard].keys() + return [] + +def getThroughHoleDia(standard, threadDia, tolerance = "medium"): + if not standard in standards_through.keys(): + raise Exception("No such standard exists") + values = standards_through[standard] + if not threadDia in values: + FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard)) + return values[values.keys()[0]][standards_tolerance.index(tolerance)] + return values[threadDia][standards_tolerance.index(tolerance)] + +def getThroughHoleStandard(standard): + if not standard in standards_counterbore_through.keys(): + raise Exception("No such standard exists") + return standards_counterbore_through[standard] + +def getCounterboreDia(standard, threadDia, extraStandard = ""): + if not standard in standards_counterbore.keys(): + raise Exception("No such standard exists") + values = standards_counterbore[standard] + if not threadDia in values: + FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard)) + return values[values.keys()[0]][0] + row = 1 # Use row 1 by default + for r in standards_counterbore_rows[standard].keys(): + if extraStandard in standards_counterbore_rows[standard][r]: + row = r + break + return values[threadDia][row-1] + +def calcCounterboreDepth(standard, threadDia, standardBolt, standardsWashers = []): + headHeight = getBoltHead(standardBolt) + washerHeight = 0.0 + for standard in standardsWashers: + washerHeight = washerHeight + getWasherHeight(standard) + for maxThread in reverse(standards_counterbore_extradepth.keys()): + if threadDia <= maxThread: + extraDepth = standards_counterbore_extradepth[maxThread] + return headHeight + washerHeight + extraDepth + +def getRowStandards(standard): + if not standard in standards_counterbore_rows.keys(): + raise Exception("No such standard exists") + result = [] + rowdict = standards_counterbore_rows[standard] + for stds in rowdict.values(): + for std in stds: + if std != "": + result.append(std) + return result + +def getCountersinkDia(standard, threadDia): + if not standard in standards_countersink.keys(): + raise Exception("No such standard exists") + values = standards_countersink[standard] + if not threadDia in values: + FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard)) + return values[values.keys()[0]][standards_countersink_dia] + return values[threadDia][standards_countersink_dia] + +def getCountersinkAngle(standard, threadDia): + if not standard in standards_countersink.keys(): + raise Exception("No such standard exists") + values = standards_countersink[standard] + if not threadDia in values: + FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard)) + return values[values.keys()[0]][standards_countersink_angle] + return values[threadDia][standards_countersink_angle] + +def getThreadCoreDiameter(standard, threadDia): + if not standard in standards_thread.keys(): + raise Exception("No such standard exists") + values = standards_thread[standard] + if not threadDia in values: + FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard)) + return values[values.keys()[0]][standards_thread_innercoredia] + return values[threadDia][standards_thread_innercoredia] + +def getThreadFinishLength(standard, threadDia, length = "normal"): + if not standard in standards_threaded.keys(): + raise Exception("No such standard exists") + stdThread = standards_threaded_thread[standard] + values = standards_thread[stdThread] + if not threadDia in values: + FreeCAD.Console.PrintMessage("Warning: Diameter %f is not in %s" % (threadDia, standard)) + return values[values.keys()[0]][standards_thread_pitch] + pitch = values[threadDia][standards_thread_pitch] + return standards_threaded[standard][pitch][standards_threaded_types.index(length)] diff --git a/src/Mod/PartDesign/FeatureHole/TaskHole.py b/src/Mod/PartDesign/FeatureHole/TaskHole.py new file mode 100644 index 000000000000..5eec78c20372 --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/TaskHole.py @@ -0,0 +1,659 @@ +#/****************************************************************************** +# * Copyright (c)2012 Jan Rheinlaender * +# * * +# * 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 * +# * * +# ******************************************************************************/ + +import FreeCAD, FreeCADGui +import Part, PartDesignGui +from PyQt4 import QtCore, QtGui +import Standards +import os + +class TaskHole: + "Hole hole feature" + types = ["Linear", "Coaxial"] + typestr = ["Linear to two lines/planes", "Coaxial to a circle/cylinder"] + + def __init__(self, feature): + self.form = None + self.extraStandards = [] + self.feature = feature + p=os.path.realpath(__file__) + p=os.path.dirname(p) + self.ui = os.path.join(p, "TaskHole.ui") + + def accept(self): + self.feature.touch() + FreeCAD.ActiveDocument.recompute() + FreeCADGui.ActiveDocument.resetEdit() + return True + + def reject(self): + if (self.feature != None): + self.hideFeature() # Show the support again + document = self.feature.Document + body = PartDesignGui.getActivePart() + groove = self.feature.HoleGroove + sketch = groove.Sketch + plane = sketch.Support[0] + axis = plane.References[0][0] + body.removeFeature(self.feature) + document.removeObject(self.feature.Name) + body.removeFeature(groove) + document.removeObject(groove.Name) + body.removeFeature(sketch) + try: + document.removeObject(sketch.Name) + except: + pass # This always throws an exception: "Sketch support has been deleted" from SketchObject::execute() + body.removeFeature(plane) + document.removeObject(plane.Name) + body.removeFeature(axis) + document.removeObject(axis.Name) + FreeCADGui.ActiveDocument.resetEdit() + FreeCADGui.Control.closeDialog(self) + return True + + def isAllowedAlterDocument(self): + return False + + def isAllowedAlterView(self): + return False + + def isAllowedAlterSelection(self): + return True + + def getMainWindow(self): + "returns the main window" + # using QtGui.qApp.activeWindow() isn't very reliable because if another + # widget than the mainwindow is active (e.g. a dialog) the wrong widget is + # returned + toplevel = QtGui.qApp.topLevelWidgets() + for i in toplevel: + if i.metaObject().className() == "Gui::MainWindow": + return i + raise Exception("No main window found") + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskHole") + if form == None: + return + form.tabWidget = form.findChild(QtGui.QTabWidget, "tabWidget") + # Type + form.tabType = form.tabWidget.findChild(QtGui.QWidget, "tab_type") + form.buttonThru = form.tabType.findChild(QtGui.QRadioButton, "buttonThru") + form.buttonDepth = form.tabType.findChild(QtGui.QRadioButton, "buttonDepth") + form.checkThreaded = form.tabType.findChild(QtGui.QCheckBox, "checkThreaded") + form.checkCounterbore = form.tabType.findChild(QtGui.QCheckBox, "checkCounterbore") + form.checkCountersink = form.tabType.findChild(QtGui.QCheckBox, "checkCountersink") + # Norm + form.tabNorm = form.tabWidget.findChild(QtGui.QWidget, "tab_norm") + form.checkCustom = form.tabNorm.findChild(QtGui.QCheckBox, "checkCustom") + form.comboNorm = form.tabNorm.findChild(QtGui.QComboBox, "comboNorm") + for std in Standards.getStandards("through"): + form.comboNorm.addItem(std) + form.comboTolerance = form.tabNorm.findChild(QtGui.QComboBox, "comboTolerance") + for tol in Standards.standards_tolerance: + form.comboTolerance.addItem(tol) + form.comboNormDia = form.tabNorm.findChild(QtGui.QComboBox, "comboNormDia") + form.comboNormBoltWasher = form.tabNorm.findChild(QtGui.QComboBox, "comboNormBoltWasher") + # Thread + form.tabThread = form.tabWidget.findChild(QtGui.QWidget, "tab_thread") + form.comboThreadNorm = form.tabThread.findChild(QtGui.QComboBox, "comboThreadNorm") + for std in Standards.getStandards("thread"): + form.comboThreadNorm.addItem(std) + form.comboThreadDia = form.tabThread.findChild(QtGui.QComboBox, "comboThreadDia") + form.checkCustomThreadLength = form.tabThread.findChild(QtGui.QCheckBox, "checkCustomThreadLength") + form.comboFinishNorm = form.tabThread.findChild(QtGui.QComboBox, "comboFinishNorm") + for std in Standards.getStandards("threaded"): + form.comboFinishNorm.addItem(std) + # Data + form.tabData = form.tabWidget.findChild(QtGui.QWidget, "tab_data") + form.spinDiameter = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinDiameter") + form.spinDepth = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinDepth") + form.spinCounterboreDiameter = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCounterboreDiameter") + form.spinCounterboreDepth = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCounterboreDepth") + form.spinCountersinkAngle = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinCountersinkAngle") + form.spinThreadLength = form.tabData.findChild(QtGui.QDoubleSpinBox, "spinThreadLength") + # Position + form.tabPosition = form.tabWidget.findChild(QtGui.QWidget, "tab_position") + form.comboType = form.tabPosition.findChild(QtGui.QComboBox, "comboType") + for i in self.typestr: + form.comboType.addItem(i) + form.buttonSupport = form.tabPosition.findChild(QtGui.QPushButton, "buttonSupport") + form.lineSupport = form.tabPosition.findChild(QtGui.QLineEdit, "lineSupport") + form.buttonRef1 = form.tabPosition.findChild(QtGui.QPushButton, "buttonRef1") + form.lineRef1 = form.tabPosition.findChild(QtGui.QLineEdit, "lineRef1") + form.labelRef1 = form.tabPosition.findChild(QtGui.QLabel, "labelRef1") + form.spinRef1 = form.tabPosition.findChild(QtGui.QDoubleSpinBox, "spinRef1") + form.buttonRef2 = form.tabPosition.findChild(QtGui.QPushButton, "buttonRef2") + form.lineRef2 = form.tabPosition.findChild(QtGui.QLineEdit, "lineRef2") + form.labelRef2 = form.tabPosition.findChild(QtGui.QLabel, "labelRef2") + form.spinRef2 = form.tabPosition.findChild(QtGui.QDoubleSpinBox, "spinRef2") + self.form = form + + # Connect Signals and Slots + # Type + self.form.buttonThru.toggled.connect(self.buttonThru) + self.form.buttonDepth.toggled.connect(self.buttonDepth) + self.form.checkThreaded.toggled.connect(self.checkThreaded) + self.form.checkCounterbore.toggled.connect(self.checkCounterbore) + self.form.checkCountersink.toggled.connect(self.checkCountersink) + # Norm + self.form.checkCustom.toggled.connect(self.checkCustom) + self.form.comboNorm.currentIndexChanged.connect(self.comboNorm) + self.form.comboTolerance.currentIndexChanged.connect(self.comboTolerance) + self.form.comboNormDia.currentIndexChanged.connect(self.comboNormDia) + self.form.comboNormBoltWasher.currentIndexChanged.connect(self.comboNormBoltWasher) + # Thread + self.form.comboThreadNorm.currentIndexChanged.connect(self.comboThreadNorm) + self.form.comboThreadDia.currentIndexChanged.connect(self.comboThreadDia) + self.form.checkCustomThreadLength.toggled.connect(self.checkCustomThreadLength) + self.form.comboFinishNorm.currentIndexChanged.connect(self.comboFinishNorm) + # Data + self.form.spinDiameter.valueChanged.connect(self.spinDiameter) + self.form.spinDepth.valueChanged.connect(self.spinDepth) + self.form.spinCounterboreDiameter.valueChanged.connect(self.spinCounterboreDiameter) + self.form.spinCounterboreDepth.valueChanged.connect(self.spinCounterboreDepth) + self.form.spinCountersinkAngle.valueChanged.connect(self.spinCountersinkAngle) + self.form.spinThreadLength.valueChanged.connect(self.spinThreadLength) + # Position + self.form.comboType.currentIndexChanged.connect(self.comboType) + self.form.buttonSupport.clicked.connect(self.buttonSupport) + self.form.buttonRef1.clicked.connect(self.buttonRef1) + self.form.spinRef1.valueChanged.connect(self.spinRef1) + self.form.buttonRef2.clicked.connect(self.buttonRef2) + self.form.spinRef2.valueChanged.connect(self.spinRef2) + + # Update the UI + self.updateUI() + + def getRefText(self, ref): + (obj, element) = ref + if isinstance(element, basestring): + return obj.Name + ":" + element + elif isinstance(element, list): + return obj.Name + ":" + element[0] + else: + return obj.Name + + def updateUI(self): + # Type + self.form.buttonThru.setChecked(self.feature.HoleType == "Thru") + self.form.buttonDepth.setChecked(self.feature.HoleType == "Depth") + self.form.checkThreaded.setChecked(self.feature.Threaded == True) + self.form.checkCounterbore.setChecked(self.feature.Counterbore == True) + self.form.checkCountersink.setChecked(self.feature.Countersink == True) + # Norm + if self.feature.Norm == "Custom": + self.form.checkCustom.setChecked(True) + self.form.comboNorm.setEnabled(False) + self.form.comboTolerance.setEnabled(False) + self.form.comboNormDia.setEnabled(False) + self.form.comboNormBoltWasher.setEnabled(False) + else: + if self.feature.Counterbore == True: + holetype = "counterbore" + elif self.feature.Countersink == True: + holetype = "countersink" + elif self.feature.Threaded == True: + holetype = "threaded" + else: + holetype = "through" + self.form.comboNorm.setEnabled(True) + self.form.comboTolerance.setEnabled(True) + self.form.comboNormDia.setEnabled(True) + if holetype == "counterbore": + self.form.comboNormBoltWasher.setEnabled(True) + else: + self.form.comboNormBoltWasher.setEnabled(False) + # comboNorm + standards = Standards.getStandards(holetype) + self.form.comboNorm.blockSignals(True) + self.form.comboNorm.clear() + for std in standards: + self.form.comboNorm.addItem(std) + if not self.feature.Norm in standards: + self.feature.Norm = standards[0] + else: + self.form.comboNorm.setCurrentIndex(standards.index(self.feature.Norm)) + self.form.comboNorm.blockSignals(False) + # comboTolerance + self.form.comboTolerance.blockSignals(True) + self.form.comboTolerance.setCurrentIndex(Standards.standards_tolerance.index(self.feature.NormTolerance)) + self.form.comboTolerance.blockSignals(False) + # comboNormDia + diameters = sorted(Standards.getBaseDiameters(self.feature.Norm)) + self.form.comboNormDia.blockSignals(True) + self.form.comboNormDia.clear() + for dia in diameters: + self.form.comboNormDia.addItem("M%g" % dia) + if self.feature.NormDiameter in diameters: + self.form.comboNormDia.setCurrentIndex(diameters.index(self.feature.NormDiameter)) + self.form.comboNormDia.blockSignals(False) + # comboNormBoltWasher + if holetype == "counterbore": + rowStandards = sorted(Standards.getRowStandards(self.feature.Norm)) + self.form.comboNormBoltWasher.blockSignals(True) + self.form.comboNormBoltWasher.clear() + for std in rowStandards: + self.form.comboNormBoltWasher.addItem(std) + if self.feature.ExtraNorm in rowStandards: + self.form.comboNormBoltWasher.setCurrentIndex(rowStandards.index(self.feature.ExtraNorm)) + self.form.comboNormBoltWasher.blockSignals(False) + # Dependent values + if holetype == "through": + self.feature.Diameter = Standards.getThroughHoleDia(self.feature.Norm, self.feature.NormDiameter, self.feature.NormTolerance) + elif holetype == "counterbore": + throughStandard = Standards.getThroughHoleStandard(self.feature.Norm) + self.feature.Diameter = Standards.getThroughHoleDia(throughStandard, self.feature.NormDiameter, self.feature.NormTolerance) + self.feature.CounterboreDiameter = Standards.getCounterboreDia(self.feature.Norm, self.feature.NormDiameter, self.feature.ExtraNorm) + # TODO: Calculate counter bore depth from standard for bolt and washer(s) + # Requires accessing all the norms for bolts + # self.feature.CounterboreDepth = calcCounterboreDepth(...) + elif holetype == "countersink": + throughStandard = Standards.getThroughHoleStandard(self.feature.Norm) + self.feature.Diameter = Standards.getThroughHoleDia(throughStandard, self.feature.NormDiameter, self.feature.NormTolerance) + self.feature.CounterboreDiameter = Standards.getCountersinkDia(self.feature.Norm, self.feature.NormDiameter) + self.feature.CountersinkAngle = Standards.getCountersinkAngle(self.feature.Norm, self.feature.NormDiameter) / 2.0 + # Thread + if self.feature.Threaded == True: + if not self.feature.Counterbore and not self.feature.Countersink: + self.form.comboTolerance.setEnabled(False) + else: + self.form.tabNorm.setEnabled(True) + self.form.comboTolerance.setEnabled(False) + self.form.tabThread.setEnabled(True) + self.form.comboThreadNorm.blockSignals(True) + standards = Standards.getStandards("thread") + if not self.feature.NormThread in standards: + self.feature.NormThread = standards[0] + else: + self.form.comboThreadNorm.setCurrentIndex(standards.index(self.feature.NormThread)) + self.form.comboThreadNorm.blockSignals(False) + threadDiameters = sorted(Standards.getBaseDiameters(self.feature.NormThread)) + self.form.comboThreadDia.blockSignals(True) + self.form.comboThreadDia.clear() + for dia in threadDiameters: + self.form.comboThreadDia.addItem("M%g" % dia) + if self.feature.NormDiameter in threadDiameters: + self.form.comboThreadDia.setCurrentIndex(threadDiameters.index(self.feature.NormDiameter)) + self.form.comboThreadDia.blockSignals(False) + if self.feature.NormThreadFinish == "Custom": + self.form.checkCustomThreadLength.setChecked(True) + self.form.comboFinishNorm.setEnabled(False) + else: + self.form.checkCustomThreadLength.setChecked(False) + self.form.comboFinishNorm.setEnabled(True) + self.form.comboFinishNorm.blockSignals(True) + standards = Standards.getStandards("threaded") + if not self.feature.NormThreadFinish in standards: + self.feature.NormThreadFinish = standards[0] + else: + self.form.comboFinishNorm.setCurrentIndex(standards.index(self.feature.NormThreadFinish)) + self.form.comboFinishNorm.blockSignals(False) + flength = Standards.getThreadFinishLength(self.feature.NormThreadFinish, self.feature.NormDiameter) + tlength = self.feature.Depth - flength + if tlength > 0: + self.feature.ThreadLength = tlength # TODO: Warning message + # Dependents + self.feature.Diameter = Standards.getThreadCoreDiameter(self.feature.NormThread, self.feature.NormDiameter) + else: + self.form.tabThread.setEnabled(False) + # Dependents + self.form.spinDiameter.setEnabled(True) + # Data + self.form.spinDiameter.setValue(self.feature.Diameter) + self.form.spinDepth.setValue(self.feature.Depth) + if self.feature.HoleType == "Thru": + self.form.spinDepth.setEnabled(False) + else: + self.form.spinDepth.setEnabled(True) + if self.feature.Threaded == True: + self.form.spinThreadLength.setEnabled(True) + else: + self.form.spinThreadLength.setEnabled(False) + if self.feature.Counterbore == True: + self.form.spinCounterboreDiameter.setEnabled(True) + self.form.spinCounterboreDiameter.setValue(self.feature.CounterboreDiameter) + self.form.spinCounterboreDepth.setEnabled(True) + self.form.spinCounterboreDepth.setValue(self.feature.CounterboreDepth) + self.form.spinCountersinkAngle.setEnabled(False) + elif self.feature.Countersink == True: + self.form.spinCounterboreDiameter.setEnabled(True) + self.form.spinCounterboreDiameter.setValue(self.feature.CounterboreDiameter) + self.form.spinCounterboreDepth.setEnabled(False) + self.form.spinCountersinkAngle.setEnabled(True) + self.form.spinCountersinkAngle.setValue(self.feature.CountersinkAngle) + else: + self.form.spinCounterboreDiameter.setEnabled(False) + self.form.spinCounterboreDepth.setEnabled(False) + self.form.spinCountersinkAngle.setEnabled(False) + if self.feature.Norm == "Custom": + self.form.spinDiameter.setEnabled(True) + else: + self.form.spinDiameter.setEnabled(False) + if holetype == "counterbore": + # Diameter is taken from Norm + self.form.spinCounterboreDiameter.setEnabled(False) + elif holetype == "countersink": + # Values are taken from Norm + self.form.spinCounterboreDiameter.setEnabled(False) + self.form.spinCounterboreDepth.setEnabled(False) + self.form.spinCountersinkAngle.setEnabled(False) + if self.feature.Threaded == True: + self.form.spinDiameter.setEnabled(False) + if self.feature.NormThreadFinish != "Custom": + self.form.spinThreadLength.setEnabled(False) + self.form.spinThreadLength.setValue(self.feature.ThreadLength) + # Position + self.form.buttonSupport.setText("Face") + if self.feature.Support == None: + # First-time initialization + selection = FreeCADGui.Selection.getSelectionEx() + self.feature.Support = (selection[0].Object, selection[0].SubElementNames) + self.form.lineSupport.setText(self.getRefText(self.feature.Support)) + if self.feature.PositionType == self.types[0]: + # Linear + self.form.buttonRef1.setText("Line/Plane") + self.form.buttonRef1.setEnabled(True) + self.form.buttonRef2.setText("Line/Plane") + self.form.buttonRef2.setEnabled(True) + self.form.lineRef1.setEnabled(True) + self.form.lineRef2.setEnabled(True) + self.form.labelRef1.setEnabled(True) + self.form.labelRef1.setText("Distance") + axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0] + if len(axis.References) > 0 and axis.References[0] != None: + if (len(axis.References) == 3): + self.form.lineRef1.setText(self.getRefText(axis.References[1])) + else: + self.form.lineRef1.setText(self.getRefText(axis.References[0])) + self.form.spinRef1.setEnabled(True) + self.form.spinRef1.setValue(axis.Offset) + self.form.labelRef2.setEnabled(True) + self.form.labelRef2.setText("Distance") + if len(axis.References) > 1 and axis.References[1] != None: + if (len(axis.References) == 3): + self.form.lineRef2.setText(self.getRefText(axis.References[2])) + else: + self.form.lineRef2.setText(self.getRefText(axis.References[1])) + self.form.spinRef2.setEnabled(True) + self.form.spinRef2.setValue(axis.Offset2) + elif self.feature.PositionType == self.types[1]: + # Coaxial + self.form.buttonRef1.setText("Circle/Cylinder") + self.form.buttonRef1.setEnabled(True) + self.form.buttonRef2.setEnabled(False) + self.form.lineRef1.setEnabled(True) + axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0] + if len(axis.References) > 0 and axis.References[0] != None: + self.form.lineRef1.setText(self.getRefText(axis.References[0])) + self.form.lineRef2.setEnabled(False) + self.form.labelRef1.setEnabled(False) + self.form.spinRef1.setEnabled(False) + self.form.labelRef2.setEnabled(False) + self.form.spinRef2.setEnabled(False) + else: + # Nothing else defined yet + pass + + def getStandardButtons(self): + return int(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + + def accept(self): + return True + + def buttonThru(self, toggle): + if toggle == True: + self.feature.HoleType = "Thru" + + def buttonDepth(self, toggle): + if toggle == True: + self.feature.HoleType = "Depth" + + def checkThreaded(self, checked): + self.feature.Threaded = checked + self.updateUI() + + def checkCounterbore(self, checked): + if checked == True: + self.feature.Countersink = False + self.feature.Counterbore = checked + self.updateUI() + + def checkCountersink(self, checked): + if checked == True: + self.feature.Counterbore = False + self.feature.Countersink = checked + self.updateUI() + + def checkCustom(self, checked): + if checked == True: + self.feature.Norm = "Custom" + else: + self.feature.Norm = str(self.form.comboNorm.currentText()) + self.updateUI() + + def comboNorm(self, index): + self.feature.Norm = str(self.form.comboNorm.itemText(index)) + self.updateUI() + + def comboTolerance(self, index): + self.feature.NormTolerance = str(self.form.comboTolerance.itemText(index)) + self.updateUI() + + def comboNormDia(self, index): + diameter = str(self.form.comboNormDia.itemText(index)) + self.feature.NormDiameter = float(diameter[1:]) + self.updateUI() + + def comboNormBoltWasher(self, index): + self.feature.ExtraNorm = str(self.form.comboNormBoltWasher.itemText(index)) + self.updateUI() + + def comboThreadNorm(self, index): + self.feature.NormThread = str(self.form.comboThreadNorm.itemText(index)) + self.updateUI() + + def comboThreadDia(self, index): + diameter = str(self.form.comboThreadDia.itemText(index)) + self.feature.NormDiameter = float(diameter[1:]) + self.updateUI() + + def checkCustomThreadLength(self, checked): + if checked == True: + self.feature.NormThreadFinish = "Custom" + else: + self.feature.NormThreadFinish = str(self.form.comboFinishNorm.currentText()) + self.updateUI() + + def comboFinishNorm(self, index): + self.feature.NormThreadFinish = str(self.form.comboFinishNorm.itemText(index)) + self.updateUI() + + def spinDiameter(self, val): + if (val > 0.0): + self.feature.Diameter = val + + def spinDepth(self, val): + if (val > 0.0): + self.feature.Depth = val + self.updateUI() # required to update the thread length + + def spinCounterboreDiameter(self, val): + if (val > self.feature.Diameter): + self.feature.CounterboreDiameter = val + + def spinCounterboreDepth(self, val): + if (val > 0.0): + self.feature.CounterboreDepth = val + + def spinCountersinkAngle(self, val): + if (val > 0.0): + self.feature.CountersinkAngle = val + + def spinThreadLength(self, val): + if (val > 0.0): + self.feature.ThreadLength = val + + def comboType(self, index): + self.feature.PositionType = self.types[index] + self.updateUI() + + def addSelection(self, document, obj, element, position): + #FreeCAD.Console.PrintMessage("AddSelection() for " + document + "." + obj + "." + element + "\n") + # TODO: What is the position parameter? + if document == self.feature.Document.Name: + axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0] + refs = axis.References + feature = eval("FreeCAD.getDocument('" + document + "')." + obj) + shape = eval("feature.Shape." + element) + if self.selectionMode == "Plane": + if shape.Surface.__class__ != Part.Plane: + FreeCAD.Console.PrintMessage("Selected face must be planar\n") + return + if self.feature.PositionType == self.types[0]: + # The Hole support is also the first reference of the sketch axis in Linear mode with edges selected + if len(refs) == 3: + refs[0] = (feature, element) + axis.References = refs + self.feature.Support = (feature, [element]) + elif self.selectionMode == "LinearReference": + if shape.ShapeType == "Edge": + if shape.Curve.__class__ != Part.Line: + FreeCAD.Console.PrintMessage("Selected edge must be linear\n") + return + if len(refs) > 1: + refs[1] = (feature, element) + else: + refs.append((feature, element)) + elif shape.ShapeType == "Face": + if shape.Surface.__class__ != Part.Plane: + FreeCAD.Console.PrintMessage("Selected face must be planar\n") + return + if len(refs) > 0: + if len(refs) > 2: + refs = [(feature, element)] + else: + refs[0] = (feature, element) + else: + refs = [(feature, element)] + else: + FreeCAD.Console.PrintMessage("Wrong shape type selected\n") + return + axis.References = refs + axis.Document.recompute() + elif self.selectionMode == "LinearReference2": + if shape.ShapeType == "Edge": + if shape.Curve.__class__ != Part.Line: + FreeCAD.Console.PrintMessage("Selected edge must be linear\n") + return + if len(refs) > 2: + refs[2] = (feature, element) + else: + refs.append((feature, element)) + elif shape.ShapeType == "Face": + if shape.Surface.__class__ != Part.Plane: + FreeCAD.Console.PrintMessage("Selected face must be planar\n") + return + if len(refs) > 1: + if len(refs) > 2: + del refs[2] + refs[1] = (feature, element) + else: + refs.append((feature, element)) + else: + FreeCAD.Console.PrintMessage("Wrong shape type selected\n") + return + axis.References = refs + axis.Document.recompute() + elif self.selectionMode == "CircularReference": + if shape.ShapeType == "Edge": + if shape.Curve.__class__ != Part.Circle: + FreeCAD.Console.PrintMessage("Selected edge must be arc or circle\n") + return + elif shape.ShapeType == "Face": + if shape.Surface.__class__ != Part.Cylinder: + FreeCAD.Console.PrintMessage("Selected face must be cylindrical\n") + return + else: + FreeCAD.Console.PrintMessage("Wrong shape type selected\n") + return + refs = [(feature, element)] + axis.References = refs + axis.Document.recompute() + else: + FreeCAD.Console.PrintMessage("Unknown selection mode: " + self.selectionMode + "\n") + self.selectionMode = "" + return + + FreeCADGui.Selection.removeObserver(self) + FreeCADGui.Selection.clearSelection() + FreeCADGui.Selection.removeSelectionGate() + self.selectionMode = "" + self.updateUI() + self.showFeature() + + def hideFeature(self): + # Make sure selection takes place on support, not on hole feature + if self.feature.Support != None: + FreeCADGui.ActiveDocument.hide(self.feature.Name) + (support, elements) = self.feature.Support + FreeCADGui.ActiveDocument.show(support.Name) + + def showFeature(self): + if self.feature.Support != None: + FreeCADGui.ActiveDocument.show(self.feature.Name) + (support, elements) = self.feature.Support + FreeCADGui.ActiveDocument.hide(support.Name) + + def buttonSupport(self): + FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Face COUNT 1") + FreeCADGui.Selection.addObserver(self) + # Currently support must be a planar face (but could also be a point or a construction plane in the future) + self.selectionMode = "Plane" + self.hideFeature() + + def buttonRef1(self): + FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Edge COUNT 1 SELECT Part::Feature SUBELEMENT Face COUNT 1") + FreeCADGui.Selection.addObserver(self) + if self.feature.PositionType == self.types[0]: + self.selectionMode = "LinearReference" + elif self.feature.PositionType == self.types[1]: + self.selectionMode = "CircularReference" + self.hideFeature() + + def buttonRef2(self): + FreeCADGui.Selection.addSelectionGate("SELECT Part::Feature SUBELEMENT Edge COUNT 1 SELECT Part::Feature SUBELEMENT Face COUNT 1") + FreeCADGui.Selection.addObserver(self) + self.selectionMode = "LinearReference2" + self.hideFeature() + + def spinRef1(self, val): + axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0] + axis.Offset = val + axis.Document.recompute() + + def spinRef2(self, val): + axis = self.feature.HoleGroove.Sketch.Support[0].References[0][0] + axis.Offset2 = val + axis.Document.recompute() diff --git a/src/Mod/PartDesign/FeatureHole/TaskHole.ui b/src/Mod/PartDesign/FeatureHole/TaskHole.ui new file mode 100644 index 000000000000..35b465b80c5d --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/TaskHole.ui @@ -0,0 +1,598 @@ + + + TaskHole + + + + 0 + 0 + 327 + 315 + + + + Form + + + + + + 0 + + + + Position + + + + + + + + + + + Face + + + + + + + + + + + + + + Edge + + + + + + + + + + + + + + Distance + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 5.000000000000000 + + + + + + + + + + + Edge + + + + + + + + + + + + + + Distance + + + + + + + -99999.000000000000000 + + + 99999.000000000000000 + + + 5.000000000000000 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Type + + + + + + + + Through + + + + + + + Depth + + + + + + + + + Threaded + + + + + + + Countersink + + + + + + + Counterbore + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Hole norm + + + + + + Custom dimensions + + + + + + + false + + + + + + + + + Tolerance + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Diameter + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Bolt/Washer + + + + + + + + 150 + 0 + + + + false + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 125 + + + + + + + + + Thread norm + + + + + + + + Thread norm + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Diameter + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Custom thread length + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Finish depth + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 81 + + + + + + + + + Data + + + + + + + + Diameter + + + + + + + 8.000000000000000 + + + + + + + + + + + Depth + + + + + + + 20.000000000000000 + + + + + + + + + + + Counterbore/sink dia + + + + + + + 15.000000000000000 + + + + + + + + + + + Counterbore depth + + + + + + + 7.000000000000000 + + + + + + + + + + + Countersink angle + + + + + + + 15.000000000000000 + + + + + + + + + + + Thread length + + + + + + + 5.000000000000000 + + + + + + + + + Qt::Vertical + + + + 20 + 3 + + + + + + + + + + + + + diff --git a/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py b/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py new file mode 100644 index 000000000000..5dd342446f72 --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py @@ -0,0 +1,98 @@ +#/****************************************************************************** +# * Copyright (c)2012 Jan Rheinlaender * +# * * +# * 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 * +# * * +# ******************************************************************************/ + +import FreeCAD, FreeCADGui +from TaskHole import TaskHole + +class ViewProviderHole: + def __init__(self, obj): + ''' Set this object to the proxy object of the actual view provider ''' + obj.Proxy = self + self.Object = obj.Object + + def attach(self, obj): + ''' Setup the scene sub-graph of the view provider, this method is mandatory ''' + return + + def claimChildren(self): + if self is None: + return + # The following statement leads to the error: + # : PyCXX: Error creating object of type N2Py7SeqBaseINS_6ObjectEEE from None + if not hasattr(self, "Object"): + return + + if self.Object != None: + return [self.Object.HoleGroove, # the groove feature + self.Object.HoleGroove.Sketch.Support[0], # the groove sketchplane (datum plane) feature + self.Object.HoleGroove.Sketch.Support[0].References[0][0]] # the sketchplane first reference (datum line) + + def updateData(self, fp, prop): + ''' If a property of the handled feature has changed we have the chance to handle this here ''' + return + + def getDisplayModes(self,obj): + ''' Return a list of display modes. ''' + modes=[] + return modes + + def getDefaultDisplayMode(self): + ''' Return the name of the default display mode. It must be defined in getDisplayModes. ''' + return "Shaded" + + def onChanged(self, vp, prop): + ''' Print the name of the property that has changed ''' + #FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") + pass + + def setEdit(self,vp,mode): + FreeCAD.Console.PrintMessage("setEdit\n") + panel = TaskHole(self.Object) + + FreeCADGui.Control.showDialog(panel) + if panel.setupUi(): + FreeCADGui.Control.closeDialog(panel) + return True + + return False + + def unsetEdit(self,vp,mode): + return + + def getIcon(self): + ''' Return the icon in XMP format which will appear in the tree view. This method is optional + and if not defined a default icon is shown. + ''' + return "" + + def __getstate__(self): + ''' When saving the document this object gets stored using Python's cPickle module. + Since we have some un-pickable here -- the Coin stuff -- we must define this method + to return a tuple of all pickable objects or None. + ''' + return None + + def __setstate__(self,state): + ''' When restoring the pickled object from document we have the chance to set some + internals here. Since no data were pickled nothing needs to be done here. + ''' + return None diff --git a/src/Mod/PartDesign/FeatureHole/__init__.py b/src/Mod/PartDesign/FeatureHole/__init__.py new file mode 100644 index 000000000000..68209b5dc53c --- /dev/null +++ b/src/Mod/PartDesign/FeatureHole/__init__.py @@ -0,0 +1,30 @@ +""" +Hole Feature +""" + +#/****************************************************************************** +# * Copyright (c)2012 Jan Rheinlaender * +# * * +# * 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 * +# * * +# ******************************************************************************/ + +# Empty file to treat the folder as a package +# Initialize eric to do code completion for freecad libs +# import sys +# sys.path.append("/home/jan/freizeit/freecad-build-dbg/lib") diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index a4d88cfca80c..8d4e0439f6a8 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -649,7 +649,9 @@ Gui::MenuItem* Workbench::setupMenuBar() const // << "PartDesign_Scaled" << "PartDesign_MultiTransform" << "Separator" - << "PartDesign_Boolean"; + << "PartDesign_Boolean" + << "Separator" + << "PartDesign_Hole"; // For 0.13 a couple of python packages like numpy, matplotlib and others // are not deployed with the installer on Windows. Thus, the WizardShaft is diff --git a/src/Mod/PartDesign/InitGui.py b/src/Mod/PartDesign/InitGui.py index ad3fc358cfe8..51653806846f 100644 --- a/src/Mod/PartDesign/InitGui.py +++ b/src/Mod/PartDesign/InitGui.py @@ -42,6 +42,7 @@ def Initialize(self): from WizardShaft import WizardShaft except ImportError: print "Wizard shaft module cannot be loaded" + from FeatureHole import HoleGui import PartDesignGui import PartDesign try: diff --git a/src/Mod/PartDesign/InitGui.py.orig b/src/Mod/PartDesign/InitGui.py.orig new file mode 100644 index 000000000000..3f17ef0962d1 --- /dev/null +++ b/src/Mod/PartDesign/InitGui.py.orig @@ -0,0 +1,72 @@ +# PartDesign gui init module +# (c) 2003 Juergen Riegel +# +# Gathering all the information to start FreeCAD +# This is the second one of three init scripts, the third one +# runs when the gui is up + +#*************************************************************************** +#* (c) Juergen Riegel (juergen.riegel@web.de) 2002 * +#* * +#* This file is part of the FreeCAD CAx development system. * +#* * +#* This program is free software; you can redistribute it and/or modify * +#* it under the terms of the GNU Lesser General Public License (LGPL) * +#* as published by the Free Software Foundation; either version 2 of * +#* the License, or (at your option) any later version. * +#* for detail see the LICENCE text file. * +#* * +#* 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 FreeCAD; if not, write to the Free Software * +#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +#* USA * +#* * +#* Juergen Riegel 2002 * +#***************************************************************************/ + +class PartDesignWorkbench ( Workbench ): + "PartDesign workbench object" + def __init__(self): + self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/PartDesign/Resources/icons/PartDesignWorkbench.svg" + self.__class__.MenuText = "Part Design" + self.__class__.ToolTip = "Part Design workbench" + +<<<<<<< 64a1a440055b8a4359349b7abffe8956e78196db + def Initialize(self): + # load the module + try: + from WizardShaft import WizardShaft + except ImportError: + print "Wizard shaft module cannot be loaded" + import PartDesignGui + import PartDesign + try: + import InvoluteGearFeature + except ImportError: + print "Involute gear module cannot be loaded" + def GetClassName(self): + return "PartDesignGui::Workbench" +======= + def Initialize(self): + # load the module + try: + from WizardShaft import WizardShaft + except ImportError: + print "Wizard shaft module cannot be loaded" + from FeatureHole import HoleGui + import PartDesignGui + import PartDesign + try: + import InvoluteGearFeature + except ImportError: + print "Involute gear module cannot be loaded" + def GetClassName(self): + return "PartDesignGui::Workbench" +>>>>>>> Python code of Hole Feature + +Gui.addWorkbench(PartDesignWorkbench()) From 3ff550f977d48be5a55896fe4ed228f83b241945 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 18 Sep 2013 14:19:44 +0200 Subject: [PATCH 202/664] Fixed double clicking bug in the viewprovider --- src/Mod/PartDesign/FeatureHole/HoleGui.py | 10 ++-------- src/Mod/PartDesign/FeatureHole/TaskHole.py | 1 + src/Mod/PartDesign/FeatureHole/ViewProviderHole.py | 9 ++++----- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/Mod/PartDesign/FeatureHole/HoleGui.py b/src/Mod/PartDesign/FeatureHole/HoleGui.py index c2c156ac84ca..59893d3787a7 100644 --- a/src/Mod/PartDesign/FeatureHole/HoleGui.py +++ b/src/Mod/PartDesign/FeatureHole/HoleGui.py @@ -69,19 +69,13 @@ def Activated(self): hole = Hole(feature) body.addFeature(feature) - ViewProviderHole(feature.ViewObject) + vp = ViewProviderHole(feature.ViewObject) feature.touch() FreeCAD.ActiveDocument.recompute() # Fit view (remove after the testing phase) FreeCADGui.SendMsgToActiveView("ViewFit") - panel = TaskHole(feature) - - FreeCADGui.Control.showDialog(panel) - if panel.setupUi(): - FreeCADGui.Control.closeDialog(panel) - return None - return panel + vp.setEdit(vp, 1) def GetResources(self): IconPath = FreeCAD.ConfigGet("AppHomePath") + "Mod/PartDesign/FeatureHole/PartDesign_Hole.svg" diff --git a/src/Mod/PartDesign/FeatureHole/TaskHole.py b/src/Mod/PartDesign/FeatureHole/TaskHole.py index 5eec78c20372..c02dda18237c 100644 --- a/src/Mod/PartDesign/FeatureHole/TaskHole.py +++ b/src/Mod/PartDesign/FeatureHole/TaskHole.py @@ -185,6 +185,7 @@ def setupUi(self): # Update the UI self.updateUI() + return True def getRefText(self, ref): (obj, element) = ref diff --git a/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py b/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py index 5dd342446f72..94f836ca52aa 100644 --- a/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py +++ b/src/Mod/PartDesign/FeatureHole/ViewProviderHole.py @@ -63,17 +63,16 @@ def onChanged(self, vp, prop): ''' Print the name of the property that has changed ''' #FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") pass - + def setEdit(self,vp,mode): - FreeCAD.Console.PrintMessage("setEdit\n") panel = TaskHole(self.Object) FreeCADGui.Control.showDialog(panel) - if panel.setupUi(): + if not panel.setupUi(): FreeCADGui.Control.closeDialog(panel) - return True + return False - return False + return True def unsetEdit(self,vp,mode): return From f007608c81ecc0a3e668b05751407bf651621ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 24 Sep 2013 17:05:50 +0000 Subject: [PATCH 203/664] throw exception at unsuported geometrie instead of crashing --- src/Mod/Assembly/App/Constraint.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp index 0343a39f7eb3..516f6324627e 100644 --- a/src/Mod/Assembly/App/Constraint.cpp +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -56,6 +56,9 @@ using namespace Assembly; namespace Assembly { +struct ConstraintInitException : std::exception { + const char* what() const throw() { return "Constraint cout not be initialised: unsoported geometry";} +}; PROPERTY_SOURCE(Assembly::Constraint, App::DocumentObject) @@ -102,6 +105,9 @@ void Constraint::init(Assembly::ItemAssembly* ass) { m_first_geom = initLink(First); m_second_geom = initLink(Second); + + if(!m_first_geom || !m_second_geom) + throw ConstraintInitException(); } PyObject *Constraint::getPyObject(void) From 14b3246974c05226d8078a43d5e51a6417387549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 24 Sep 2013 18:21:45 +0000 Subject: [PATCH 204/664] dont remove already removed view providers from the toplevel inventor node --- src/Gui/Document.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 6cb877102d18..af545e7f36c3 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -514,7 +514,11 @@ void Document::slotChangedObject(const App::DocumentObject& Obj, const App::Prop if (activeView && viewProvider) { if (d->_editViewProvider == ChildViewProvider) resetEdit(); - activeView->getViewer()->removeViewProvider(ChildViewProvider); + //remove the viewprovider serves the purpose of detaching the inventor nodes from the + //top level root in the viewer. However, if some of the children were grouped beneath the object + //earlier they are not anymore part of the toplevel inventor node. we need to check for that. + if(activeView->getViewer()->hasViewProvider(ChildViewProvider)) + activeView->getViewer()->removeViewProvider(ChildViewProvider); } } } From a15fbf3db66978704797091ae288ca5ef9506f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Tue, 24 Sep 2013 19:10:52 +0000 Subject: [PATCH 205/664] add parts and components to the selected or active assembly only and add user information --- src/Mod/Assembly/Gui/Command.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 4af10a38c584..29b255b89a0f 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -69,7 +69,9 @@ void CmdAssemblyAddNewPart::activated(int iMsg) dest = dynamic_cast(ActiveAsmObject); }else { - return; + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active or selected assembly"), + QObject::tr("You need a active or selected assembly to insert a part in.")); + return; } openCommand("Insert Part"); @@ -171,8 +173,10 @@ void CmdAssemblyAddExistingComponent::activated(int iMsg) }else if(ActiveAsmObject && ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { dest = dynamic_cast(ActiveAsmObject); }else { - - return; + + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active or selected assembly"), + QObject::tr("You need a active or selected assembly to insert a component in.")); + return; } // asking for file name (only step at the moment) @@ -197,7 +201,7 @@ void CmdAssemblyAddExistingComponent::activated(int iMsg) std::string fName( (const char*)fn.toUtf8()); - doCommand(Gui,"AssemblyLib.importAssembly('%s',AssemblyGui.getActiveAssembly())",fName.c_str()); + doCommand(Gui,"AssemblyLib.importAssembly('%s',App.ActiveDocument.%s)",fName.c_str(), dest->getNameInDocument()); this->updateActive(); } From 904799d4629d110cea6d69b4f2b986148e1b75f4 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 26 Sep 2013 21:10:29 +0200 Subject: [PATCH 206/664] Color already selected faces of Draft feature when adding more or removing faces --- .../PartDesign/Gui/TaskDraftParameters.cpp | 35 ++++++++++++++----- src/Mod/PartDesign/Gui/TaskDraftParameters.h | 3 ++ src/Mod/PartDesign/Gui/ViewProviderDraft.cpp | 32 +++++++++++++++++ src/Mod/PartDesign/Gui/ViewProviderDraft.h | 6 ++++ 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index 3ca579e7e64d..2bc3ca7d3445 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -137,9 +137,10 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) pcDraft->Base.setValue(base, faces); ui->listWidgetFaces->insertItem(0, QString::fromStdString(subName)); - pcDraft->getDocument()->recomputeFeature(pcDraft); - ui->buttonFaceAdd->setChecked(false); + clearButtons(NULL); + DraftView->highlightReferences(false); exitSelectionMode(); + pcDraft->getDocument()->recomputeFeature(pcDraft); } } else if ((selectionMode == faceRemove) && (subName.size() > 4 && subName.substr(0,4) == "Face")) { @@ -157,10 +158,11 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) QListWidgetItem* it = ui->listWidgetFaces->takeItem(ui->listWidgetFaces->row(*i)); delete it; } - } - pcDraft->getDocument()->recomputeFeature(pcDraft); - ui->buttonFaceRemove->setChecked(false); + } + clearButtons(NULL); + DraftView->highlightReferences(false); exitSelectionMode(); + pcDraft->getDocument()->recomputeFeature(pcDraft); } } else if ((selectionMode == plane)) { std::vector planes; @@ -186,13 +188,23 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) } } +void TaskDraftParameters::clearButtons(const QToolButton* notThis) +{ + if (ui->buttonFaceAdd != notThis) ui->buttonFaceAdd->setChecked(false); + if (ui->buttonFaceRemove != notThis) ui->buttonFaceRemove->setChecked(false); + if (ui->buttonLine != notThis) ui->buttonLine->setChecked(false); + if (ui->buttonPlane != notThis) ui->buttonPlane->setChecked(false); +} + void TaskDraftParameters::onButtonFaceAdd(bool checked) { if (checked) { + clearButtons(ui->buttonFaceAdd); hideObject(); selectionMode = faceAdd; - Gui::Selection().clearSelection(); + Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); + DraftView->highlightReferences(true); } else { exitSelectionMode(); } @@ -201,10 +213,12 @@ void TaskDraftParameters::onButtonFaceAdd(bool checked) void TaskDraftParameters::onButtonFaceRemove(bool checked) { if (checked) { + clearButtons(ui->buttonFaceRemove); hideObject(); selectionMode = faceRemove; - Gui::Selection().clearSelection(); + Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); + DraftView->highlightReferences(true); } else { exitSelectionMode(); } @@ -213,6 +227,7 @@ void TaskDraftParameters::onButtonFaceRemove(bool checked) void TaskDraftParameters::onButtonPlane(bool checked) { if (checked) { + clearButtons(ui->buttonPlane); hideObject(); selectionMode = plane; Gui::Selection().clearSelection(); @@ -225,6 +240,7 @@ void TaskDraftParameters::onButtonPlane(bool checked) void TaskDraftParameters::onButtonLine(bool checked) { if (checked) { + clearButtons(ui->buttonLine); hideObject(); selectionMode = line; Gui::Selection().clearSelection(); @@ -278,7 +294,7 @@ void TaskDraftParameters::hideObject() if (doc != NULL && base != NULL) { doc->setHide(DraftView->getObject()->getNameInDocument()); doc->setShow(base->getNameInDocument()); - } + } } void TaskDraftParameters::showObject() @@ -293,6 +309,7 @@ void TaskDraftParameters::showObject() void TaskDraftParameters::onAngleChanged(double angle) { + clearButtons(NULL); PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); pcDraft->Angle.setValue(angle); pcDraft->getDocument()->recomputeFeature(pcDraft); @@ -304,6 +321,7 @@ const double TaskDraftParameters::getAngle(void) const } void TaskDraftParameters::onReversedChanged(const bool on) { + clearButtons(NULL); PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); pcDraft->Reversed.setValue(on); pcDraft->getDocument()->recomputeFeature(pcDraft); @@ -338,6 +356,7 @@ void TaskDraftParameters::exitSelectionMode() { selectionMode = none; Gui::Selection().rmvSelectionGate(); + Gui::Selection().clearSelection(); showObject(); } diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.h b/src/Mod/PartDesign/Gui/TaskDraftParameters.h index ac4e07fa19d4..2b8c60636ba9 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.h @@ -77,6 +77,9 @@ private Q_SLOTS: void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); +private: + void clearButtons(const QToolButton* notThis); + private: QWidget* proxy; Ui_TaskDraftParameters* ui; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp index a4632d4dab35..dd82ec2aaaad 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp @@ -27,6 +27,8 @@ # include # include # include +# include +# include #endif #include "ViewProviderDraft.h" @@ -107,4 +109,34 @@ bool ViewProviderDraft::onDelete(const std::vector &s) return ViewProvider::onDelete(s); } +void ViewProviderDraft::highlightReferences(const bool on) +{ + PartDesign::Draft* pcDraft = static_cast(getObject()); + Part::Feature* base = static_cast(pcDraft->Base.getValue()); + if (base == NULL) return; + PartGui::ViewProviderPart* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(base)); + if (vp == NULL) return; + + if (on) { + std::vector SubVals = pcDraft->Base.getSubValuesStartsWith("Face"); + if (SubVals.size() == 0) return; + + TopTools_IndexedMapOfShape fMap; + TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); + + originalColors = vp->DiffuseColor.getValues(); + std::vector colors = originalColors; + colors.resize(fMap.Extent(), ShapeColor.getValue()); + + for (std::vector::const_iterator f = SubVals.begin(); f != SubVals.end(); f++) { + int idx = atoi(f->substr(4).c_str()) - 1; + // TODO: Find a better colour + colors[idx] = App::Color(0.2,1,0.2); + } + vp->DiffuseColor.setValues(colors); + } else { + vp->DiffuseColor.setValues(originalColors); + } +} diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.h b/src/Mod/PartDesign/Gui/ViewProviderDraft.h index 0709c8f40f16..16b03f6c7e92 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.h @@ -44,9 +44,15 @@ class PartDesignGuiExport ViewProviderDraft : public ViewProvider virtual bool onDelete(const std::vector &); + /// Highlight the faces that have been selected + void highlightReferences(const bool on); + protected: virtual bool setEdit(int ModNum); +private: + std::vector originalColors; + }; From d32317229df167a08005bfb719012dace3667f6e Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 26 Sep 2013 21:10:46 +0200 Subject: [PATCH 207/664] Fix bug in workbench --- src/Mod/PartDesign/Gui/ViewProvider.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/ViewProvider.cpp b/src/Mod/PartDesign/Gui/ViewProvider.cpp index 2b4858b87a67..d63ccf808509 100644 --- a/src/Mod/PartDesign/Gui/ViewProvider.cpp +++ b/src/Mod/PartDesign/Gui/ViewProvider.cpp @@ -78,7 +78,8 @@ bool ViewProvider::doubleClicked(void) void ViewProvider::unsetEdit(int ModNum) { // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); + if (!oldWb.empty()) + Gui::Command::assureWorkbench(oldWb.c_str()); if (ModNum == ViewProvider::Default) { // when pressing ESC make sure to close the dialog From a59901ee4b30517b1e8239bc1f0040d8df68f140 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 26 Sep 2013 21:11:54 +0200 Subject: [PATCH 208/664] Some code unification for DressUp features --- src/Mod/PartDesign/App/FeatureChamfer.cpp | 18 +-- .../PartDesign/App/FeatureChamfer.cpp.orig | 153 ++++++++++++++++++ src/Mod/PartDesign/App/FeatureDraft.cpp | 18 +-- src/Mod/PartDesign/App/FeatureDressUp.cpp | 17 ++ src/Mod/PartDesign/App/FeatureDressUp.h | 1 + src/Mod/PartDesign/App/FeatureFillet.cpp | 18 +-- src/Mod/PartDesign/App/FeatureFillet.cpp.orig | 143 ++++++++++++++++ 7 files changed, 335 insertions(+), 33 deletions(-) create mode 100644 src/Mod/PartDesign/App/FeatureChamfer.cpp.orig create mode 100644 src/Mod/PartDesign/App/FeatureFillet.cpp.orig diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp index 77d3bb10e0d4..2c0685abf553 100644 --- a/src/Mod/PartDesign/App/FeatureChamfer.cpp +++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp @@ -35,6 +35,7 @@ #endif #include +#include #include #include @@ -66,17 +67,12 @@ App::DocumentObjectExecReturn *Chamfer::execute(void) { // NOTE: Normally the Base property and the BaseFeature property should point to the same object. // The only difference is that the Base property also stores the edges that are to be chamfered - App::DocumentObject* link = BaseFeature.getValue(); - if (!link) - link = Base.getValue(); // For legacy features - if (!link) - return new App::DocumentObjectExecReturn("No object linked"); - if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("Linked object is not a Part object"); - Part::Feature *base = static_cast(link); - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()) - return new App::DocumentObjectExecReturn("Cannot chamfer invalid shape"); + Part::TopoShape TopShape; + try { + TopShape = getBaseShape(); + } catch (Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } const std::vector& SubVals = Base.getSubValuesStartsWith("Edge"); if (SubVals.size() == 0) diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp.orig b/src/Mod/PartDesign/App/FeatureChamfer.cpp.orig new file mode 100644 index 000000000000..063bcc439c5a --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp.orig @@ -0,0 +1,153 @@ +/*************************************************************************** + * Copyright (c) 2010 Juergen Riegel * + * * + * 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 +# include +# include +# include +# include +# include +# include +#endif + +<<<<<<< 50287516b47694e57429cc98f6d5596a06a635d6 +#include +#include +======= +#include +>>>>>>> Some code unification for DressUp features +#include + +#include "FeatureChamfer.h" + + +using namespace PartDesign; + + +PROPERTY_SOURCE(PartDesign::Chamfer, PartDesign::DressUp) + +const App::PropertyQuantityConstraint::Constraints floatSize = {0.0,FLT_MAX,0.1}; + +Chamfer::Chamfer() +{ + ADD_PROPERTY(Size,(1.0)); + Size.setUnit(Base::Unit::Length); + Size.setConstraints(&floatSize); +} + +short Chamfer::mustExecute() const +{ + if (Placement.isTouched() || Size.isTouched()) + return 1; + return DressUp::mustExecute(); +} + +App::DocumentObjectExecReturn *Chamfer::execute(void) +{ + // NOTE: Normally the Base property and the BaseFeature property should point to the same object. + // The only difference is that the Base property also stores the edges that are to be chamfered + Part::TopoShape TopShape; + try { + TopShape = getBaseShape(); + } catch (Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } + + const std::vector& SubVals = Base.getSubValuesStartsWith("Edge"); + if (SubVals.size() == 0) + return new App::DocumentObjectExecReturn("No edges specified"); + + double size = Size.getValue(); + + this->positionByBaseFeature(); + // create an untransformed copy of the basefeature shape + Part::TopoShape baseShape(TopShape); + baseShape.setTransform(Base::Matrix4D()); + try { + BRepFilletAPI_MakeChamfer mkChamfer(baseShape._Shape); + + TopTools_IndexedMapOfShape mapOfEdges; + TopTools_IndexedDataMapOfShapeListOfShape mapEdgeFace; + TopExp::MapShapesAndAncestors(baseShape._Shape, TopAbs_EDGE, TopAbs_FACE, mapEdgeFace); + TopExp::MapShapes(baseShape._Shape, TopAbs_EDGE, mapOfEdges); + + for (std::vector::const_iterator it=SubVals.begin(); it != SubVals.end(); ++it) { + TopoDS_Edge edge = TopoDS::Edge(baseShape.getSubShape(it->c_str())); + const TopoDS_Face& face = TopoDS::Face(mapEdgeFace.FindFromKey(edge).First()); + mkChamfer.Add(size, edge, face); + } + + mkChamfer.Build(); + if (!mkChamfer.IsDone()) + return new App::DocumentObjectExecReturn("Failed to create chamfer"); + + TopoDS_Shape shape = mkChamfer.Shape(); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is null"); + + this->Shape.setValue(shape); + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } +} + +void Chamfer::Restore(Base::XMLReader &reader) +{ + reader.readElement("Properties"); + int Cnt = reader.getAttributeAsInteger("Count"); + + for (int i=0 ;igetTypeId().getName(), TypeName) == 0) { + prop->Restore(reader); + } + else if (prop && strcmp(TypeName,"App::PropertyFloatConstraint") == 0 && + strcmp(prop->getTypeId().getName(), "App::PropertyQuantityConstraint") == 0) { + App::PropertyFloatConstraint p; + p.Restore(reader); + static_cast(prop)->setValue(p.getValue()); + } + } + catch (const Base::XMLParseException&) { + throw; // re-throw + } + catch (const Base::Exception &e) { + Base::Console().Error("%s\n", e.what()); + } + catch (const std::exception &e) { + Base::Console().Error("%s\n", e.what()); + } + reader.readEndElement("Property"); + } + reader.readEndElement("Properties"); +} diff --git a/src/Mod/PartDesign/App/FeatureDraft.cpp b/src/Mod/PartDesign/App/FeatureDraft.cpp index f3e8a686f41b..ca46e02abc26 100644 --- a/src/Mod/PartDesign/App/FeatureDraft.cpp +++ b/src/Mod/PartDesign/App/FeatureDraft.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include "FeatureDraft.h" @@ -90,17 +91,12 @@ App::DocumentObjectExecReturn *Draft::execute(void) { // Get parameters // Base shape - App::DocumentObject* link = BaseFeature.getValue(); - if (!link) - link = Base.getValue(); // For legacy features - if (!link) - return new App::DocumentObjectExecReturn("No object linked"); - if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("Linked object is not a Part object"); - Part::Feature *base = static_cast(link); - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()) - return new App::DocumentObjectExecReturn("Cannot draft invalid shape"); + Part::TopoShape TopShape; + try { + TopShape = getBaseShape(); + } catch (Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } // Faces where draft should be applied // Note: Cannot be const reference currently because of BRepOffsetAPI_DraftAngle::Remove() bug, see below diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp b/src/Mod/PartDesign/App/FeatureDressUp.cpp index 8d8a42a64047..95fc0467f405 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.cpp +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp @@ -27,6 +27,7 @@ #include "FeatureDressUp.h" +#include using namespace PartDesign; @@ -57,6 +58,22 @@ void DressUp::positionByBaseFeature(void) this->Placement.setValue(base->Placement.getValue()); } +Part::TopoShape DressUp::getBaseShape() +{ + App::DocumentObject* link = BaseFeature.getValue(); + if (!link) + link = this->Base.getValue(); // For legacy features + if (!link) + throw Base::Exception("No object linked"); + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + throw Base::Exception("Linked object is not a Part object"); + Part::Feature* base = static_cast(link); + const Part::TopoShape& shape = base->Shape.getShape(); + if (shape._Shape.IsNull()) + throw Base::Exception("Cannot draft invalid shape"); + return shape; +} + void DressUp::onChanged(const App::Property* prop) { if (prop == &BaseFeature) { diff --git a/src/Mod/PartDesign/App/FeatureDressUp.h b/src/Mod/PartDesign/App/FeatureDressUp.h index 81e8a556d30c..af143e8fc97d 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.h +++ b/src/Mod/PartDesign/App/FeatureDressUp.h @@ -42,6 +42,7 @@ class PartDesignExport DressUp : public PartDesign::Feature short mustExecute() const; /// updates the Placement property from the Placement of the BaseFeature void positionByBaseFeature(void); + Part::TopoShape getBaseShape(); protected: void onChanged(const App::Property* prop); diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp index d0ba0622255c..0c82686dfc8d 100644 --- a/src/Mod/PartDesign/App/FeatureFillet.cpp +++ b/src/Mod/PartDesign/App/FeatureFillet.cpp @@ -32,6 +32,7 @@ #endif #include +#include #include #include @@ -61,17 +62,12 @@ short Fillet::mustExecute() const App::DocumentObjectExecReturn *Fillet::execute(void) { - App::DocumentObject* link = BaseFeature.getValue(); - if (!link) - link = Base.getValue(); // For legacy features - if (!link) - return new App::DocumentObjectExecReturn("No object linked"); - if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("Linked object is not a Part object"); - Part::Feature *base = static_cast(link); - const Part::TopoShape& TopShape = base->Shape.getShape(); - if (TopShape._Shape.IsNull()) - return new App::DocumentObjectExecReturn("Cannot fillet invalid shape"); + Part::TopoShape TopShape; + try { + TopShape = getBaseShape(); + } catch (Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } const std::vector& SubVals = Base.getSubValuesStartsWith("Edge"); if (SubVals.size() == 0) diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp.orig b/src/Mod/PartDesign/App/FeatureFillet.cpp.orig new file mode 100644 index 000000000000..7e4324a6f6fc --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureFillet.cpp.orig @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (c) 2008 Werner Mayer * + * * + * 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 +# include +# include +# include +#endif + +<<<<<<< 50287516b47694e57429cc98f6d5596a06a635d6 +#include +#include +======= +#include +>>>>>>> Some code unification for DressUp features +#include + +#include "FeatureFillet.h" + + +using namespace PartDesign; + + +PROPERTY_SOURCE(PartDesign::Fillet, PartDesign::DressUp) + +const App::PropertyQuantityConstraint::Constraints floatRadius = {0.0,FLT_MAX,0.1}; + +Fillet::Fillet() +{ + ADD_PROPERTY(Radius,(1.0)); + Radius.setUnit(Base::Unit::Length); + Radius.setConstraints(&floatRadius); +} + +short Fillet::mustExecute() const +{ + if (Placement.isTouched() || Radius.isTouched()) + return 1; + return DressUp::mustExecute(); +} + +App::DocumentObjectExecReturn *Fillet::execute(void) +{ + Part::TopoShape TopShape; + try { + TopShape = getBaseShape(); + } catch (Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } + + const std::vector& SubVals = Base.getSubValuesStartsWith("Edge"); + if (SubVals.size() == 0) + return new App::DocumentObjectExecReturn("No edges specified"); + + double radius = Radius.getValue(); + + this->positionByBaseFeature(); + + // create an untransformed copy of the base shape + Part::TopoShape baseShape(TopShape); + baseShape.setTransform(Base::Matrix4D()); + try { + BRepFilletAPI_MakeFillet mkFillet(baseShape._Shape); + + for (std::vector::const_iterator it=SubVals.begin(); it != SubVals.end(); ++it) { + TopoDS_Edge edge = TopoDS::Edge(baseShape.getSubShape(it->c_str())); + mkFillet.Add(radius, edge); + } + + mkFillet.Build(); + if (!mkFillet.IsDone()) + return new App::DocumentObjectExecReturn("Failed to create fillet"); + + TopoDS_Shape shape = mkFillet.Shape(); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is null"); + + this->Shape.setValue(shape); + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } +} + +void Fillet::Restore(Base::XMLReader &reader) +{ + reader.readElement("Properties"); + int Cnt = reader.getAttributeAsInteger("Count"); + + for (int i=0 ;igetTypeId().getName(), TypeName) == 0) { + prop->Restore(reader); + } + else if (prop && strcmp(TypeName,"App::PropertyFloatConstraint") == 0 && + strcmp(prop->getTypeId().getName(), "App::PropertyQuantityConstraint") == 0) { + App::PropertyFloatConstraint p; + p.Restore(reader); + static_cast(prop)->setValue(p.getValue()); + } + } + catch (const Base::XMLParseException&) { + throw; // re-throw + } + catch (const Base::Exception &e) { + Base::Console().Error("%s\n", e.what()); + } + catch (const std::exception &e) { + Base::Console().Error("%s\n", e.what()); + } + reader.readEndElement("Property"); + } + reader.readEndElement("Properties"); +} From fcea39b0d835f06761dd10f0ccafe36e88a61ecd Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Sat, 28 Sep 2013 16:17:55 +0200 Subject: [PATCH 209/664] Enable multiple originals for the transformed features --- src/Mod/PartDesign/App/FeatureTransformed.cpp | 52 +- src/Mod/PartDesign/App/FeatureTransformed.h | 5 +- src/Mod/PartDesign/Gui/ReferenceSelection.cpp | 3 + .../Gui/TaskLinearPatternParameters.cpp | 57 +- .../Gui/TaskLinearPatternParameters.cpp.orig | 92 ++-- .../Gui/TaskLinearPatternParameters.h | 2 + .../Gui/TaskLinearPatternParameters.ui | 23 +- .../PartDesign/Gui/TaskMirroredParameters.cpp | 55 +- .../Gui/TaskMirroredParameters.cpp.orig | 92 ++-- .../PartDesign/Gui/TaskMirroredParameters.h | 2 + .../PartDesign/Gui/TaskMirroredParameters.ui | 25 +- .../Gui/TaskMultiTransformParameters.cpp | 40 +- .../Gui/TaskMultiTransformParameters.cpp.orig | 512 ++++++++++++++++++ .../Gui/TaskMultiTransformParameters.h | 2 + .../Gui/TaskMultiTransformParameters.ui | 27 +- .../Gui/TaskPolarPatternParameters.cpp | 55 +- .../Gui/TaskPolarPatternParameters.cpp.orig | 82 +-- .../Gui/TaskPolarPatternParameters.h | 2 + .../Gui/TaskPolarPatternParameters.ui | 25 +- .../PartDesign/Gui/TaskScaledParameters.cpp | 43 +- .../Gui/TaskScaledParameters.cpp.orig | 287 ++++++++++ src/Mod/PartDesign/Gui/TaskScaledParameters.h | 2 + .../PartDesign/Gui/TaskScaledParameters.ui | 25 +- .../Gui/TaskTransformedParameters.cpp | 64 ++- .../Gui/TaskTransformedParameters.h | 11 +- .../Gui/ViewProviderTransformed.cpp | 92 ++-- .../Gui/ViewProviderTransformed.cpp.orig | 410 ++++++++++++++ .../PartDesign/Gui/ViewProviderTransformed.h | 6 +- 28 files changed, 1802 insertions(+), 291 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp.orig diff --git a/src/Mod/PartDesign/App/FeatureTransformed.cpp b/src/Mod/PartDesign/App/FeatureTransformed.cpp index 2ac20f93bc5b..f3b70dcd6121 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.cpp +++ b/src/Mod/PartDesign/App/FeatureTransformed.cpp @@ -56,7 +56,7 @@ namespace PartDesign { PROPERTY_SOURCE(PartDesign::Transformed, PartDesign::Feature) -Transformed::Transformed() : rejected(0) +Transformed::Transformed() { ADD_PROPERTY(Originals,(0)); Originals.setSize(0); @@ -202,8 +202,10 @@ App::DocumentObjectExecReturn *Transformed::execute(void) supportShape.setTransform(Base::Matrix4D()); TopoDS_Shape support = supportShape._Shape; - std::set::const_iterator> nointersect_trsfms; - std::set::const_iterator> overlapping_trsfms; + typedef std::set::const_iterator> trsf_it; + typedef std::map rej_it_map; + rej_it_map nointersect_trsfms; + rej_it_map overlapping_trsfms; // NOTE: It would be possible to build a compound from all original addShapes/subShapes and then // transform the compounds as a whole. But we choose to apply the transformations to each @@ -233,7 +235,8 @@ App::DocumentObjectExecReturn *Transformed::execute(void) } // Transform the add/subshape and collect the resulting shapes for overlap testing - std::vector::const_iterator> v_transformations; + typedef std::vector::const_iterator> trsf_it_vec; + trsf_it_vec v_transformations; std::vector v_transformedShapes; std::vector::const_iterator t = transformations.begin(); @@ -244,7 +247,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) BRepBuilderAPI_Copy copy(shape); shape = copy.Shape(); if (shape.IsNull()) - throw Base::Exception("Transformed: Linked shape object is empty"); + return new App::DocumentObjectExecReturn("Transformed: Linked shape object is empty"); BRepBuilderAPI_Transform mkTrf(shape, *t, false); // No need to copy, now if (!mkTrf.IsDone()) @@ -256,7 +259,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) #ifdef FC_DEBUG // do not write this in release mode because a message appears already in the task view Base::Console().Warning("Transformed shape does not intersect support %s: Removed\n", (*o)->getNameInDocument()); #endif - nointersect_trsfms.insert(t); + nointersect_trsfms[*o].insert(t); } else { v_transformations.push_back(t); v_transformedShapes.push_back(mkTrf.Shape()); @@ -274,7 +277,7 @@ App::DocumentObjectExecReturn *Transformed::execute(void) } if (v_transformedShapes.empty()) - break; // Skip the overlap check and go on to next original + continue; // Skip the overlap check and go on to next original // Check for overlapping of the original and the transformed shapes, and remove the overlapping transformations if (this->getTypeId() != PartDesign::MultiTransform::getClassTypeId()) { @@ -283,34 +286,35 @@ App::DocumentObjectExecReturn *Transformed::execute(void) if (v_transformedShapes.size() > 1) if (Part::checkIntersection(shape, v_transformedShapes.front(), false, false)) { // For single transformations, if one overlaps, all overlap, as long as we have uniform increments - overlapping_trsfms.insert(v_transformations.begin(),v_transformations.end()); + for (trsf_it_vec::const_iterator v = v_transformations.begin(); v != v_transformations.end(); v++) + overlapping_trsfms[*o].insert(*v); v_transformedShapes.clear(); } } else { // For MultiTransform, just checking the first transformed shape is not sufficient - any two // features might overlap, even if the original and the first shape don't overlap! - - std::set::iterator> rejected_iterators; + typedef std::set::iterator> shape_it_set; + shape_it_set rejected_iterators; std::vector::iterator s1 = v_transformedShapes.begin(); std::vector::iterator s2 = s1; ++s2; - std::vector::const_iterator>::const_iterator t1 = v_transformations.begin(); - std::vector::const_iterator>::const_iterator t2 = t1; + trsf_it_vec::const_iterator t1 = v_transformations.begin(); + trsf_it_vec::const_iterator t2 = t1; ++t2; for (; s2 != v_transformedShapes.end();) { // Check intersection with the original if (Part::checkIntersection(shape, *s1, false, false)) { rejected_iterators.insert(s1); - overlapping_trsfms.insert(*t1); + overlapping_trsfms[*o].insert(*t1); } // Check intersection with other transformations for (; s2 != v_transformedShapes.end(); ++s2, ++t2) if (Part::checkIntersection(*s1, *s2, false, false)) { rejected_iterators.insert(s1); rejected_iterators.insert(s2); - overlapping_trsfms.insert(*t1); - overlapping_trsfms.insert(*t2); + overlapping_trsfms[*o].insert(*t1); + overlapping_trsfms[*o].insert(*t2); } ++s1; s2 = s1; @@ -322,16 +326,16 @@ App::DocumentObjectExecReturn *Transformed::execute(void) // Check intersection of last transformation with the original if (Part::checkIntersection(shape, *s1, false, false)) { rejected_iterators.insert(s1); - overlapping_trsfms.insert(*t1); + overlapping_trsfms[*o].insert(*t1); } - for (std::set::iterator>::reverse_iterator it = rejected_iterators.rbegin(); + for (shape_it_set::reverse_iterator it = rejected_iterators.rbegin(); it != rejected_iterators.rend(); ++it) v_transformedShapes.erase(*it); } if (v_transformedShapes.empty()) - break; // Skip the boolean operation and go on to next original + continue; // Skip the boolean operation and go on to next original // Build a compound from all the valid transformations BRep_Builder builder; @@ -366,13 +370,13 @@ App::DocumentObjectExecReturn *Transformed::execute(void) if (!overlapping_trsfms.empty()) // Concentrate on overlapping shapes since they are more serious - for (std::set::const_iterator>::const_iterator it = overlapping_trsfms.begin(); - it != overlapping_trsfms.end(); ++it) - rejected.push_back(**it); + for (rej_it_map::const_iterator it = overlapping_trsfms.begin(); it != overlapping_trsfms.end(); ++it) + for (trsf_it::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) + rejected[it->first].push_back(**it2); else - for (std::set::const_iterator>::const_iterator it = nointersect_trsfms.begin(); - it != nointersect_trsfms.end(); ++it) - rejected.push_back(**it); + for (rej_it_map::const_iterator it = nointersect_trsfms.begin(); it != nointersect_trsfms.end(); ++it) + for (trsf_it::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) + rejected[it->first].push_back(**it2); this->Shape.setValue(support); if (!overlapping_trsfms.empty()) diff --git a/src/Mod/PartDesign/App/FeatureTransformed.h b/src/Mod/PartDesign/App/FeatureTransformed.h index fe077931d8d8..cd837f312aca 100644 --- a/src/Mod/PartDesign/App/FeatureTransformed.h +++ b/src/Mod/PartDesign/App/FeatureTransformed.h @@ -77,14 +77,15 @@ class PartDesignExport Transformed : public PartDesign::Feature /** returns a list of the transformations that where rejected during the last execute * because they did not ovelap with the support */ - const std::list getRejectedTransformations(void) { return rejected; } + typedef std::map > rejectedMap; + const rejectedMap getRejectedTransformations(void) { return rejected; } protected: void Restore(Base::XMLReader &reader); virtual void positionBySupport(void); TopoDS_Shape refineShapeIfActive(const TopoDS_Shape&) const; - std::list rejected; + rejectedMap rejected; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp index 7cb465735281..10f01c2a95b7 100644 --- a/src/Mod/PartDesign/Gui/ReferenceSelection.cpp +++ b/src/Mod/PartDesign/Gui/ReferenceSelection.cpp @@ -123,6 +123,9 @@ namespace PartDesignGui void getReferencedSelection(const App::DocumentObject* thisObj, const Gui::SelectionChanges& msg, App::DocumentObject*& selObj, std::vector& selSub) { + if (strcmp(thisObj->getDocument()->getName(), msg.pDocName) != 0) + return; + selObj = thisObj->getDocument()->getObject(msg.pObjectName); if (selObj == thisObj) return; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index 300c3f8cebb9..ad2c757852d5 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -68,7 +68,7 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(ViewProviderTransformed ui->buttonOK->hide(); ui->checkBoxUpdateView->setEnabled(true); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -87,11 +87,12 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(TaskMultiTransformParam layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -99,6 +100,14 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(TaskMultiTransformParam void TaskLinearPatternParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + updateViewTimer = new QTimer(this); updateViewTimer->setSingleShot(true); updateViewTimer->setInterval(getUpdateViewTimeout()); @@ -121,13 +130,10 @@ void TaskLinearPatternParameters::setupUI() std::vector originals = pcLinearPattern->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -196,7 +202,7 @@ void TaskLinearPatternParameters::updateUI() undefined = true; } - if (referenceSelectionMode) { + if (selectionMode == reference) { ui->comboDirection->addItem(tr("Select an edge/face or datum line/plane")); ui->comboDirection->setCurrentIndex(ui->comboDirection->count() - 1); } else if (undefined) { @@ -227,13 +233,14 @@ void TaskLinearPatternParameters::kickUpdateViewTimer() const void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { - - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) - return; - if (originalSelected(msg)) { - ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode) { + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + + exitSelectionMode(); + } else if (selectionMode == reference) { // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { @@ -266,6 +273,12 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges } } +void TaskLinearPatternParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskLinearPatternParameters::onCheckReverse(const bool on) { if (blockUpdate) return; @@ -339,7 +352,7 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { // enter reference selection mode hideObject(); showBase(); - referenceSelectionMode = true; + selectionMode = reference; Gui::Selection().clearSelection(); addReferenceSelectionGate(true, true); } @@ -368,6 +381,16 @@ void TaskLinearPatternParameters::onUpdateView(bool on) } } +void TaskLinearPatternParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskLinearPatternParameters::getDirection(App::DocumentObject*& obj, std::vector& sub) const { obj = getSketchObject(); diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig index 0a982a4a8b40..8357e5423591 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig @@ -32,6 +32,7 @@ #include "TaskLinearPatternParameters.h" #include "TaskMultiTransformParameters.h" #include "Workbench.h" +#include "ReferenceSelection.h" #include #include #include @@ -67,7 +68,7 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(ViewProviderTransformed ui->buttonOK->hide(); ui->checkBoxUpdateView->setEnabled(true); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -86,11 +87,12 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(TaskMultiTransformParam layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -98,6 +100,14 @@ TaskLinearPatternParameters::TaskLinearPatternParameters(TaskMultiTransformParam void TaskLinearPatternParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + updateViewTimer = new QTimer(this); updateViewTimer->setSingleShot(true); updateViewTimer->setInterval(getUpdateViewTimeout()); @@ -120,13 +130,17 @@ void TaskLinearPatternParameters::setupUI() std::vector originals = pcLinearPattern->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 if ((*i) != NULL) { // find the first valid original ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); break; } +======= + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Enable multiple originals for the transformed features } // --------------------- @@ -167,11 +181,7 @@ void TaskLinearPatternParameters::updateUI() for (int i=ui->comboDirection->count()-1; i >= 5; i--) ui->comboDirection->removeItem(i); for (int i=ui->comboDirection->count(); i < maxcount; i++) -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - ui->comboDirection->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); -======= - ui->comboDirection->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); ->>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboDirection->addItem(QString::fromLatin1("Sketch axis %1").arg(i-5)); bool undefined = false; if (directionFeature != NULL && !directions.empty()) { @@ -191,20 +201,15 @@ void TaskLinearPatternParameters::updateUI() ui->comboDirection->setCurrentIndex(pos); else undefined = true; -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - } else if (directionFeature != NULL && !directions.empty()) { - ui->comboDirection->addItem(QString::fromLatin1(directions.front().c_str())); -======= } else { ui->comboDirection->addItem(getRefStr(directionFeature, directions)); ->>>>>>> Allow datum lines and planes for Transformed features' references ui->comboDirection->setCurrentIndex(maxcount); } } else { undefined = true; } - if (referenceSelectionMode) { + if (selectionMode == reference) { ui->comboDirection->addItem(tr("Select an edge/face or datum line/plane")); ui->comboDirection->setCurrentIndex(ui->comboDirection->count() - 1); } else if (undefined) { @@ -235,31 +240,26 @@ void TaskLinearPatternParameters::kickUpdateViewTimer() const void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { - - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) - return; - if (originalSelected(msg)) { -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode && - ((subName.size() > 4 && subName.substr(0,4) == "Edge") || - (subName.size() > 4 && subName.substr(0,4) == "Face"))) { - - if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) - return; - -======= - ui->lineOriginal->setText(QString::fromAscii(msg.pObjectName)); } else if (referenceSelectionMode) { +======= + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + + exitSelectionMode(); + } else if (selectionMode == reference) { +>>>>>>> Enable multiple originals for the transformed features // Note: ReferenceSelection has already checked the selection for validity ->>>>>>> Allow datum lines and planes for Transformed features' references exitSelectionMode(); if (!blockUpdate) { std::vector directions; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, directions); PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + getReferencedSelection(pcLinearPattern, msg, selObj, directions); pcLinearPattern->Direction.setValue(selObj, directions); recomputeFeature(); @@ -273,14 +273,11 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges for (int i=ui->comboDirection->count()-1; i >= maxcount; i--) ui->comboDirection->removeItem(i); -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - ui->comboDirection->addItem(QString::fromLatin1(subName.c_str())); -======= std::vector directions; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, directions); + PartDesign::LinearPattern* pcLinearPattern = static_cast(getObject()); + getReferencedSelection(pcLinearPattern, msg, selObj, directions); ui->comboDirection->addItem(getRefStr(selObj, directions)); ->>>>>>> Allow datum lines and planes for Transformed features' references ui->comboDirection->setCurrentIndex(maxcount); ui->comboDirection->addItem(tr("Select reference...")); } @@ -288,6 +285,12 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges } } +void TaskLinearPatternParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskLinearPatternParameters::onCheckReverse(const bool on) { if (blockUpdate) return; @@ -355,12 +358,13 @@ void TaskLinearPatternParameters::onDirectionChanged(int num) { QString buf = QString::fromUtf8("Axis%1").arg(num-5); std::string str = buf.toStdString(); pcLinearPattern->Direction.setValue(pcSketch, std::vector(1,str)); + exitSelectionMode(); } else if (num == ui->comboDirection->count() - 1) { // enter reference selection mode hideObject(); - showOriginals(); - referenceSelectionMode = true; + showBase(); + selectionMode = reference; Gui::Selection().clearSelection(); addReferenceSelectionGate(true, true); } @@ -389,6 +393,16 @@ void TaskLinearPatternParameters::onUpdateView(bool on) } } +void TaskLinearPatternParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskLinearPatternParameters::getDirection(App::DocumentObject*& obj, std::vector& sub) const { obj = getSketchObject(); diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h index 5bf80e256ccb..ccf266feb0f1 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.h @@ -66,10 +66,12 @@ private Q_SLOTS: void onLength(const double l); void onOccurrences(const uint n); virtual void onUpdateView(bool); + virtual void onFeatureDeleted(void); protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + virtual void clearButtons(); void getDirection(App::DocumentObject*& obj, std::vector& sub) const; const bool getReverse(void) const; const double getLength(void) const; diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui index dff273eb8952..578aa266de4b 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.ui @@ -7,7 +7,7 @@ 0 0 266 - 402 + 333 @@ -15,19 +15,32 @@ - + - + - Original feature + Add feature + + + true - + + + Remove feature + + + true + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index 4812f2f9f784..e99932399099 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -65,7 +65,7 @@ TaskMirroredParameters::TaskMirroredParameters(ViewProviderTransformed *Transfor ui->buttonOK->hide(); ui->checkBoxUpdateView->setEnabled(true); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -84,11 +84,12 @@ TaskMirroredParameters::TaskMirroredParameters(TaskMultiTransformParameters *par layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -96,6 +97,14 @@ TaskMirroredParameters::TaskMirroredParameters(TaskMultiTransformParameters *par void TaskMirroredParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + connect(ui->comboPlane, SIGNAL(activated(int)), this, SLOT(onPlaneChanged(int))); connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), @@ -106,13 +115,10 @@ void TaskMirroredParameters::setupUI() std::vector originals = pcMirrored->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -168,7 +174,7 @@ void TaskMirroredParameters::updateUI() undefined = true; } - if (referenceSelectionMode) { + if (selectionMode == reference) { ui->comboPlane->addItem(tr("Select a face or datum plane")); ui->comboPlane->setCurrentIndex(ui->comboPlane->count() - 1); } else if (undefined) { @@ -184,12 +190,13 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg { if (msg.Type == Gui::SelectionChanges::AddSelection) { - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) - return; - if (originalSelected(msg)) { - ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode) { + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); + } else if (selectionMode == reference) { // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { @@ -222,6 +229,12 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg } } +void TaskMirroredParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskMirroredParameters::onPlaneChanged(int num) { if (blockUpdate) return; @@ -265,7 +278,7 @@ void TaskMirroredParameters::onPlaneChanged(int num) { // enter reference selection mode hideObject(); showBase(); - referenceSelectionMode = true; + selectionMode = reference; Gui::Selection().clearSelection(); addReferenceSelectionGate(false, true); } @@ -291,6 +304,16 @@ void TaskMirroredParameters::onUpdateView(bool on) } } +void TaskMirroredParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskMirroredParameters::getMirrorPlane(App::DocumentObject*& obj, std::vector& sub) const { obj = getSketchObject(); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig index c3ae4235c1ba..37fc6cf74414 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig @@ -31,6 +31,7 @@ #include "TaskMirroredParameters.h" #include "TaskMultiTransformParameters.h" #include "Workbench.h" +#include "ReferenceSelection.h" #include #include #include @@ -64,7 +65,7 @@ TaskMirroredParameters::TaskMirroredParameters(ViewProviderTransformed *Transfor ui->buttonOK->hide(); ui->checkBoxUpdateView->setEnabled(true); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -83,11 +84,12 @@ TaskMirroredParameters::TaskMirroredParameters(TaskMultiTransformParameters *par layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -95,6 +97,14 @@ TaskMirroredParameters::TaskMirroredParameters(TaskMultiTransformParameters *par void TaskMirroredParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + connect(ui->comboPlane, SIGNAL(activated(int)), this, SLOT(onPlaneChanged(int))); connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), @@ -105,13 +115,17 @@ void TaskMirroredParameters::setupUI() std::vector originals = pcMirrored->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 if ((*i) != NULL) { // find the first valid original ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); break; } +======= + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Enable multiple originals for the transformed features } // --------------------- @@ -139,11 +153,7 @@ void TaskMirroredParameters::updateUI() for (int i=ui->comboPlane->count()-1; i >= 5; i--) ui->comboPlane->removeItem(i); for (int i=ui->comboPlane->count(); i < maxcount; i++) -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - ui->comboPlane->addItem(QString::fromLatin1("Sketch axis %1").arg(i-2)); -======= - ui->comboPlane->addItem(QString::fromAscii("Sketch axis %1").arg(i-5)); ->>>>>>> Allow datum lines and planes for Transformed features' references + ui->comboPlane->addItem(QString::fromLatin1("Sketch axis %1").arg(i-5)); bool undefined = false; if (mirrorPlaneFeature != NULL && !mirrorPlanes.empty()) { @@ -163,21 +173,15 @@ void TaskMirroredParameters::updateUI() ui->comboPlane->setCurrentIndex(pos); else undefined = true; -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - } else if (mirrorPlaneFeature != NULL && !mirrorPlanes.empty()) { - ui->comboPlane->addItem(QString::fromLatin1(mirrorPlanes.front().c_str())); - ui->comboPlane->setCurrentIndex(maxcount); -======= } else { ui->comboPlane->addItem(getRefStr(mirrorPlaneFeature, mirrorPlanes)); ui->comboPlane->setCurrentIndex(maxcount); ->>>>>>> Allow datum lines and planes for Transformed features' references } } else { undefined = true; } - if (referenceSelectionMode) { + if (selectionMode == reference) { ui->comboPlane->addItem(tr("Select a face or datum plane")); ui->comboPlane->setCurrentIndex(ui->comboPlane->count() - 1); } else if (undefined) { @@ -193,29 +197,25 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg { if (msg.Type == Gui::SelectionChanges::AddSelection) { - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) - return; - if (originalSelected(msg)) { -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode && - (subName.size() > 4 && subName.substr(0,4) == "Face")) { - - if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) - return; - -======= - ui->lineOriginal->setText(QString::fromAscii(msg.pObjectName)); } else if (referenceSelectionMode) { +======= + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); + } else if (selectionMode == reference) { +>>>>>>> Enable multiple originals for the transformed features // Note: ReferenceSelection has already checked the selection for validity ->>>>>>> Allow datum lines and planes for Transformed features' references exitSelectionMode(); if (!blockUpdate) { std::vector mirrorPlanes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, mirrorPlanes); PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + getReferencedSelection(pcMirrored, msg, selObj, mirrorPlanes); pcMirrored->MirrorPlane.setValue(selObj, mirrorPlanes); recomputeFeature(); @@ -229,14 +229,11 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg for (int i=ui->comboPlane->count()-1; i >= maxcount; i--) ui->comboPlane->removeItem(i); -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - ui->comboPlane->addItem(QString::fromLatin1(subName.c_str())); -======= std::vector mirrorPlanes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, mirrorPlanes); + PartDesign::Mirrored* pcMirrored = static_cast(getObject()); + getReferencedSelection(pcMirrored, msg, selObj, mirrorPlanes); ui->comboPlane->addItem(getRefStr(selObj, mirrorPlanes)); ->>>>>>> Allow datum lines and planes for Transformed features' references ui->comboPlane->setCurrentIndex(maxcount); ui->comboPlane->addItem(tr("Select reference...")); } @@ -244,6 +241,12 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg } } +void TaskMirroredParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskMirroredParameters::onPlaneChanged(int num) { if (blockUpdate) return; @@ -281,12 +284,13 @@ void TaskMirroredParameters::onPlaneChanged(int num) { QString buf = QString::fromUtf8("Axis%1").arg(num-5); std::string str = buf.toStdString(); pcMirrored->MirrorPlane.setValue(pcSketch, std::vector(1,str)); + exitSelectionMode(); } else if (num == ui->comboPlane->count() - 1) { // enter reference selection mode hideObject(); - showOriginals(); - referenceSelectionMode = true; + showBase(); + selectionMode = reference; Gui::Selection().clearSelection(); addReferenceSelectionGate(false, true); } @@ -312,6 +316,16 @@ void TaskMirroredParameters::onUpdateView(bool on) } } +void TaskMirroredParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskMirroredParameters::getMirrorPlane(App::DocumentObject*& obj, std::vector& sub) const { obj = getSketchObject(); @@ -390,7 +404,7 @@ bool TaskDlgMirroredParameters::accept() std::vector mirrorPlanes; App::DocumentObject* obj; mirrorParameter->getMirrorPlane(obj, mirrorPlanes); - std::string mirrorPlane = mirrorParameter->getPythonStr(obj, mirrorPlanes); + std::string mirrorPlane = getPythonStr(obj, mirrorPlanes); if (!mirrorPlane.empty()) { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirrorPlane = %s", name.c_str(), mirrorPlane.c_str()); } else diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.h b/src/Mod/PartDesign/Gui/TaskMirroredParameters.h index fa56829ed971..a27a873fe734 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.h +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.h @@ -64,10 +64,12 @@ class TaskMirroredParameters : public TaskTransformedParameters private Q_SLOTS: void onPlaneChanged(int num); virtual void onUpdateView(bool); + virtual void onFeatureDeleted(void); protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + virtual void clearButtons(); private: void setupUI(); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui b/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui index 461ca5e07f8d..db0b364ceadf 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.ui @@ -6,8 +6,8 @@ 0 0 - 242 - 290 + 253 + 235 @@ -15,19 +15,32 @@ - + - + - Original feature + Add feature + + + true - + + + Remove feature + + + true + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp index ec818a961e2b..98a2f4635ddf 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp @@ -67,8 +67,16 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform QMetaObject::connectSlotsByName(this); this->groupLayout()->addWidget(proxy); + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + // Create a context menu for the listview of transformation features - QAction* action = new QAction(tr("Edit"), ui->listTransformFeatures); + action = new QAction(tr("Edit"), ui->listTransformFeatures); action->connect(action, SIGNAL(triggered()), this, SLOT(onTransformEdit())); ui->listTransformFeatures->addAction(action); @@ -131,13 +139,10 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform std::vector originals = pcMultiTransform->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); // This is never enabled since it is for optical feed-back only for (std::vector::const_iterator i = originals.begin(); i != originals.end(); i++) { - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- } @@ -145,11 +150,30 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform void TaskMultiTransformParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (originalSelected(msg)) { - App::DocumentObject* selectedObject = TransformedView->getObject()->getDocument()->getActiveObject(); - ui->lineOriginal->setText(QString::fromLatin1(selectedObject->getNameInDocument())); + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); } } +void TaskMultiTransformParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + +void TaskMultiTransformParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskMultiTransformParameters::closeSubTask() { if (subTask) { diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig new file mode 100644 index 000000000000..ba9a802e0275 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig @@ -0,0 +1,512 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +#endif + +#include "ui_TaskMultiTransformParameters.h" +#include "TaskMultiTransformParameters.h" +#include "TaskMirroredParameters.h" +#include "TaskLinearPatternParameters.h" +#include "TaskPolarPatternParameters.h" +#include "TaskScaledParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskMultiTransformParameters */ + +TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransformed *TransformedView,QWidget *parent) + : TaskTransformedParameters(TransformedView, parent), subTask(NULL) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskMultiTransformParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + this->groupLayout()->addWidget(proxy); + + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + + // Create a context menu for the listview of transformation features + action = new QAction(tr("Edit"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onTransformEdit())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Delete"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onTransformDelete())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Add mirrored transformation"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onTransformAddMirrored())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Add linear pattern"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onTransformAddLinearPattern())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Add polar pattern"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onTransformAddPolarPattern())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Add scaled transformation"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onTransformAddScaled())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Move up"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onMoveUp())); + ui->listTransformFeatures->addAction(action); + action = new QAction(tr("Move down"), ui->listTransformFeatures); + action->connect(action, SIGNAL(triggered()), + this, SLOT(onMoveDown())); + ui->listTransformFeatures->addAction(action); + ui->listTransformFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + connect(ui->listTransformFeatures, SIGNAL(activated(QModelIndex)), + this, SLOT(onTransformActivated(QModelIndex))); + + // Get the transformFeatures data + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); + + // Fill data into dialog elements + ui->listTransformFeatures->setEnabled(true); + ui->listTransformFeatures->clear(); + for (std::vector::const_iterator i = transformFeatures.begin(); i != transformFeatures.end(); i++) + { + if ((*i) != NULL) + ui->listTransformFeatures->addItem(QString::fromLatin1((*i)->Label.getValue())); + } + if (transformFeatures.size() > 0) { + ui->listTransformFeatures->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); + editHint = false; + } else { + ui->listTransformFeatures->addItem(tr("Right-click to add")); + editHint = true; + } + + // Get the Originals data + std::vector originals = pcMultiTransform->Originals.getValues(); + + // Fill data into dialog elements + for (std::vector::const_iterator i = originals.begin(); i != originals.end(); i++) + { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 + if ((*i) != NULL) { // find the first valid original + ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); + break; + } +======= + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Enable multiple originals for the transformed features + } + // --------------------- +} + +void TaskMultiTransformParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (originalSelected(msg)) { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 + App::DocumentObject* selectedObject = TransformedView->getObject()->getDocument()->getActiveObject(); + ui->lineOriginal->setText(QString::fromLatin1(selectedObject->getNameInDocument())); +======= + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); +>>>>>>> Enable multiple originals for the transformed features + } +} + +void TaskMultiTransformParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + +void TaskMultiTransformParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + +void TaskMultiTransformParameters::closeSubTask() +{ + if (subTask) { + exitSelectionMode(); + disconnect(ui->checkBoxUpdateView, 0, subTask, 0); + delete subTask; + subTask = NULL; + } +} + +void TaskMultiTransformParameters::onTransformDelete() +{ + if (editHint) return; // Can't delete the hint... + int row = ui->listTransformFeatures->currentIndex().row(); + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); + + App::DocumentObject* feature = transformFeatures[row]; + pcMultiTransform->getDocument()->remObject(feature->getNameInDocument()); + closeSubTask(); + + transformFeatures.erase(transformFeatures.begin() + row); + pcMultiTransform->Transformations.setValues(transformFeatures); + // Note: When the last transformation is deleted, recomputeFeature does nothing, because Transformed::execute() + // says: "No transformations defined, exit silently" + recomputeFeature(); + + ui->listTransformFeatures->model()->removeRow(row); + ui->listTransformFeatures->setCurrentRow(0, QItemSelectionModel::ClearAndSelect); +} + +void TaskMultiTransformParameters::onTransformEdit() +{ + if (editHint) return; // Can't edit the hint... + closeSubTask(); // For example if user is editing one subTask and then double-clicks on another without OK'ing first + ui->listTransformFeatures->currentItem()->setSelected(true); + int row = ui->listTransformFeatures->currentIndex().row(); + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); + + subFeature = static_cast(transformFeatures[row]); + if (transformFeatures[row]->getTypeId() == PartDesign::Mirrored::getClassTypeId()) + subTask = new TaskMirroredParameters(this, ui->verticalLayout); + else if (transformFeatures[row]->getTypeId() == PartDesign::LinearPattern::getClassTypeId()) + subTask = new TaskLinearPatternParameters(this, ui->verticalLayout); + else if (transformFeatures[row]->getTypeId() == PartDesign::PolarPattern::getClassTypeId()) + subTask = new TaskPolarPatternParameters(this, ui->verticalLayout); + else if (transformFeatures[row]->getTypeId() == PartDesign::Scaled::getClassTypeId()) + subTask = new TaskScaledParameters(this, ui->verticalLayout); + else + return; // TODO: Show an error? + + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + subTask, SLOT(onUpdateView(bool))); +} + +void TaskMultiTransformParameters::onTransformActivated(const QModelIndex& index) { + onTransformEdit(); +} + +void TaskMultiTransformParameters::onTransformAddMirrored() +{ + closeSubTask(); + std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("Mirrored"); + + Gui::Command::openCommand("Mirrored"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject(\"PartDesign::Mirrored\",\"%s\")",newFeatName.c_str()); + //Gui::Command::updateActive(); + App::DocumentObject* sketch = getSketchObject(); + if (sketch) + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.MirrorPlane = (App.activeDocument().%s, [\"V_Axis\"])", + newFeatName.c_str(), sketch->getNameInDocument()); + + finishAdd(newFeatName); +} + +void TaskMultiTransformParameters::onTransformAddLinearPattern() +{ + closeSubTask(); + std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("LinearPattern"); + + Gui::Command::openCommand("LinearPattern"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject(\"PartDesign::LinearPattern\",\"%s\")",newFeatName.c_str()); + //Gui::Command::updateActive(); + App::DocumentObject* sketch = getSketchObject(); + if (sketch) + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Direction = (App.activeDocument().%s, [\"H_Axis\"])", + newFeatName.c_str(), sketch->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Length = 100", newFeatName.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Occurrences = 2", newFeatName.c_str()); + + finishAdd(newFeatName); +} + +void TaskMultiTransformParameters::onTransformAddPolarPattern() +{ + closeSubTask(); + std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("PolarPattern"); + + Gui::Command::openCommand("PolarPattern"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject(\"PartDesign::PolarPattern\",\"%s\")",newFeatName.c_str()); + //Gui::Command::updateActive(); + App::DocumentObject* sketch = getSketchObject(); + if (sketch) + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Axis = (App.activeDocument().%s, [\"N_Axis\"])", + newFeatName.c_str(), sketch->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 360", newFeatName.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Occurrences = 2", newFeatName.c_str()); + + finishAdd(newFeatName); +} + +void TaskMultiTransformParameters::onTransformAddScaled() +{ + closeSubTask(); + std::string newFeatName = TransformedView->getObject()->getDocument()->getUniqueObjectName("Scaled"); + + Gui::Command::openCommand("Scaled"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject(\"PartDesign::Scaled\",\"%s\")",newFeatName.c_str()); + //Gui::Command::updateActive(); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Factor = 2", newFeatName.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Occurrences = 2", newFeatName.c_str()); + + finishAdd(newFeatName); +} + +void TaskMultiTransformParameters::finishAdd(std::string &newFeatName) +{ + //Gui::Command::updateActive(); + //Gui::Command::copyVisual(newFeatName.c_str(), "ShapeColor", getOriginals().front()->getNameInDocument().c_str()); + //Gui::Command::copyVisual(newFeatName.c_str(), "DisplayMode", getOriginals().front()->getNameInDocument().c_str()); + + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + if (editHint) { + // Remove hint, first feature is being added + ui->listTransformFeatures->model()->removeRow(0); + } + int row = ui->listTransformFeatures->currentIndex().row(); + if (row < 0) { + // Happens when first row (first transformation) is created + // Hide all the originals now (hiding them in Command.cpp presents the user with an empty screen!) + hideBase(); + } + + // Insert new transformation after the selected row + // This means that in order to insert at the beginning, the user has to use "Move Up" in the menu + App::DocumentObject* newFeature = pcMultiTransform->getDocument()->getObject(newFeatName.c_str()); + std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); + if (row == ui->listTransformFeatures->model()->rowCount() - 1) { + // Note: Inserts always happen before the specified iterator so in order to append at the + // end we need to use push_back() and append() + transformFeatures.push_back(newFeature); + ui->listTransformFeatures->addItem(QString::fromLatin1(newFeature->Label.getValue())); + ui->listTransformFeatures->setCurrentRow(row+1, QItemSelectionModel::ClearAndSelect); + } else { + // Note: The feature tree always seems to append to the end, no matter what we say here + transformFeatures.insert(transformFeatures.begin() + row + 1, newFeature); + ui->listTransformFeatures->insertItem(row + 1, QString::fromLatin1(newFeature->Label.getValue())); + ui->listTransformFeatures->setCurrentRow(row + 1, QItemSelectionModel::ClearAndSelect); + } + pcMultiTransform->Transformations.setValues(transformFeatures); + + recomputeFeature(); + + // Set state to hidden - only the MultiTransform should be visible + Gui::Command::doCommand( + Gui::Command::Doc,"Gui.activeDocument().getObject(\"%s\").Visibility=False", newFeatName.c_str()); + editHint = false; + + onTransformEdit(); +} + +void TaskMultiTransformParameters::moveTransformFeature(const int increment) +{ + int row = ui->listTransformFeatures->currentIndex().row(); + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); + + App::DocumentObject* feature = transformFeatures[row]; + transformFeatures.erase(transformFeatures.begin() + row); + QListWidgetItem* item = new QListWidgetItem(*(ui->listTransformFeatures->item(row))); + ui->listTransformFeatures->model()->removeRow(row); + // After this operation, if we were to insert at index row again, things will remain unchanged + + row += increment; + + if (row < 0) + row = 0; + + if (row >= ui->listTransformFeatures->model()->rowCount()) { + // Note: Inserts always happen before the specified iterator so in order to append at the + // end we need to use push_back() and append() + transformFeatures.push_back(feature); + ui->listTransformFeatures->addItem(item); + ui->listTransformFeatures->setCurrentRow(row, QItemSelectionModel::ClearAndSelect); + } else { + transformFeatures.insert(transformFeatures.begin() + row, feature); + ui->listTransformFeatures->insertItem(row, item); + ui->listTransformFeatures->setCurrentRow(row, QItemSelectionModel::ClearAndSelect); + } + + pcMultiTransform->Transformations.setValues(transformFeatures); + recomputeFeature(); +} + +void TaskMultiTransformParameters::onMoveUp() +{ + moveTransformFeature(-1); +} + +void TaskMultiTransformParameters::onMoveDown() +{ + moveTransformFeature(+1); +} + +void TaskMultiTransformParameters::onSubTaskButtonOK() { + closeSubTask(); +} + +void TaskMultiTransformParameters::onUpdateView(bool on) +{ + blockUpdate = !on; + if (on) + recomputeFeature(); +} + +const std::vector TaskMultiTransformParameters::getTransformFeatures(void) const +{ + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + return pcMultiTransform->Transformations.getValues(); +} + +void TaskMultiTransformParameters::apply() +{ +} + +TaskMultiTransformParameters::~TaskMultiTransformParameters() +{ + closeSubTask(); + delete ui; + if (proxy) + delete proxy; +} + +void TaskMultiTransformParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgMultiTransformParameters::TaskDlgMultiTransformParameters(ViewProviderMultiTransform *MultiTransformView) + : TaskDlgTransformedParameters(MultiTransformView) +{ + parameter = new TaskMultiTransformParameters(MultiTransformView); + + Content.push_back(parameter); +} +//==== calls from the TaskView =============================================================== + +bool TaskDlgMultiTransformParameters::accept() +{ + std::string name = TransformedView->getObject()->getNameInDocument(); + + try { + //Gui::Command::openCommand("MultiTransform changed"); + // Handle Originals + if (!TaskDlgTransformedParameters::accept()) + return false; + + TaskMultiTransformParameters* mtParameter = static_cast(parameter); + std::vector transformFeatures = mtParameter->getTransformFeatures(); + std::stringstream str; + str << "App.ActiveDocument." << name.c_str() << ".Transformations = ["; + for (std::vector::const_iterator it = transformFeatures.begin(); it != transformFeatures.end(); it++) + { + if ((*it) != NULL) + str << "App.ActiveDocument." << (*it)->getNameInDocument() << ","; + } + str << "]"; + Gui::Command::runCommand(Gui::Command::Doc,str.str().c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!TransformedView->getObject()->isValid()) + throw Base::Exception(TransformedView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return true; +} + +bool TaskDlgMultiTransformParameters::reject() +{ + // Get objects before view is invalidated + // For the same reason we can't delegate showing the originals to TaskDlgTransformedParameters::reject() + PartDesign::MultiTransform* pcMultiTransform = static_cast(TransformedView->getObject()); + std::vector transformFeatures = pcMultiTransform->Transformations.getValues(); + + // Delete the transformation features - must happen before abortCommand()! + for (std::vector::const_iterator it = transformFeatures.begin(); it != transformFeatures.end(); ++it) + { + if ((*it) != NULL) + Gui::Command::doCommand( + Gui::Command::Doc,"App.ActiveDocument.removeObject(\"%s\")", (*it)->getNameInDocument()); + } + + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + return TaskDlgTransformedParameters::reject(); +} + +#include "moc_TaskMultiTransformParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.h b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.h index 4b13176585b8..e9a2564981ae 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.h +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.h @@ -80,10 +80,12 @@ private Q_SLOTS: // Note: There is no Cancel button because I couldn't work out how to save the state of // a subFeature so as to revert the changes of an edit operation virtual void onUpdateView(bool); + virtual void onFeatureDeleted(void); protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + virtual void clearButtons(); private: void updateUI(); diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.ui b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.ui index ad44059e696a..026986173902 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.ui @@ -6,8 +6,8 @@ 0 0 - 225 - 182 + 256 + 266 @@ -15,21 +15,34 @@ - + - + - Original feature + Add feature + + + true - + + + Remove feature + + + true + + - + + + + Transformations diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index bb0591a21370..16faa793d097 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -67,7 +67,7 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(ViewProviderTransformed * ui->buttonOK->hide(); ui->checkBoxUpdateView->setEnabled(true); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -86,11 +86,12 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(TaskMultiTransformParamet layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -98,6 +99,14 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(TaskMultiTransformParamet void TaskPolarPatternParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + updateViewTimer = new QTimer(this); updateViewTimer->setSingleShot(true); updateViewTimer->setInterval(getUpdateViewTimeout()); @@ -120,13 +129,10 @@ void TaskPolarPatternParameters::setupUI() std::vector originals = pcPolarPattern->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -169,7 +175,7 @@ void TaskPolarPatternParameters::updateUI() // Error message? } - if (referenceSelectionMode) { + if (selectionMode == reference) { ui->comboAxis->addItem(tr("Select an edge or datum line")); ui->comboAxis->setCurrentIndex(ui->comboAxis->count() - 1); } else @@ -198,12 +204,13 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& { if (msg.Type == Gui::SelectionChanges::AddSelection) { - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) - return; - if (originalSelected(msg)) { - ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode) { + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); + } else if (selectionMode == reference) { // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { @@ -232,6 +239,12 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& } } +void TaskPolarPatternParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskPolarPatternParameters::onCheckReverse(const bool on) { if (blockUpdate) return; @@ -275,7 +288,7 @@ void TaskPolarPatternParameters::onAxisChanged(int num) { // enter reference selection mode hideObject(); showBase(); - referenceSelectionMode = true; + selectionMode = reference; Gui::Selection().clearSelection(); addReferenceSelectionGate(true, false); } @@ -304,6 +317,16 @@ void TaskPolarPatternParameters::onUpdateView(bool on) } } +void TaskPolarPatternParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskPolarPatternParameters::getAxis(App::DocumentObject*& obj, std::vector& sub) const { obj = getSketchObject(); diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig index 085ed2d81c4c..5ab4878fce73 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig @@ -32,6 +32,7 @@ #include "TaskPolarPatternParameters.h" #include "TaskMultiTransformParameters.h" #include "Workbench.h" +#include "ReferenceSelection.h" #include #include #include @@ -66,7 +67,7 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(ViewProviderTransformed * ui->buttonOK->hide(); ui->checkBoxUpdateView->setEnabled(true); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -85,11 +86,12 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(TaskMultiTransformParamet layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); - referenceSelectionMode = false; + selectionMode = none; blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! setupUI(); @@ -97,6 +99,14 @@ TaskPolarPatternParameters::TaskPolarPatternParameters(TaskMultiTransformParamet void TaskPolarPatternParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + updateViewTimer = new QTimer(this); updateViewTimer->setSingleShot(true); updateViewTimer->setInterval(getUpdateViewTimeout()); @@ -119,13 +129,17 @@ void TaskPolarPatternParameters::setupUI() std::vector originals = pcPolarPattern->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 if ((*i) != NULL) { // find the first valid original ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); break; } +======= + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Enable multiple originals for the transformed features } // --------------------- @@ -160,20 +174,15 @@ void TaskPolarPatternParameters::updateUI() if (axisFeature != NULL && !axes.empty()) { if (axes.front() == "N_Axis") ui->comboAxis->setCurrentIndex(0); -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - else if (axisFeature != NULL && !axes.empty()) { - ui->comboAxis->addItem(QString::fromLatin1(axes.front().c_str())); -======= else { ui->comboAxis->addItem(getRefStr(axisFeature, axes)); ->>>>>>> Allow datum lines and planes for Transformed features' references ui->comboAxis->setCurrentIndex(1); } } else { // Error message? } - if (referenceSelectionMode) { + if (selectionMode == reference) { ui->comboAxis->addItem(tr("Select an edge or datum line")); ui->comboAxis->setCurrentIndex(ui->comboAxis->count() - 1); } else @@ -202,29 +211,25 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& { if (msg.Type == Gui::SelectionChanges::AddSelection) { - if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) - return; - if (originalSelected(msg)) { -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode && - (subName.size() > 4 && subName.substr(0,4) == "Edge")) { - - if (strcmp(msg.pObjectName, getSupportObject()->getNameInDocument()) != 0) - return; - -======= - ui->lineOriginal->setText(QString::fromAscii(msg.pObjectName)); } else if (referenceSelectionMode) { +======= + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); + } else if (selectionMode == reference) { +>>>>>>> Enable multiple originals for the transformed features // Note: ReferenceSelection has already checked the selection for validity ->>>>>>> Allow datum lines and planes for Transformed features' references exitSelectionMode(); if (!blockUpdate) { std::vector axes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, axes); PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + getReferencedSelection(pcPolarPattern, msg, selObj, axes); pcPolarPattern->Axis.setValue(selObj, axes); recomputeFeature(); @@ -234,14 +239,11 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& for (int i=ui->comboAxis->count()-1; i >= 1; i--) ui->comboAxis->removeItem(i); -<<<<<<< 9c07d220e78d49c084d7ec2cec90f1df0572e044 - ui->comboAxis->addItem(QString::fromLatin1(subName.c_str())); -======= std::vector axes; App::DocumentObject* selObj; - getReferencedSelection(msg, selObj, axes); + PartDesign::PolarPattern* pcPolarPattern = static_cast(getObject()); + getReferencedSelection(pcPolarPattern, msg, selObj, axes); ui->comboAxis->addItem(getRefStr(selObj, axes)); ->>>>>>> Allow datum lines and planes for Transformed features' references ui->comboAxis->setCurrentIndex(1); ui->comboAxis->addItem(tr("Select reference...")); } @@ -249,6 +251,12 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& } } +void TaskPolarPatternParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskPolarPatternParameters::onCheckReverse(const bool on) { if (blockUpdate) return; @@ -291,8 +299,8 @@ void TaskPolarPatternParameters::onAxisChanged(int num) { else if (num == ui->comboAxis->count() - 1) { // enter reference selection mode hideObject(); - showOriginals(); - referenceSelectionMode = true; + showBase(); + selectionMode = reference; Gui::Selection().clearSelection(); addReferenceSelectionGate(true, false); } @@ -321,6 +329,16 @@ void TaskPolarPatternParameters::onUpdateView(bool on) } } +void TaskPolarPatternParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + void TaskPolarPatternParameters::getAxis(App::DocumentObject*& obj, std::vector& sub) const { obj = getSketchObject(); diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h index 531105cbb211..90a5ca16db81 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.h @@ -65,10 +65,12 @@ private Q_SLOTS: void onAngle(const double a); void onOccurrences(const uint n); virtual void onUpdateView(bool); + virtual void onFeatureDeleted(void); protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + virtual void clearButtons(); void getAxis(App::DocumentObject*& obj, std::vector& sub) const; const std::string getStdAxis(void) const; //const std::string getAxis(void) const; diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui index 8257825db684..651ec335fe08 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.ui @@ -6,8 +6,8 @@ 0 0 - 225 - 400 + 253 + 333 @@ -15,19 +15,32 @@ - + - + - Original feature + Add feature + + + true - + + + Remove feature + + + true + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp index ec2a5865809e..fd5995794e58 100644 --- a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp @@ -80,8 +80,9 @@ TaskScaledParameters::TaskScaledParameters(TaskMultiTransformParameters *parentT layout->addWidget(proxy); ui->buttonOK->setEnabled(true); - ui->labelOriginal->hide(); - ui->lineOriginal->hide(); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); ui->checkBoxUpdateView->hide(); blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! @@ -90,6 +91,14 @@ TaskScaledParameters::TaskScaledParameters(TaskMultiTransformParameters *parentT void TaskScaledParameters::setupUI() { + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + connect(ui->spinFactor, SIGNAL(valueChanged(double)), this, SLOT(onFactor(double))); connect(ui->spinOccurrences, SIGNAL(valueChanged(uint)), @@ -102,13 +111,10 @@ void TaskScaledParameters::setupUI() std::vector originals = pcScaled->Originals.getValues(); // Fill data into dialog elements - ui->lineOriginal->setEnabled(false); for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -142,11 +148,20 @@ void TaskScaledParameters::updateUI() void TaskScaledParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (originalSelected(msg)) { - App::DocumentObject* selectedObject = TransformedView->getObject()->getDocument()->getActiveObject(); - ui->lineOriginal->setText(QString::fromLatin1(selectedObject->getNameInDocument())); + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); } } +void TaskScaledParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + void TaskScaledParameters::onFactor(const double f) { if (blockUpdate) @@ -177,6 +192,16 @@ void TaskScaledParameters::onUpdateView(bool on) } } +void TaskScaledParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + const double TaskScaledParameters::getFactor(void) const { return ui->spinFactor->value().getValue(); diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig new file mode 100644 index 000000000000..5729ca98d105 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig @@ -0,0 +1,287 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +#endif + +#include "ui_TaskScaledParameters.h" +#include "TaskScaledParameters.h" +#include "TaskMultiTransformParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskScaledParameters */ + +TaskScaledParameters::TaskScaledParameters(ViewProviderTransformed *TransformedView,QWidget *parent) + : TaskTransformedParameters(TransformedView, parent) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskScaledParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + this->groupLayout()->addWidget(proxy); + + ui->buttonOK->hide(); + ui->checkBoxUpdateView->setEnabled(true); + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +TaskScaledParameters::TaskScaledParameters(TaskMultiTransformParameters *parentTask, QLayout *layout) + : TaskTransformedParameters(parentTask) +{ + proxy = new QWidget(parentTask); + ui = new Ui_TaskScaledParameters(); + ui->setupUi(proxy); + connect(ui->buttonOK, SIGNAL(pressed()), + parentTask, SLOT(onSubTaskButtonOK())); + QMetaObject::connectSlotsByName(this); + + layout->addWidget(proxy); + + ui->buttonOK->setEnabled(true); + ui->buttonAddFeature->hide(); + ui->buttonRemoveFeature->hide(); + ui->listWidgetFeatures->hide(); + ui->checkBoxUpdateView->hide(); + + blockUpdate = false; // Hack, sometimes it is NOT false although set to false in Transformed::Transformed()!! + setupUI(); +} + +void TaskScaledParameters::setupUI() +{ + connect(ui->buttonAddFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonAddFeature(bool))); + connect(ui->buttonRemoveFeature, SIGNAL(toggled(bool)), this, SLOT(onButtonRemoveFeature(bool))); + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetFeatures->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onFeatureDeleted())); + ui->listWidgetFeatures->setContextMenuPolicy(Qt::ActionsContextMenu); + + connect(ui->spinFactor, SIGNAL(valueChanged(double)), + this, SLOT(onFactor(double))); + connect(ui->spinOccurrences, SIGNAL(valueChanged(uint)), + this, SLOT(onOccurrences(uint))); + connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)), + this, SLOT(onUpdateView(bool))); + + // Get the feature data + PartDesign::Scaled* pcScaled = static_cast(getObject()); + std::vector originals = pcScaled->Originals.getValues(); + + // Fill data into dialog elements + for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) + { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 + if ((*i) != NULL) { // find the first valid original + ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); + break; + } +======= + if ((*i) != NULL) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Enable multiple originals for the transformed features + } + // --------------------- + + ui->spinFactor->bind(pcScaled->Factor); + ui->spinOccurrences->setMaximum(INT_MAX); + ui->spinOccurrences->bind(pcScaled->Occurrences); + ui->spinFactor->setEnabled(true); + ui->spinOccurrences->setEnabled(true); + //ui->spinFactor->setDecimals(Base::UnitsApi::getDecimals()); + + updateUI(); +} + +void TaskScaledParameters::updateUI() +{ + if (blockUpdate) + return; + blockUpdate = true; + + PartDesign::Scaled* pcScaled = static_cast(getObject()); + + double factor = pcScaled->Factor.getValue(); + unsigned occurrences = pcScaled->Occurrences.getValue(); + + ui->spinFactor->setValue(factor); + ui->spinOccurrences->setValue(occurrences); + + blockUpdate = false; +} + +void TaskScaledParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (originalSelected(msg)) { +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 + App::DocumentObject* selectedObject = TransformedView->getObject()->getDocument()->getActiveObject(); + ui->lineOriginal->setText(QString::fromLatin1(selectedObject->getNameInDocument())); +======= + if (selectionMode == addFeature) + ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); + else + removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); + exitSelectionMode(); +>>>>>>> Enable multiple originals for the transformed features + } +} + +void TaskScaledParameters::clearButtons() +{ + ui->buttonAddFeature->setChecked(false); + ui->buttonRemoveFeature->setChecked(false); +} + +void TaskScaledParameters::onFactor(const double f) +{ + if (blockUpdate) + return; + PartDesign::Scaled* pcScaled = static_cast(getObject()); + pcScaled->Factor.setValue(f); + recomputeFeature(); +} + +void TaskScaledParameters::onOccurrences(const uint n) +{ + if (blockUpdate) + return; + PartDesign::Scaled* pcScaled = static_cast(getObject()); + pcScaled->Occurrences.setValue(n); + recomputeFeature(); +} + +void TaskScaledParameters::onUpdateView(bool on) +{ + blockUpdate = !on; + if (on) { + // Do the same like in TaskDlgScaledParameters::accept() but without doCommand + PartDesign::Scaled* pcScaled = static_cast(getObject()); + pcScaled->Factor.setValue(getFactor()); + pcScaled->Occurrences.setValue(getOccurrences()); + recomputeFeature(); + } +} + +void TaskScaledParameters::onFeatureDeleted(void) +{ + PartDesign::Transformed* pcTransformed = getObject(); + std::vector originals = pcTransformed->Originals.getValues(); + originals.erase(originals.begin() + ui->listWidgetFeatures->currentRow()); + pcTransformed->Originals.setValues(originals); + ui->listWidgetFeatures->model()->removeRow(ui->listWidgetFeatures->currentRow()); + recomputeFeature(); +} + +const double TaskScaledParameters::getFactor(void) const +{ + return ui->spinFactor->value().getValue(); +} + +const unsigned TaskScaledParameters::getOccurrences(void) const +{ + return ui->spinOccurrences->value(); +} + +TaskScaledParameters::~TaskScaledParameters() +{ + delete ui; + if (proxy) + delete proxy; +} + +void TaskScaledParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + +void TaskScaledParameters::apply() +{ + std::string name = TransformedView->getObject()->getNameInDocument(); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Factor = %f",name.c_str(), getFactor()); + ui->spinOccurrences->apply(); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + if (!TransformedView->getObject()->isValid()) + throw Base::Exception(TransformedView->getObject()->getStatusString()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgScaledParameters::TaskDlgScaledParameters(ViewProviderScaled *ScaledView) + : TaskDlgTransformedParameters(ScaledView) +{ + parameter = new TaskScaledParameters(ScaledView); + + Content.push_back(parameter); +} +//==== calls from the TaskView =============================================================== + +bool TaskDlgScaledParameters::accept() +{ + try { + //Gui::Command::openCommand("Scaled changed"); + // Handle Originals + if (!TaskDlgTransformedParameters::accept()) + return false; + + parameter->apply(); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } + + return true; +} + +#include "moc_TaskScaledParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.h b/src/Mod/PartDesign/Gui/TaskScaledParameters.h index f591fde90d4d..df8e763a12d7 100644 --- a/src/Mod/PartDesign/Gui/TaskScaledParameters.h +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.h @@ -62,10 +62,12 @@ private Q_SLOTS: void onFactor(const double f); void onOccurrences(const uint n); virtual void onUpdateView(bool); + virtual void onFeatureDeleted(void); protected: virtual void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + virtual void clearButtons(); const double getFactor(void) const; const unsigned getOccurrences(void) const; diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.ui b/src/Mod/PartDesign/Gui/TaskScaledParameters.ui index e8182a7b60bb..14c622c3456d 100644 --- a/src/Mod/PartDesign/Gui/TaskScaledParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.ui @@ -6,8 +6,8 @@ 0 0 - 225 - 305 + 253 + 270 @@ -15,19 +15,32 @@ - + - + - Original feature + Add feature + + + true - + + + Remove feature + + + true + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp index 3cd7331bd16b..803266391461 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.cpp @@ -24,6 +24,7 @@ #ifndef _PreComp_ # include +# include # include # include # include @@ -64,7 +65,7 @@ TaskTransformedParameters::TaskTransformedParameters(ViewProviderTransformed *Tr insideMultiTransform(false), blockUpdate(false) { - originalSelectionMode = false; + selectionMode = none; } TaskTransformedParameters::TaskTransformedParameters(TaskMultiTransformParameters *parentTask) @@ -75,7 +76,7 @@ TaskTransformedParameters::TaskTransformedParameters(TaskMultiTransformParameter blockUpdate(false) { // Original feature selection makes no sense inside a MultiTransform - originalSelectionMode = false; + selectionMode = none; } TaskTransformedParameters::~TaskTransformedParameters() @@ -96,9 +97,10 @@ int TaskTransformedParameters::getUpdateViewTimeout() const const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChanges& msg) { - if (msg.Type == Gui::SelectionChanges::AddSelection && originalSelectionMode) { + if (msg.Type == Gui::SelectionChanges::AddSelection && ( + (selectionMode == addFeature) || (selectionMode == removeFeature))) { - if ((msg.pDocName, getObject()->getDocument()->getName()) != 0) + if (strcmp(msg.pDocName, getObject()->getDocument()->getName()) != 0) return false; PartDesign::Transformed* pcTransformed = getObject(); @@ -107,11 +109,22 @@ const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChang selectedObject->isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { // Do the same like in TaskDlgTransformedParameters::accept() but without doCommand - std::vector originals(1,selectedObject); + std::vector originals = pcTransformed->Originals.getValues(); + std::vector::iterator o = std::find(originals.begin(), originals.end(), selectedObject); + if (selectionMode == addFeature) { + if (o == originals.end()) + originals.push_back(selectedObject); + else + return false; // duplicate selection + } else { + if (o != originals.end()) + originals.erase(o); + else + return false; + } pcTransformed->Originals.setValues(originals); recomputeFeature(); - originalSelectionMode = false; return true; } } @@ -119,6 +132,41 @@ const bool TaskTransformedParameters::originalSelected(const Gui::SelectionChang return false; } +void TaskTransformedParameters::onButtonAddFeature(bool checked) +{ + if (checked) { + hideObject(); + showBase(); + selectionMode = addFeature; + Gui::Selection().clearSelection(); + } else { + exitSelectionMode(); + } +} + +void TaskTransformedParameters::onButtonRemoveFeature(bool checked) +{ + if (checked) { + hideObject(); + showBase(); + selectionMode = removeFeature; + Gui::Selection().clearSelection(); + } else { + exitSelectionMode(); + } +} + +void TaskTransformedParameters::removeItemFromListWidget(QListWidget* widget, const char* itemstr) +{ + QList items = widget->findItems(QString::fromAscii(itemstr), Qt::MatchExactly); + if (!items.empty()) { + for (QList::const_iterator i = items.begin(); i != items.end(); i++) { + QListWidgetItem* it = widget->takeItem(widget->row(*i)); + delete it; + } + } +} + PartDesign::Transformed *TaskTransformedParameters::getObject() const { @@ -228,8 +276,8 @@ void TaskTransformedParameters::showBase() void TaskTransformedParameters::exitSelectionMode() { - originalSelectionMode = false; - referenceSelectionMode = false; + clearButtons(); + selectionMode = none; Gui::Selection().rmvSelectionGate(); showObject(); hideBase(); diff --git a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h index cbb9d93b6df3..e4170064f573 100644 --- a/src/Mod/PartDesign/Gui/TaskTransformedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskTransformedParameters.h @@ -31,6 +31,8 @@ #include "TaskTransformedMessages.h" #include "ViewProviderTransformed.h" +class QListWidget; + namespace PartDesign { class Transformed; } @@ -71,6 +73,9 @@ class TaskTransformedParameters : public Gui::TaskView::TaskBox, public Gui::Sel protected Q_SLOTS: /// Connect the subTask OK button to the MultiTransform task virtual void onSubTaskButtonOK() {} + void onButtonAddFeature(const bool checked); + void onButtonRemoveFeature(const bool checked); + virtual void onFeatureDeleted(void)=0; protected: const bool originalSelected(const Gui::SelectionChanges& msg); @@ -94,13 +99,15 @@ protected Q_SLOTS: protected: virtual void changeEvent(QEvent *e) = 0; virtual void onSelectionChanged(const Gui::SelectionChanges& msg) = 0; + virtual void clearButtons()=0; + static void removeItemFromListWidget(QListWidget* widget, const char* itemstr); protected: QWidget* proxy; ViewProviderTransformed *TransformedView; - bool originalSelectionMode; - bool referenceSelectionMode; + enum selectionModes { none, addFeature, removeFeature, reference }; + selectionModes selectionMode; /// The MultiTransform parent task of this task TaskMultiTransformParameters* parentTask; diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index 249b229721fa..b7228e8278de 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -77,18 +77,6 @@ bool ViewProviderTransformed::setEdit(int ModNum) pcRejectedRoot = new SoSeparator(); pcRejectedRoot->ref(); - rejectedTrfms = new SoMultipleCopy(); - rejectedTrfms->ref(); - - rejectedCoords = new SoCoordinate3(); - rejectedCoords->ref(); - - rejectedNorms = new SoNormal(); - rejectedNorms->ref(); - - rejectedFaceSet = new SoIndexedFaceSet(); - rejectedFaceSet->ref(); - SoPickStyle* rejectedPickStyle = new SoPickStyle(); rejectedPickStyle->style = SoPickStyle::UNPICKABLE; @@ -118,12 +106,7 @@ bool ViewProviderTransformed::setEdit(int ModNum) pcRejectedRoot->addChild(rejectedMaterial); pcRejectedRoot->addChild(rejectedHints); pcRejectedRoot->addChild(rejectedFaceStyle); - pcRejectedRoot->addChild(rejectedCoords); - pcRejectedRoot->addChild(rejectedNorms); - pcRejectedRoot->addChild(rejectedNormb); - pcRejectedRoot->addChild(rejectedTrfms); - rejectedTrfms->addChild(rejectedFaceSet); - + pcRejectedRoot->addChild(rejectedNormb); // NOTE: The code relies on the last child added here being index 6 pcRoot->addChild(pcRejectedRoot); recomputeFeature(); @@ -151,16 +134,19 @@ void ViewProviderTransformed::unsetEdit(int ModNum) PartGui::ViewProviderPart::unsetEdit(ModNum); } - rejectedTrfms->removeAllChildren(); + while (pcRejectedRoot->getNumChildren() > 7) { + SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); + SoMultipleCopy* rejectedTrfms = static_cast(sep->getChild(2)); + rejectedTrfms ->removeAllChildren(); + sep->removeChild(1); + sep->removeChild(0); + pcRejectedRoot ->removeChild(7); + } pcRejectedRoot->removeAllChildren(); pcRoot->removeChild(pcRejectedRoot); pcRejectedRoot->unref(); - rejectedTrfms->unref(); - rejectedCoords->unref(); - rejectedNorms->unref(); - rejectedFaceSet->unref(); } bool ViewProviderTransformed::onDelete(const std::vector &s) @@ -203,8 +189,11 @@ void ViewProviderTransformed::recomputeFeature(void) PartDesign::Transformed* pcTransformed = static_cast(getObject()); pcTransformed->getDocument()->recomputeFeature(pcTransformed); const std::vector log = pcTransformed->getDocument()->getRecomputeLog(); - unsigned rejected = pcTransformed->getRejectedTransformations().size(); - QString msg = QString::fromLatin1("%1"); + PartDesign::Transformed::rejectedMap rejected_trsf = pcTransformed->getRejectedTransformations(); + unsigned rejected = 0; + for (PartDesign::Transformed::rejectedMap::const_iterator r = rejected_trsf.begin(); r != rejected_trsf.end(); r++) + rejected += r->second.size(); + QString msg = QString::fromAscii("%1"); if (rejected > 0) { msg = QString::fromLatin1("%1
\r\n%2"); if (rejected == 1) @@ -223,25 +212,30 @@ void ViewProviderTransformed::recomputeFeature(void) } signalDiagnosis(msg); - TopoDS_Shape shape; - if (rejected != 0) { - // FIXME: create a compound if there are more than one originals - App::DocumentObject* original = pcTransformed->Originals.getValues().front(); - if (original->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) { - PartDesign::Additive* addFeature = static_cast(original); + // Clear all the rejected stuff + while (pcRejectedRoot->getNumChildren() > 7) { + SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); + SoMultipleCopy* rejectedTrfms = static_cast(sep->getChild(2)); + rejectedTrfms ->removeAllChildren(); + sep->removeChild(1); + sep->removeChild(0); + pcRejectedRoot ->removeChild(7); + } + + for (PartDesign::Transformed::rejectedMap::const_iterator o = rejected_trsf.begin(); o != rejected_trsf.end(); o++) { + if (o->second.empty()) continue; + + TopoDS_Shape shape; + if ((o->first)->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) { + PartDesign::Additive* addFeature = static_cast(o->first); shape = addFeature->AddShape.getShape()._Shape; - } else if (original->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { - PartDesign::Subtractive* subFeature = static_cast(original); + } else if ((o->first)->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { + PartDesign::Subtractive* subFeature = static_cast(o->first); shape = subFeature->SubShape.getShape()._Shape; } - } - if (rejected == 0 || shape.IsNull()) { - rejectedCoords ->point .setNum(0); - rejectedNorms ->vector .setNum(0); - rejectedFaceSet ->coordIndex .setNum(0); - rejectedTrfms ->matrix .setNum(0); - } else { + if (shape.IsNull()) continue; + // Display the rejected transformations in red TopoDS_Shape cShape(shape); @@ -257,6 +251,7 @@ void ViewProviderTransformed::recomputeFeature(void) Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue(); // create or use the mesh on the data structure + // Note: This DOES have an effect on cShape #if OCC_VERSION_HEX >= 0x060600 Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI; BRepMesh_IncrementalMesh(cShape,deflection,Standard_False, @@ -282,8 +277,11 @@ void ViewProviderTransformed::recomputeFeature(void) } // create memory for the nodes and indexes + SoCoordinate3* rejectedCoords = new SoCoordinate3(); rejectedCoords ->point .setNum(nbrNodes); + SoNormal* rejectedNorms = new SoNormal(); rejectedNorms ->vector .setNum(nbrNodes); + SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet(); rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4); // get the raw memory for fast fill up @@ -379,17 +377,23 @@ void ViewProviderTransformed::recomputeFeature(void) rejectedFaceSet ->coordIndex .finishEditing(); // fill in the transformation matrices - rejectedTrfms->matrix.setNum(rejected); + SoMultipleCopy* rejectedTrfms = new SoMultipleCopy(); + rejectedTrfms->matrix.setNum((o->second).size()); SbMatrix* mats = rejectedTrfms->matrix.startEditing(); - std::list rejected_trsf = pcTransformed->getRejectedTransformations(); - std::list::const_iterator trsf = rejected_trsf.begin(); - for (unsigned int i=0; i < rejected; i++,trsf++) { + std::list::const_iterator trsf = (o->second).begin(); + for (unsigned int i=0; i < (o->second).size(); i++,trsf++) { Base::Matrix4D mat; Part::TopoShape::convertToMatrix(*trsf,mat); mats[i] = convert(mat); } rejectedTrfms->matrix.finishEditing(); + rejectedTrfms->addChild(rejectedFaceSet); + SoSeparator* sep = new SoSeparator(); + sep->addChild(rejectedCoords); + sep->addChild(rejectedNorms); + sep->addChild(rejectedTrfms); + pcRejectedRoot->addChild(sep); } catch (...) { Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n", diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp.orig b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp.orig new file mode 100644 index 000000000000..efe35658d555 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp.orig @@ -0,0 +1,410 @@ +/****************************************************************************** + * Copyright (c)2012 Jan Rheinlaender * + * * + * 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 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include "Workbench.h" +#include "ViewProviderTransformed.h" +#include "TaskTransformedParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderTransformed,PartDesignGui::ViewProvider) + +void ViewProviderTransformed::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr((std::string("Edit ") + featureName + " feature").c_str()), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderTransformed::setEdit(int ModNum) +{ + pcRejectedRoot = new SoSeparator(); + pcRejectedRoot->ref(); + + SoPickStyle* rejectedPickStyle = new SoPickStyle(); + rejectedPickStyle->style = SoPickStyle::UNPICKABLE; + + SoShapeHints* rejectedHints = new SoShapeHints(); + rejectedHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE; + rejectedHints->shapeType = SoShapeHints::UNKNOWN_SHAPE_TYPE; + + SoMaterialBinding* rejectedBind = new SoMaterialBinding(); + + SoTransparencyType* rejectedTransparencyType = new SoTransparencyType(); + rejectedTransparencyType->value.setValue(SoGLRenderAction::BLEND); + + SoMaterial* rejectedMaterial = new SoMaterial(); + rejectedMaterial->diffuseColor.set1Value(0,SbColor(1.f,0.f,0.f)); + rejectedMaterial->transparency.setValue(0.6f); + + SoDrawStyle* rejectedFaceStyle = new SoDrawStyle(); + rejectedFaceStyle->style = SoDrawStyle::FILLED; + + SoNormalBinding* rejectedNormb = new SoNormalBinding(); + rejectedNormb->value = SoNormalBinding::PER_VERTEX_INDEXED; + + // just faces with no edges or points + pcRejectedRoot->addChild(rejectedPickStyle); + pcRejectedRoot->addChild(rejectedTransparencyType); + pcRejectedRoot->addChild(rejectedBind); + pcRejectedRoot->addChild(rejectedMaterial); + pcRejectedRoot->addChild(rejectedHints); + pcRejectedRoot->addChild(rejectedFaceStyle); + pcRejectedRoot->addChild(rejectedNormb); // NOTE: The code relies on the last child added here being index 6 + pcRoot->addChild(pcRejectedRoot); + + recomputeFeature(); + return true; +} + +void ViewProviderTransformed::unsetEdit(int ModNum) +{ + // return to the WB we were in before editing the PartDesign feature + Gui::Command::assureWorkbench(oldWb.c_str()); + + if (ModNum == ViewProvider::Default) { + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + if ((PartDesignGui::ActivePartObject != NULL) && (oldTip != NULL)) { + Gui::Selection().clearSelection(); + Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + oldTip = NULL; + } else { + oldTip = NULL; + } + } + else { + PartGui::ViewProviderPart::unsetEdit(ModNum); + } + + while (pcRejectedRoot->getNumChildren() > 7) { + SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); + SoMultipleCopy* rejectedTrfms = static_cast(sep->getChild(2)); + rejectedTrfms ->removeAllChildren(); + sep->removeChild(1); + sep->removeChild(0); + pcRejectedRoot ->removeChild(7); + } + pcRejectedRoot->removeAllChildren(); + + pcRoot->removeChild(pcRejectedRoot); + + pcRejectedRoot->unref(); +} + +bool ViewProviderTransformed::onDelete(const std::vector &s) +{ + return ViewProvider::onDelete(s); +} + +const bool ViewProviderTransformed::checkDlgOpen(TaskDlgTransformedParameters* transformedDlg) { + // When double-clicking on the item for this feature the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + transformedDlg = qobject_cast(dlg); + + if ((transformedDlg != NULL) && (transformedDlg->getTransformedView() != this)) + transformedDlg = NULL; // another transformed feature left open its task panel + + if ((dlg != NULL) && (transformedDlg == NULL)) { + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().reject(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // Continue (usually in virtual method setEdit()) + return true; +} + +void ViewProviderTransformed::recomputeFeature(void) +{ + PartDesign::Transformed* pcTransformed = static_cast(getObject()); + pcTransformed->getDocument()->recomputeFeature(pcTransformed); + const std::vector log = pcTransformed->getDocument()->getRecomputeLog(); +<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 + unsigned rejected = pcTransformed->getRejectedTransformations().size(); + QString msg = QString::fromLatin1("%1"); +======= + PartDesign::Transformed::rejectedMap rejected_trsf = pcTransformed->getRejectedTransformations(); + unsigned rejected = 0; + for (PartDesign::Transformed::rejectedMap::const_iterator r = rejected_trsf.begin(); r != rejected_trsf.end(); r++) + rejected += r->second.size(); + QString msg = QString::fromAscii("%1"); +>>>>>>> Enable multiple originals for the transformed features + if (rejected > 0) { + msg = QString::fromLatin1("%1
\r\n%2"); + if (rejected == 1) + msg = msg.arg(QObject::tr("One transformed shape does not intersect support")); + else { + msg = msg.arg(QObject::tr("%1 transformed shapes do not intersect support")); + msg = msg.arg(rejected); + } + } + if (log.size() > 0) { + msg = msg.arg(QString::fromLatin1("%1
")); + msg = msg.arg(QString::fromStdString(log.back()->Why)); + } else { + msg = msg.arg(QString::fromLatin1("%1
")); + msg = msg.arg(QObject::tr("Transformation succeeded")); + } + signalDiagnosis(msg); + + // Clear all the rejected stuff + while (pcRejectedRoot->getNumChildren() > 7) { + SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); + SoMultipleCopy* rejectedTrfms = static_cast(sep->getChild(2)); + rejectedTrfms ->removeAllChildren(); + sep->removeChild(1); + sep->removeChild(0); + pcRejectedRoot ->removeChild(7); + } + + for (PartDesign::Transformed::rejectedMap::const_iterator o = rejected_trsf.begin(); o != rejected_trsf.end(); o++) { + if (o->second.empty()) continue; + + TopoDS_Shape shape; + if ((o->first)->getTypeId().isDerivedFrom(PartDesign::Additive::getClassTypeId())) { + PartDesign::Additive* addFeature = static_cast(o->first); + shape = addFeature->AddShape.getShape()._Shape; + } else if ((o->first)->getTypeId().isDerivedFrom(PartDesign::Subtractive::getClassTypeId())) { + PartDesign::Subtractive* subFeature = static_cast(o->first); + shape = subFeature->SubShape.getShape()._Shape; + } + + if (shape.IsNull()) continue; + + // Display the rejected transformations in red + TopoDS_Shape cShape(shape); + + try { + // calculating the deflection value + Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; + { + Bnd_Box bounds; + BRepBndLib::Add(cShape, bounds); + bounds.SetGap(0.0); + bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); + } + Standard_Real deflection = ((xMax-xMin)+(yMax-yMin)+(zMax-zMin))/300.0 * Deviation.getValue(); + + // create or use the mesh on the data structure + // Note: This DOES have an effect on cShape +#if OCC_VERSION_HEX >= 0x060600 + Standard_Real AngDeflectionRads = AngularDeflection.getValue() / 180.0 * M_PI; + BRepMesh_IncrementalMesh(cShape,deflection,Standard_False, + AngDeflectionRads,Standard_True); +#else + BRepMesh_IncrementalMesh(cShape,deflection); +#endif + // We must reset the location here because the transformation data + // are set in the placement property + TopLoc_Location aLoc; + cShape.Location(aLoc); + + // count triangles and nodes in the mesh + int nbrTriangles=0, nbrNodes=0; + TopExp_Explorer Ex; + for (Ex.Init(cShape,TopAbs_FACE);Ex.More();Ex.Next()) { + Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(TopoDS::Face(Ex.Current()), aLoc); + // Note: we must also count empty faces + if (!mesh.IsNull()) { + nbrTriangles += mesh->NbTriangles(); + nbrNodes += mesh->NbNodes(); + } + } + + // create memory for the nodes and indexes + SoCoordinate3* rejectedCoords = new SoCoordinate3(); + rejectedCoords ->point .setNum(nbrNodes); + SoNormal* rejectedNorms = new SoNormal(); + rejectedNorms ->vector .setNum(nbrNodes); + SoIndexedFaceSet* rejectedFaceSet = new SoIndexedFaceSet(); + rejectedFaceSet ->coordIndex .setNum(nbrTriangles*4); + + // get the raw memory for fast fill up + SbVec3f* verts = rejectedCoords ->point .startEditing(); + SbVec3f* norms = rejectedNorms ->vector .startEditing(); + int32_t* index = rejectedFaceSet ->coordIndex .startEditing(); + + // preset the normal vector with null vector + for (int i=0; i < nbrNodes; i++) + norms[i]= SbVec3f(0.0,0.0,0.0); + + int ii = 0,FaceNodeOffset=0,FaceTriaOffset=0; + for (Ex.Init(cShape, TopAbs_FACE); Ex.More(); Ex.Next(),ii++) { + TopLoc_Location aLoc; + const TopoDS_Face &actFace = TopoDS::Face(Ex.Current()); + // get the mesh of the shape + Handle (Poly_Triangulation) mesh = BRep_Tool::Triangulation(actFace,aLoc); + if (mesh.IsNull()) continue; + + // getting the transformation of the shape/face + gp_Trsf myTransf; + Standard_Boolean identity = true; + if (!aLoc.IsIdentity()) { + identity = false; + myTransf = aLoc.Transformation(); + } + + // getting size of node and triangle array of this face + int nbNodesInFace = mesh->NbNodes(); + int nbTriInFace = mesh->NbTriangles(); + // check orientation + TopAbs_Orientation orient = actFace.Orientation(); + + // cycling through the poly mesh + const Poly_Array1OfTriangle& Triangles = mesh->Triangles(); + const TColgp_Array1OfPnt& Nodes = mesh->Nodes(); + for (int g=1; g <= nbTriInFace; g++) { + // Get the triangle + Standard_Integer N1,N2,N3; + Triangles(g).Get(N1,N2,N3); + + // change orientation of the triangle if the face is reversed + if ( orient != TopAbs_FORWARD ) { + Standard_Integer tmp = N1; + N1 = N2; + N2 = tmp; + } + + // get the 3 points of this triangle + gp_Pnt V1(Nodes(N1)), V2(Nodes(N2)), V3(Nodes(N3)); + + // transform the vertices to the place of the face + if (!identity) { + V1.Transform(myTransf); + V2.Transform(myTransf); + V3.Transform(myTransf); + } + + // calculating per vertex normals + // Calculate triangle normal + gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z()); + gp_Vec Normal = (v2-v1)^(v3-v1); + + // add the triangle normal to the vertex normal for all points of this triangle + norms[FaceNodeOffset+N1-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z()); + norms[FaceNodeOffset+N2-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z()); + norms[FaceNodeOffset+N3-1] += SbVec3f(Normal.X(),Normal.Y(),Normal.Z()); + + // set the vertices + verts[FaceNodeOffset+N1-1].setValue((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z())); + verts[FaceNodeOffset+N2-1].setValue((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z())); + verts[FaceNodeOffset+N3-1].setValue((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z())); + + // set the index vector with the 3 point indexes and the end delimiter + index[FaceTriaOffset*4+4*(g-1)] = FaceNodeOffset+N1-1; + index[FaceTriaOffset*4+4*(g-1)+1] = FaceNodeOffset+N2-1; + index[FaceTriaOffset*4+4*(g-1)+2] = FaceNodeOffset+N3-1; + index[FaceTriaOffset*4+4*(g-1)+3] = SO_END_FACE_INDEX; + } + + // counting up the per Face offsets + FaceNodeOffset += nbNodesInFace; + FaceTriaOffset += nbTriInFace; + } + + // normalize all normals + for (int i=0; i < nbrNodes; i++) + norms[i].normalize(); + + // end the editing of the nodes + rejectedCoords ->point .finishEditing(); + rejectedNorms ->vector .finishEditing(); + rejectedFaceSet ->coordIndex .finishEditing(); + + // fill in the transformation matrices + SoMultipleCopy* rejectedTrfms = new SoMultipleCopy(); + rejectedTrfms->matrix.setNum((o->second).size()); + SbMatrix* mats = rejectedTrfms->matrix.startEditing(); + + std::list::const_iterator trsf = (o->second).begin(); + for (unsigned int i=0; i < (o->second).size(); i++,trsf++) { + Base::Matrix4D mat; + Part::TopoShape::convertToMatrix(*trsf,mat); + mats[i] = convert(mat); + } + rejectedTrfms->matrix.finishEditing(); + rejectedTrfms->addChild(rejectedFaceSet); + SoSeparator* sep = new SoSeparator(); + sep->addChild(rejectedCoords); + sep->addChild(rejectedNorms); + sep->addChild(rejectedTrfms); + pcRejectedRoot->addChild(sep); + } + catch (...) { + Base::Console().Error("Cannot compute Inventor representation for the rejected transformations of shape of %s.\n", + pcTransformed->getNameInDocument()); + } + } + +} + diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h index 601df79b6efa..8ecd67e7d5da 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h @@ -64,12 +64,8 @@ class PartDesignGuiExport ViewProviderTransformed : public ViewProvider const bool checkDlgOpen(TaskDlgTransformedParameters* transformedDlg); - // nodes for the representation of rejected repetitions + // node for the representation of rejected repetitions SoGroup * pcRejectedRoot; - SoMultipleCopy * rejectedTrfms; - SoCoordinate3 * rejectedCoords; - SoNormal * rejectedNorms; - SoIndexedFaceSet * rejectedFaceSet; public: void recomputeFeature(); From 913ec86fdd6ee9f0e4df80a20e0703fa1ba32072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 29 Sep 2013 13:51:35 +0000 Subject: [PATCH 210/664] treat gradient zeros at residual!=0 --- .../Assembly/App/opendcm/core/constraint.hpp | 140 +++++++++++++-- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 161 ++++++++++-------- .../Assembly/App/opendcm/module3d/solver.hpp | 71 +++++--- 3 files changed, 271 insertions(+), 101 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index a54685bac36b..961b6a3cba19 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -47,7 +47,9 @@ #include "traits.hpp" #include "object.hpp" #include "equations.hpp" +#include +class T; namespace mpl = boost::mpl; namespace fusion = boost::fusion; @@ -86,6 +88,7 @@ class Constraint : public Object { void resetType(creator_type& c); void calculate(Scalar scale, bool rotation_only = false); + void treatLGZ(); void setMaps(MES& mes); @@ -118,6 +121,7 @@ class Constraint : public Object { virtual ~placeholder() {} virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const = 0; virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false) = 0; + virtual void treatLGZ(geom_ptr first, geom_ptr second) = 0; virtual int equationCount() = 0; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; @@ -202,6 +206,15 @@ class Constraint : public Object { void operator()(T& val) const; }; + struct LGZ { + geom_ptr first,second; + + LGZ(geom_ptr f, geom_ptr s); + + template< typename T > + void operator()(T& val) const; + }; + struct GenericEquations { std::vector& vec; GenericEquations(std::vector& v); @@ -230,6 +243,7 @@ class Constraint : public Object { holder(Objects& obj); virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false); + virtual void treatLGZ(geom_ptr first, geom_ptr second); virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); @@ -328,7 +342,8 @@ void Constraint::initialize(ConstraintVect //and now store it content = c.p; //geometry order needs to be the one needed by equations - if(c.need_swap) first.swap(second); + if(c.need_swap) + first.swap(second); }; @@ -342,7 +357,8 @@ template< typename creator_type> void Constraint::resetType(creator_type& c) { boost::apply_visitor(c, first->m_geometry, second->m_geometry); content = c.p; - if(c.need_swap) first.swap(second); + if(c.need_swap) + first.swap(second); }; template @@ -350,6 +366,11 @@ void Constraint::calculate(Scalar scale, b content->calculate(first, second, scale, rotation_only); }; +template +void Constraint::treatLGZ() { + content->treatLGZ(first, second); +}; + template void Constraint::setMaps(MES& mes) { content->setMaps(mes, first, second); @@ -427,7 +448,8 @@ void Constraint::holdergetClusterMode()) { @@ -435,7 +457,8 @@ void Constraint::holder::holderm_parameter, block); } } - } else { + } + else { //not in cluster, so allow the constraint to optimize the gradient calculation val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); } @@ -487,7 +511,8 @@ void Constraint::holderm_parameter, block); } } - } else { + } + else { //not in cluster, so allow the constraint to optimize the gradient calculation val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); } @@ -515,7 +540,9 @@ void Constraint::holderm_offset_rot, 3, val.m_diff_first_rot); mes.setJacobiMap(equation, first->m_offset, 3, val.m_diff_first); } - } else mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); + } + else + mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); if(second->getClusterMode()) { @@ -523,7 +550,9 @@ void Constraint::holderm_offset_rot, 3, val.m_diff_second_rot); mes.setJacobiMap(equation, second->m_offset, 3, val.m_diff_second); } - } else mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); + } + else + mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); }; template @@ -539,15 +568,92 @@ template< typename T > void Constraint::holder::PseudoCollector::operator()(T& val) const { if(first->m_isInCluster && second->m_isInCluster) { val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); - } else if(first->m_isInCluster) { - typename Kernel::Vector sec = second->m_parameter; - val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); - } else if(second->m_isInCluster) { - typename Kernel::Vector fir = first->m_parameter; - val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); } + else + if(first->m_isInCluster) { + typename Kernel::Vector sec = second->m_parameter; + val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); + } + else + if(second->m_isInCluster) { + typename Kernel::Vector fir = first->m_parameter; + val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); + } }; +template +template +Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) + : first(f), second(s) { + +}; + +template +template +template< typename T > +void Constraint::holder::LGZ::operator()(T& val) const { + + //to treat local gradient zeros we calculate a approximate second derivative of the equations + //only do that if neseccary: residual is not zero + Base::Console().Message("res: %f\n", val.m_residual(0)); + if(val.m_residual(0) > 1e-7) { //TODO: use exact precission and scale value + + //rotations exist only in cluster + if(first->getClusterMode() && !first->isClusterFixed()) { + //LGZ exists for rotations only + for(int i=0; i<3; i++) { + + //only treat if the gradient realy is zero + Base::Console().Message("local grad: %f\n", val.m_diff_first_rot(i)); + if(std::abs(val.m_diff_first_rot(i)) < 1e-7) { + + //to get the approximated second derivative we need the slightly moved geometrie + typename Kernel::Vector incr = first->m_parameter + first->m_diffparam.col(i)*1e-3; + //with this changed geometrie we test if a gradient exist now + typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); + typename Kernel::VectorMap block2(&incr(0),first->m_parameterCount,1, DS(1,1)); + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(block2, + second->m_parameter, block); + + //let's see if the initial LGZ was a real one + Base::Console().Message("approx second: %f\n", res); + if(std::abs(res) > 1e-7) { + + //is a fake zero, let's correct it + val.m_diff_first_rot(i) = res; + }; + }; + }; + } + //and the same for the second one too + if(second->getClusterMode() && !second->isClusterFixed()) { + + for(int i=0; i<3; i++) { + + //only treat if the gradient realy is zero + Base::Console().Message("local grad: %f\n", val.m_diff_second_rot(i)); + if(std::abs(val.m_diff_second_rot(i)) < 1e-7) { + + //to get the approximated second derivative we need the slightly moved geometrie + typename Kernel::Vector incr = second->m_parameter + second->m_diffparam.col(i)*1e-3; + //with this changed geometrie we test if a gradient exist now + typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); + typename Kernel::VectorMap block2(&incr(0),second->m_parameterCount,1, DS(1,1)); + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(block2, + second->m_parameter, block); + + //let's see if the initial LGZ was a real one + Base::Console().Message("approx second: %f\n", res); + if(std::abs(res) > 1e-7) { + + //is a fake zero, let's correct it + val.m_diff_second_rot(i) = res; + }; + }; + }; + }; + }; +}; template template @@ -605,6 +711,12 @@ void Constraint::holder +template +void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { + fusion::for_each(m_sets, LGZ(first, second)); +}; + template template typename Constraint::placeholder* diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 392dc43da0f2..1e738ad827e9 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -99,44 +99,48 @@ struct Dogleg { // compute the dogleg step if(h_gn.norm() <= delta) { h_dl = h_gn; - } else if((alpha*h_sd).norm() >= delta) { - //h_dl = alpha*h_sd; - h_dl = (delta/(h_sd.norm()))*h_sd; + } + else + if((alpha*h_sd).norm() >= delta) { + //h_dl = alpha*h_sd; + h_dl = (delta/(h_sd.norm()))*h_sd; #ifdef USE_LOGGING - if(!boost::math::isfinite(h_dl.norm())) { - BOOST_LOG(log)<< "Unnormal dogleg descent detected: "<= maxIterNumber) - throw solving_error() << boost::errinfo_errno(4) << error_message("maximal iterations reached"); - else if(!boost::math::isfinite(err)) - throw solving_error() << boost::errinfo_errno(5) << error_message("error is inf or nan"); - else if(err > diverging_lim) - throw solving_error() << boost::errinfo_errno(6) << error_message("error diverged"); + else + if(g_inf <= tolg) + throw solving_error() << boost::errinfo_errno(2) << error_message("g infinity norm smaller below limit"); + else + if(delta <= tolx) + throw solving_error() << boost::errinfo_errno(3) << error_message("step size below limit"); + else + if(iter >= maxIterNumber) + throw solving_error() << boost::errinfo_errno(4) << error_message("maximal iterations reached"); + else + if(!boost::math::isfinite(err)) + throw solving_error() << boost::errinfo_errno(5) << error_message("error is inf or nan"); + else + if(err > diverging_lim) + throw solving_error() << boost::errinfo_errno(6) << error_message("error diverged"); // see if we are already finished @@ -210,6 +219,10 @@ struct Dogleg { number_type dF=0, dL=0; number_type rho; + //handle possible lgz's + if(iter==0) + sys.removeLocalGradientZeros(); + //get the update step calculateStep(g, sys.Jacobi, sys.Residual, h_dl, delta); @@ -238,15 +251,18 @@ struct Dogleg { dF = err - err_new; rho = dF/dL; - if(dF<=0 || dL<=0) rho = -1; + if(dF<=0 || dL<=0) + rho = -1; // update delta if(rho>0.85) { delta = std::max(delta,2*h_dl.norm()); nu = 2; - } else if(rho < 0.25) { - delta = delta/nu; - nu = 2*nu; } + else + if(rho < 0.25) { + delta = delta/nu; + nu = 2*nu; + } if(dF > 0 && dL > 0) { @@ -259,11 +275,12 @@ struct Dogleg { sys.recalculate(); } //it can also happen that the differentials get too small, however, we cant check for that - else if(iter>1 && (counter>50)) { - rescale(); - sys.recalculate(); - counter = 0; - } + else + if(iter>1 && (counter>50)) { + rescale(); + sys.recalculate(); + counter = 0; + } F_old = sys.Residual; J_old = sys.Jacobi; @@ -275,7 +292,8 @@ struct Dogleg { g_inf = g.template lpNorm(); fx_inf = sys.Residual.template lpNorm(); - } else { + } + else { sys.Residual = F_old; sys.Jacobi = J_old; sys.Parameter -= h_dl; @@ -401,7 +419,8 @@ struct Kernel { new(&map) VectorMap(&m_parameter(m_param_rot_offset), number, DynStride(1,1)); m_param_rot_offset += number; return m_param_rot_offset-number; - } else { + } + else { m_param_trans_offset -= number; new(&map) VectorMap(&m_parameter(m_param_trans_offset), number, DynStride(1,1)); return m_param_trans_offset; @@ -413,7 +432,8 @@ struct Kernel { new(&map) Vector3Map(&m_parameter(m_param_rot_offset)); m_param_rot_offset += 3; return m_param_rot_offset-3; - } else { + } + else { m_param_trans_offset -= 3; new(&map) Vector3Map(&m_parameter(m_param_trans_offset)); return m_param_trans_offset; @@ -431,7 +451,8 @@ struct Kernel { }; bool isValid() { - if(!m_params || !m_eqns) return false; + if(!m_params || !m_eqns) + return false; return true; }; @@ -440,15 +461,19 @@ struct Kernel { if(t==complete) { new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1)); new(&Parameter) VectorMap(&m_parameter(0),m_params,DynStride(1,1)); - } else if(t==rotation) { - int num = m_param_trans_offset; - new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); - new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1)); - } else if(t==general) { - int num = m_params - m_param_trans_offset; - new(&Jacobi) MatrixMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); - new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1)); } + else + if(t==rotation) { + int num = m_param_trans_offset; + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1)); + } + else + if(t==general) { + int num = m_params - m_param_trans_offset; + new(&Jacobi) MatrixMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1)); + } }; void setGeneralEquationAccess(bool general) { @@ -459,13 +484,15 @@ struct Kernel { if(t==rotation) return (m_param_rot_offset>0); - else if(t==general) - return (m_param_trans_offset0); + if(t==general) + return (m_param_trans_offset0); }; virtual void recalculate() = 0; + virtual void removeLocalGradientZeros() = 0; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index 3f8d5a114fc7..75fc9ff2719d 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -51,12 +51,13 @@ struct MES : public system_traits::Kernel::MappedEquationSystem { typedef typename module3d::math_prop math_prop; typedef typename module3d::fix_prop fix_prop; typedef typename Kernel::number_type Scalar; - typedef typename system_traits::Kernel::MappedEquationSystem Base; + typedef typename system_traits::Kernel::MappedEquationSystem base; boost::shared_ptr m_cluster; MES(boost::shared_ptr cl, int par, int eqn); virtual void recalculate(); + virtual void removeLocalGradientZeros(); }; template @@ -126,7 +127,7 @@ struct SystemSolver : public Job { template -MES::MES(boost::shared_ptr cl, int par, int eqn) : Base(par, eqn), m_cluster(cl) { +MES::MES(boost::shared_ptr cl, int par, int eqn) : base(par, eqn), m_cluster(cl) { }; @@ -153,7 +154,26 @@ void MES::recalculate() { std::pair< oiter, oiter > oit = m_cluster->template getObjects(*eit.first); for(; oit.first != oit.second; oit.first++) { if(*oit.first) - (*oit.first)->calculate(Base::Scaling, Base::rot_only); + (*oit.first)->calculate(base::Scaling, base::rot_only); + } + } +}; + +template +void MES::removeLocalGradientZeros() { + + Base::Console().Message("remove local gradient zero\n"); + //let the constraints treat the local zeros + typedef typename Cluster::template object_iterator oiter; + typedef typename boost::graph_traits::edge_iterator eiter; + std::pair eit = boost::edges(*m_cluster); + for(; eit.first != eit.second; eit.first++) { + //as always: every local edge can hold multiple global ones, so iterate over all constraints + //hold by the individual edge + std::pair< oiter, oiter > oit = m_cluster->template getObjects(*eit.first); + for(; oit.first != oit.second; oit.first++) { + if(*oit.first) + (*oit.first)->treatLGZ(); } } }; @@ -178,7 +198,8 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() Scalar sc = 0; for(cit = cluster->clusters(); cit.first != cit.second; cit.first++) { //fixed cluster are irrelevant for scaling - if((*cit.first).second->template getClusterProperty()) continue; + if((*cit.first).second->template getClusterProperty()) + continue; //get the biggest scale factor details::ClusterMath& math = (*cit.first).second->template getClusterProperty(); @@ -200,7 +221,8 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() boost::shared_ptr c = cluster->getVertexCluster(*it.first); c->template getClusterProperty().applyClusterScale(sc, c->template getClusterProperty()); - } else { + } + else { Geom g = cluster->template getObject(*it.first); g->scale(sc*SKALEFAKTOR); } @@ -283,7 +305,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy if(!cluster->template getSubclusterProperty(*it.first)) { params += 6; } - } else { + } + else { params += cluster->template getObject(*it.first)->m_parameterCount; }; } @@ -328,14 +351,17 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy cm.setParameterOffset(offset, general); //wirte initial values cm.initMaps(); - } else cm.initFixMaps(); + } + else + cm.initFixMaps(); //map all geometrie within that cluster to it's rotation matrix //for collecting all geometries which need updates cm.clearGeometry(); cm.mapClusterDownstreamGeometry(c); - } else { + } + else { Geom g = cluster->template getObject(*it.first); int offset = mes.setParameterMap(g->m_parameterCount, g->getParameterMap()); g->m_offset = offset; @@ -356,7 +382,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //set the maps Cons c = *oit.first; - if(c) c->setMaps(mes); + if(c) + c->setMaps(mes); //TODO: else throw (as every global edge was counted as one equation) } } @@ -370,7 +397,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy DummyScaler re; Kernel::solve(mes, re); - } else { + } + else { // we have rotations, so let's check our options. first search for cycles, as systems with them // always need the full solver power @@ -378,18 +406,18 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy cycle_dedector cd(has_cycle); //create te needed property map, fill it and run the test property_map vi_map(cluster); - property_map vc_map(cluster); - property_map ec_map(cluster); + property_map vc_map(cluster); + property_map ec_map(cluster); cluster->initIndexMaps(); boost::undirected_dfs(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map).vertex_color_map(vc_map).edge_color_map(ec_map)); - - bool done = false; + + bool done = false; if(!has_cycle) { #ifdef USE_LOGGING BOOST_LOG(log)<< "non-cyclic system dedected" #endif - //cool, lets do uncylic. first all rotational constraints with rotational parameters - mes.setAccess(rotation); + //cool, lets do uncylic. first all rotational constraints with rotational parameters + mes.setAccess(rotation); mes.setGeneralEquationAccess(false); //solve can be done without catching exceptions, because this only fails if the system is //unsolvable @@ -408,7 +436,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy DummyScaler re; Kernel::solve(mes, re); done=true; - } catch(boost::exception& ) { + } + catch(boost::exception&) { //not successful, so we need brute force done = false; } @@ -420,7 +449,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy #ifdef USE_LOGGING BOOST_LOG(log)<< "Full scale solver used" #endif - Rescaler re(cluster, mes); + Rescaler re(cluster, mes); re(); Kernel::solve(mes, re); #ifdef USE_LOGGING @@ -444,7 +473,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy for(typename std::vector::iterator vit = vec.begin(); vit != vec.end(); vit++) (*vit)->finishCalculation(); - } else { + } + else { Geom g = cluster->template getObject(*it.first); g->scale(mes.Scaling); g->finishCalculation(); @@ -453,7 +483,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //we have solved this cluster cluster->template setClusterProperty(false); - } catch(boost::exception& ) { + } + catch(boost::exception&) { throw; } }; From 6c494157f50eb10db5b9e4efb5f64ab7e3825698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 30 Sep 2013 04:38:29 +0000 Subject: [PATCH 211/664] updated dcm version --- .../Assembly/App/opendcm/.kdev_include_paths | 2 + src/Mod/Assembly/App/opendcm/core.hpp | 1 + .../App/opendcm/core/clustergraph.hpp | 864 +++++++++++++----- .../Assembly/App/opendcm/core/constraint.hpp | 456 +++++---- .../Assembly/App/opendcm/core/equations.hpp | 5 - .../Assembly/App/opendcm/core/geometry.hpp | 341 ++++--- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 16 +- src/Mod/Assembly/App/opendcm/core/object.hpp | 189 ++-- .../Assembly/App/opendcm/core/property.hpp | 502 +++++++++- src/Mod/Assembly/App/opendcm/core/system.hpp | 47 +- src/Mod/Assembly/App/opendcm/core/traits.hpp | 7 +- src/Mod/Assembly/App/opendcm/module3d.hpp | 1 + .../Assembly/App/opendcm/module3d/angle.hpp | 4 +- .../App/opendcm/module3d/clustermath.hpp | 12 +- .../App/opendcm/module3d/coincident.hpp | 49 +- .../Assembly/App/opendcm/module3d/defines.hpp | 7 - .../App/opendcm/module3d/distance.hpp | 11 +- .../App/opendcm/module3d/geometry.hpp | 61 +- .../Assembly/App/opendcm/module3d/module.hpp | 316 ++++++- .../Assembly/App/opendcm/module3d/solver.hpp | 78 +- .../App/opendcm/modulePart/module.hpp | 48 +- .../App/opendcm/moduleState/extractor.hpp | 6 +- .../App/opendcm/moduleState/generator.hpp | 2 +- .../App/opendcm/moduleState/generator_imp.hpp | 2 +- .../opendcm/moduleState/object_generator.hpp | 4 +- .../moduleState/object_generator_imp.hpp | 2 +- .../App/opendcm/moduleState/object_parser.hpp | 4 +- .../opendcm/moduleState/object_parser_imp.hpp | 2 +- .../App/opendcm/moduleState/parser_imp.hpp | 2 +- .../opendcm/moduleState/property_parser.hpp | 2 +- 30 files changed, 2101 insertions(+), 942 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/.kdev_include_paths b/src/Mod/Assembly/App/opendcm/.kdev_include_paths index c0f755818ff9..a9739057226e 100644 --- a/src/Mod/Assembly/App/opendcm/.kdev_include_paths +++ b/src/Mod/Assembly/App/opendcm/.kdev_include_paths @@ -1 +1,3 @@ /usr/include/eigen3 +/home/stefan/Projects/openDCM/opendcm/ +/home/stefan/Projects/openDCM/ diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index f9eacdf67fc0..6a4612f76d99 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -34,6 +34,7 @@ #endif +#include "core/defines.hpp" #include "core/geometry.hpp" #include "core/kernel.hpp" #include "core/system.hpp" diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index 9ac0cb3fe408..ed653a05c0bf 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -59,20 +59,75 @@ namespace fusion = boost::fusion; namespace dcm { +/** @addtogroup Core + * @{ + * */ + +/** @addtogroup ClusterGraph + * @{*/ + namespace details { +/** @addtogroup Metafunctions + * @{*/ + +/** + * @brief Appends a mpl sequences to another + * + * Makes two sequence to one by appending all types of the first to the second sequence. The new + * mpl sequence can be accessed by the ::type typedef. + * Usage: @code vector_fold::type @endcode + * + * @tparam state the mpl sequence which will be expanded + * @tparam seq the mpl sequence which will be appended + **/ template -struct vector_fold : mpl::fold< seq, state, - mpl::push_back > {}; - -//also add basic properties for graph algorithms like index and color -typedef mpl::vector2 bgl_v_props; -typedef mpl::vector2 bgl_e_props; - - +struct vector_fold : mpl::fold < seq, state, + mpl::push_back > {}; + +/** + * @brief Creates a fusion::vector of boost shared_ptr's from the given types + * + * Creates a shared pointer sequence (sps) of the supplied types by converting them to + * boost::shared_ptr's first and creating a fusion::vector of all pointers afterwards which can be + * accessed by the type typedef. Usage: @code sps::type @endcode + * + * @tparam seq the mpl::sequence with the types to convert to shared_ptr's + **/ +template +struct sps { //shared_ptr sequence + typedef typename mpl::transform >::type spv; + typedef typename fusion::result_of::as_vector::type type; +}; +/**@}*/ + +//Define vertex and edge properties which are always added for use in the boost graph library algorithms +//which are used in the ClusterGraph implementation +typedef mpl::vector1 bgl_v_props; +typedef mpl::vector1 bgl_e_props; + + + typedef boost::adjacency_list_traits list_traits; + + +/** + * @brief A type to be used as identifier for vertices and edges + * + * Vertices and edges need to be identified in a stable(safe/load), unique(over multiple clusters) and + * comparable manner. The bgl vertex and edge discriptors don't fullfill this need as they have a direct + * relation to the graphs storage. Therefore they change value on moving entitiys to diffrent clusters or + * clone actions. This class is used to overcome this problem. + **/ typedef int universalID; +/** + * @brief Generator for unique identifiers + * + * The universalID used to identify vertices and edges globaly need to be unique and therefore can't be + * created at good will. This generator creates universalID's in a incremental manner and is intended to + * to be shared between all graphs of a system, so that all created ID's are unique. + **/ struct IDgen { universalID* counter; @@ -85,19 +140,50 @@ struct IDgen { ~IDgen() { delete counter; }; + /** + * @brief Generates a new unique ID + * + * @return :details::universalID + **/ universalID generate() { - return ++(*counter); + return ++ (*counter); }; + /** + * @brief Returns the amount if generated ID's + * + * As universalID's are integers the returned count is a ID and can therefore also be used as the last + * created ID. + * + * @return :details::universalID + **/ universalID count() { return (*counter); }; + /** + * @brief Set the current value for incremental creation + * + * ID's are created incrementaly and if a specific startingpoint is whised it can be set here by + * supplying the last created ID or the amount of totaly created ID's + * + * @param id The last created ID + * @return void + **/ void setCount(universalID id) { *counter = id; }; }; +/** + * @brief Pointer type to share a common ID generator @ref IDgen + **/ typedef boost::shared_ptr IDpointer; +/** @ingroup Functors + * @brief Functor to clear vertex or edge objects + * + * All objects are boost::shared_ptr, therefore they can be cleared by calling the reset() method. As + * objects are stored within fusion::sequences a functor is needed to clear all of them. + **/ struct clear_ptr { template void operator()(T& t) const { @@ -105,85 +191,161 @@ struct clear_ptr { }; }; -template -struct sps { //shared_ptr sequence - typedef typename mpl::transform >::type spv; - typedef typename fusion::result_of::as_vector::type type; -}; - } +/** @name Descriptors */ +/**@{ + * @brief Identifier for local vertices + * + * The boost graph library works with identifiers for vertices which directly relate to there storage. + * Therefore they can be used only in the relevant cluster, they are local. These are the descriptors + * which need to be used for all bgl algorithms. + **/ typedef details::list_traits::vertex_descriptor LocalVertex; + +/** + * @brief Indentifier for local edge + * + * The boost graph library works with identifiers for edges which directly relate to there storage. + * Therefore they can be used only in the relevant cluster, they are local. These are the descriptors + * which need to be used for all bgl algorithms. + **/ typedef details::list_traits::edge_descriptor LocalEdge; + +/** + * @brief Identifier for global vertex + * + * To overcome the locality of the bgl vertex descriptors a global alternative is introduced. This descriptor + * is unique over clusters and stable on moves and clones. + **/ typedef details::universalID GlobalVertex; + +/** + * @brief Identifier for global edge + * + * To overcome the locality of the bgl edge discriptors a global alternative is introduced. This descriptor + * is unique over clusters and stable on moves and clones. It holds it's source and target also as global + * descriptors of type GlobalVertex and has a unique ID in form of a universalID assigned. + **/ struct GlobalEdge { GlobalVertex source; GlobalVertex target; details::universalID ID; - bool operator==(const GlobalEdge& second) const { - return ID==second.ID; + bool operator== (const GlobalEdge& second) const { + return ID == second.ID; }; - bool operator!=(const GlobalEdge& second) const { - return ID!=second.ID; + bool operator!= (const GlobalEdge& second) const { + return ID != second.ID; }; bool valid() { - return ID>9; + return ID > 9; }; }; - - +/**@}*/ + + +/** + * @brief A graph that can be stacked in a tree-like manner without loosing it connections + * + * This is basicly a boost adjacency_list with single linked lists 'listS' as storage for vertices and + * edges. The edges are undirected. This allows to use all boost graph algorithms and provides therefore + * an comprehensive way for analysing and manipulating its content. It further extends the class with the + * possibility to cluster its content and to add properties and objects to all entitys. For more + * information, see the module ClusterGraph + * + * @tparam edge_prop a mpl::vector with properties which are added to local edges + * @tparam vertex_prop a mpl::vector with properties which are added to vertices + * @tparam cluster_prop a mpl::vector with properties which are added to all clusters + * @tparam objects a mpl::vector with all object types which shall be stored at vertices and edges + **/ template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> -class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, +class ClusterGraph : public boost::adjacency_list < boost::listS, boost::listS, boost::undirectedS, - fusion::vector< GlobalVertex, - typename details::pts::type>::type, - typename details::sps::type>, - fusion::vector< typename details::pts::type>::type, - std::vector< fusion::vector< typename details::sps::type, GlobalEdge > > > >, - public boost::noncopyable, - public boost::enable_shared_from_this > { + fusion::vector < GlobalVertex, + typename details::pts< typename details::ensure_properties::type >::type, + typename details::sps::type > , + fusion::vector < typename details::pts< typename details::ensure_properties::type >::type, + std::vector< fusion::vector< typename details::sps::type, GlobalEdge > > > > , +public PropertyOwner::type>, +public boost::noncopyable, + public boost::enable_shared_from_this > { public: - typedef typename details::vector_fold::type edge_properties; - typedef typename details::vector_fold::type vertex_properties; - + /** + * @brief mpl::vector with all edge properties + * + * The edge properties supplied as template argument to the ClusterGraph are extended with graph + * specific properties, for example a edge_index_prop. These extra properties are intendet to be + * used with boost graph algorithms as property maps. They need to be in specefied by the ClusterGraph + * as they are used within it's implementation. If the graph specific properties are already a part + * of the given property sequence, nothing happens, they are not added twice. + **/ + typedef typename details::ensure_properties::type edge_properties; + /** + * @brief mpl::vector with all vertex properties + * + * The vertex properties supplied as template argument to the ClusterGraph are extended with graph + * specific properties as vertex_index_prop. These extra properties are intendet to be + * used with boost graph algorithms as property maps. They need to be in specefied by the ClusterGraph + * as they are used within it's implementation.If the graph specific properties are already a part + * of the given property sequence, nothing happens, they are not added twice. + **/ + typedef typename details::ensure_properties::type vertex_properties; + + /** + * @brief The property bundle for GlobalEdges + * + * A local edge in a cluster can hold multiple gloabal ones. Therefor we need an extra bundle for + * the GlobalEdges. This bundle holds the objects which are added to that global edge and it's identifier. + * Note that global edges don't have properties, these are only for local ones. + **/ typedef fusion::vector< typename details::sps::type, GlobalEdge > edge_bundle_single; + /** + * @brief The property bundle for local edges + * + * Local edges can hold multiple global ones, we therefore need a std::vector of global edges. As + * they are fully described by a edge_bundle_single we store those. Also local edges can have properties, + * so store a fusion sequence of them too. + **/ typedef fusion::vector< typename details::pts::type, std::vector< edge_bundle_single > > edge_bundle; + /** + * @brief Iteator to access all edge_bundle_single stored in a edge_bundle + **/ typedef typename std::vector< edge_bundle_single >::iterator edge_single_iterator; - typedef fusion::vector< GlobalVertex, typename details::pts::type, + /** + * @brief Property bundle for local vertices + * + * This bundle is simpler than the edge one, as every vertex has on single bundle. We therefore + * store the global descriptor for identification, the fusion sequence with the properties and + * the objects all in one bundle. + **/ + typedef fusion::vector < GlobalVertex, typename details::pts::type, typename details::sps::type > vertex_bundle; - - typedef boost::adjacency_list< boost::listS, boost::listS, + /** + * @brief The adjacency_list type ClusterGraph inherited from + **/ + typedef boost::adjacency_list < boost::listS, boost::listS, boost::undirectedS, vertex_bundle, edge_bundle > Graph; - + typedef boost::enable_shared_from_this > sp_base; //if changed_prop is not a property we have to add it now - typedef typename mpl::if_< - boost::is_same< - typename mpl::find::type, - typename mpl::end::type >, - typename mpl::push_back::type, - cluster_prop >::type cluster_properties; - - typedef typename details::pts::type cluster_bundle; + typedef typename details::ensure_property::type cluster_properties; typedef typename boost::graph_traits::vertex_iterator local_vertex_iterator; typedef typename boost::graph_traits::edge_iterator local_edge_iterator; typedef typename boost::graph_traits::out_edge_iterator local_out_edge_iterator; - typedef std::map > ClusterMap; - - cluster_bundle m_cluster_bundle; + typedef std::map > ClusterMap; private: struct global_extractor { typedef GlobalEdge& result_type; template result_type operator()(T& bundle) const { - return fusion::at_c<1>(bundle); + return fusion::at_c<1> (bundle); }; }; struct global_vertex_extractor { @@ -205,10 +367,10 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, BOOST_MPL_ASSERT((mpl::not_::type > >)); result_type operator()(vertex_bundle& bundle) const { - return fusion::at(fusion::at_c<2>(bundle)); + return fusion::at (fusion::at_c<2> (bundle)); }; result_type operator()(edge_bundle_single& bundle) const { - return fusion::at(fusion::at_c<0>(bundle)); + return fusion::at (fusion::at_c<0> (bundle)); }; }; @@ -221,11 +383,11 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, typedef typename mpl::if_< is_edge_property, edge_properties, vertex_properties >::type sequence; typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; - typedef typename mpl::if_< is_edge_property, mpl::int_<0>, mpl::int_<1> >::type pos; + typedef typename mpl::if_< is_edge_property, mpl::int_<0>, mpl::int_<1> >::type pos; template< typename seq> result_type operator()(seq& b) const { - return fusion::at(fusion::at(b)); + return fusion::at (fusion::at (b)); }; }; @@ -253,20 +415,57 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, public: //iterators + /** + * @brief Iterator for global edge descriptors \ref GlobalEdge + **/ typedef boost::transform_iterator global_edge_iterator; + + /** + * @brief Iterator for global vertex descriptor \ref GlobalVertex + **/ typedef boost::transform_iterator global_vertex_iterator; + /** + * @brief Iterator for objects of given type + * + * Allows to iterate over all objects of given type, dereferencing gives the boost::shared_ptr + * + * @tparam Obj the object type to iterate over + **/ template struct object_iterator : public boost::transform_iterator, edge_single_iterator> { object_iterator(edge_single_iterator it, object_extractor f) - : boost::transform_iterator,edge_single_iterator>(it, f) {}; + : boost::transform_iterator, edge_single_iterator> (it, f) {}; }; + /** + * @brief Iterator for clusters + * + * Allows to iterate over all subclusters. + **/ typedef typename ClusterMap::iterator cluster_iterator; + /** + * @brief Const equivalent to \ref cluster_iterator + **/ typedef typename ClusterMap::const_iterator const_cluster_iterator; + /** + * @brief Basic constructor + * + * This constructor creates a empty cluster with a new ID generator. This is to be used on initial + * clustergraph creation, so only for the very first cluster. + **/ ClusterGraph() : m_id(new details::IDgen) {}; - + + /** + * @brief Dependent constructor + * + * This constructor creates a new cluster, but uses the given cluster as parent. It will therefore + * create a tree-like relationship. Be aware, that the new cluster is not added to the parents + * subcluster list, that has to be done manualy. The new cluster shares the parents ID generator. + * + * @param g the parent cluster graph + **/ ClusterGraph(boost::shared_ptr g) : m_parent(g), m_id(new details::IDgen) { if(g) m_id = g->m_id; }; @@ -287,14 +486,15 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, template void copyInto(boost::shared_ptr into, Functor& functor) const { - //lists does not provide vertex index, so we have to build our own (cant use the internal - //vertex_index_property as we would need to reset the indices and that's not possible in const graph) + //lists does not provide vertex index, so we have to build our own (cant use the internal + //vertex_index_property as we would need to reset the indices and that's not possible in const graph) typedef std::map IndexMap; IndexMap mapIndex; boost::associative_property_map propmapIndex(mapIndex); std::pair vit = boost::vertices(*this); - for(int c=0; vit.first != vit.second; vit.first++, c++) + + for(int c = 0; vit.first != vit.second; vit.first++, c++) put(propmapIndex, *vit.first, c); //first copy all vertices and edges, but be aware that the objects in the new graph @@ -311,9 +511,10 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //now that we have all vertices we can recreate the subclusters std::pair it = clusters(); - for(; it.first!=it.second; it.first++) { + + for(; it.first != it.second; it.first++) { //create the new Graph - boost::shared_ptr ng = boost::shared_ptr(new ClusterGraph(into)); + boost::shared_ptr ng = boost::shared_ptr (new ClusterGraph(into)); //we already have the new vertex, however, we need to find it GlobalVertex gv = getGlobalVertex((*it.first).first); @@ -329,115 +530,240 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //lets see if the objects need special treatment into->for_each_object(functor, false); }; - + + /** + * @brief Compare by adress, not by content + * @param other the cluster to compare with + * @return bool if this is the same cluster in memory + **/ template - bool operator==(const T& other) const { + bool operator== (const T& other) const { return this == &other; }; + /** + * @brief Compare by adress, not by content + * @param other the cluster to compare with + * @return bool if this is the not same cluster in memory + **/ template - bool operator!=(const T& other) const { + bool operator!= (const T& other) const { return !(this == &other); }; - + + /** + * @brief Set diffrent behaviour for changed markers + * + * Some methods of the ClusterGraph set it's changed_prop to true. Thats sensible, as they change + * the graph. However, there are situations where you want to use the methods but don't want the change + * marked. For example recreations while cloning. This method can be used to disable the changed setting. + * @param on Turn change markers on or of + * @return void + **/ void setCopyMode(bool on) { - copy_mode = on; + copy_mode = on; }; - void setChanged() { - if(!copy_mode) - setClusterProperty(true); - }; + //Make sure the compiler finds the base class setters even with equal named functions in this class + using PropertyOwner::getProperty; + using PropertyOwner::setProperty; - /* ******************************************************* - * Cluster Property - * *******************************************************/ - template - typename P::type& getClusterProperty() { - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - return fusion::at(m_cluster_bundle); - }; + /** + * @brief Set the property of a owned cluster + * + * Makes it easy to set a property of a subcluster without retrieving it first + * + * @tparam P the property type which shall be set + * @param v the local vertex which describes the subcluster + **/ template typename P::type& getSubclusterProperty(LocalVertex v) { - return getVertexCluster(v)->template getClusterProperty

(); + return getVertexCluster(v)->template getProperty

(); }; - template - void setClusterProperty(typename P::type p) { - getClusterProperty

() = p; + /** + * @brief Mark if the cluster was changed + * + * @return void + **/ + void setChanged() { + if(!copy_mode) + PropertyOwner::template setProperty (true); }; /* ******************************************************* * Subclustering * *******************************************************/ + + /** + * @brief Creates a new subcluster + * + * As clusters can be stacked in a tree like manner, this function can be used to create new + * children. It automaticly adds it to the subcluster list and adds it to the graph. The new + * subcluster is fully defined by its object and the vertex descriptor which is it's position + * in the current cluster. + * + * @return :pair< boost::shared_ptr< ClusterGraph >, LocalVertex > Subcluster and its descriptor + **/ std::pair, LocalVertex> createCluster() { vertex_bundle vp; - fusion::at_c<0>(vp) = m_id->generate(); - LocalVertex v= boost::add_vertex(vp, *this); - return std::pair, LocalVertex>(m_clusters[v] = boost::shared_ptr(new ClusterGraph(sp_base::shared_from_this())), v); + fusion::at_c<0> (vp) = m_id->generate(); + LocalVertex v = boost::add_vertex(vp, *this); + return std::pair, LocalVertex> (m_clusters[v] = boost::shared_ptr (new ClusterGraph(sp_base::shared_from_this())), v); }; + /** + * @brief Returns the parent cluster + * + * In the stacked cluster hirarchy most clusters have a parent whcih can be accessed with this function. + * However, the toplevel cluster dos nothave a parent and a empty shared_ptr is returned. + * + * @return :shared_ptr< ClusterGraph > the parent cluster or empty pointer + **/ inline boost::shared_ptr parent() { - return boost::shared_ptr(m_parent); + return boost::shared_ptr (m_parent); }; + /** + * @brief const version of \ref parent() + * + * @return :shared_ptr< ClusterGraph > + **/ inline const boost::shared_ptr parent() const { - return boost::shared_ptr(m_parent); + return boost::shared_ptr (m_parent); }; + + /** + * @brief Is this the toplevel cluster? + * + * @return bool if it is + **/ bool isRoot() const { - return m_parent.expired(); + return m_parent.expired(); }; + /** + * @brief Returns the toplevel cluster + * + * @return :shared_ptr< ClusterGraph > + **/ boost::shared_ptr root() { return isRoot() ? sp_base::shared_from_this() : parent()->root(); }; + /** + * @brief const equivalent of \ref root() + * + * @return :shared_ptr< ClusterGraph > + **/ const boost::shared_ptr root() const { return isRoot() ? sp_base::shared_from_this() : parent()->root(); }; + /** + * @brief Iterators for all subclusters + * + * A pair with two \ref cluster_iterator is returned which point to the first cluster and + * to one after the last. #this allows full iteration over all subclusters + * + * @return :pair< cluster_iterator, cluster_iterator > + **/ std::pair clusters() { return std::make_pair(m_clusters.begin(), m_clusters.end()); } + + /** + * @brief const equivalent to \ref clusters() + * + * @return :pair< const_cluster_iterator, const_cluster_iterator > + **/ std::pair clusters() const { return std::make_pair(m_clusters.begin(), m_clusters.end()); } + /** + * @brief The amount of all subclusters + * + * @return :size_t + **/ std::size_t numClusters() const { return m_clusters.size(); } + /** + * @brief Check if this vertex is a cluster + * + * A subcluster is added as normal vertex to the parent cluster. There is no way to distinguish + * between clusters and normal vertices with global or local descriptors only. Therefore this + * function can be used to get information about the type. If it is a cluster, it can be accessed + * with \ref getVertexCluster + * + * @param v The vertex to be checked + * @return bool is cluster or not + **/ bool isCluster(LocalVertex v) { return (m_clusters.find(v) != m_clusters.end()); }; + /** + * @brief Get the cluster corresponding the discriptor + * + * A subcluster is added as normal vertex to the parent cluster. There is no way to access + * the clusters object with global or local descriptors only. Therefore this + * function can be used to get the object belonging to the descriptor. If the vertex is not + * a cluster an empty pointer is returned. + * + * @param v The vertex for which the cluster is wanted + * @return boost::shared_ptr the coresponding cluster orempty pointer + **/ boost::shared_ptr getVertexCluster(LocalVertex v) { if(isCluster(v)) return m_clusters[v]; + //TODO:throw if not a cluster return sp_base::shared_from_this(); }; + /** + * @brief Get the vertex descrptor which descripes the clusters position in the graph + * + * This function is the inverse to \ref getVertexCluster + * + * @param g the graph for which the vertex is searched + * @return :LocalVertex + **/ LocalVertex getClusterVertex(boost::shared_ptr g) { std::pair it = clusters(); - for(; it.first!=it.second; it.first++) { + + for(; it.first != it.second; it.first++) { if((*it.first).second == g) return (*it.first).first; } + return LocalVertex(); }; + /** + * @brief Convinience function for \ref removeCluster + **/ template void removeCluster(boost::shared_ptr g, Functor& f) { removeCluster(getClusterVertex(g), f); }; + /** + * @brief Convinience function for \ref removeCluster + **/ void removeCluster(boost::shared_ptr g) { placehoder p; removeCluster(getClusterVertex(g), p); }; + /** + * @brief Delete all subcluster + * + * @return void + **/ + void clearClusters() { m_clusters.clear(); }; @@ -457,6 +783,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, void removeCluster(LocalVertex v, Functor& f) { typename ClusterMap::iterator it = m_clusters.find(v); + if(it == m_clusters.end()) return; //TODO:throw @@ -468,7 +795,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //remove from map, delete subcluster and remove vertex m_clusters.erase(v); - boost::clear_vertex(v, *this); //should not be needed, just to ensure it + boost::clear_vertex(v, *this); //should not be needed, just to ensure it boost::remove_vertex(v, *this); }; void removeCluster(LocalVertex v) { @@ -481,9 +808,10 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, void remove_vertices(Functor& f, bool recursive = false) { std::pair vit = boost::vertices(*this); + //we iterate forward before deleting to not invalidate our iterator while(vit.first != vit.second) { - LocalVertex v = *(vit.first); + LocalVertex v = * (vit.first); vit.first++; if(!isCluster(v)) { @@ -496,7 +824,8 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, if(recursive) { cluster_iterator cit; - for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { f((*cit).second); (*cit).second->remove_vertices(f, recursive); } @@ -513,24 +842,32 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, /** * @brief Add a vertex to the local cluster * - * @return fusion:vector< LocalVertex, GlobalVertex > with the local and global vertex descriptor + * @return fusion::vector the local and global vertex descriptor **/ fusion::vector addVertex() { vertex_bundle vp; - fusion::at_c<0>(vp) = m_id->generate(); - LocalVertex v= boost::add_vertex(vp, *this); + fusion::at_c<0> (vp) = m_id->generate(); + LocalVertex v = boost::add_vertex(vp, *this); setChanged(); return fusion::make_vector(v, m_id->count()); }; + /** + * @brief Iterators of all global vertices in this cluster + * + * Returns the iterator for the first global vertex and the end() iterator as reference for + * iterating + * + * @return std::pair< global_vertex_iterator, global_vertex_iterator > global vertex iterators + **/ std::pair globalVertices() { std::pair res = boost::vertices(*this); global_vertex_iterator begin = boost::make_transform_iterator(res.first, global_vertex_extractor(*this)); global_vertex_iterator end = boost::make_transform_iterator(res.second, global_vertex_extractor(*this)); - return std::pair(begin, end); + return std::pair (begin, end); }; /** @@ -563,22 +900,23 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, fusion::vector addEdge(LocalVertex source, LocalVertex target) { //manual edge creation with cluster is not allowed - if((source==target) || isCluster(source) || isCluster(target)) + if((source == target) || isCluster(source) || isCluster(target)) return fusion::make_vector(LocalEdge(), GlobalEdge(), false); LocalEdge e; bool done; - boost::tie(e,done) = boost::edge(source, target, *this); + boost::tie(e, done) = boost::edge(source, target, *this); //if done=true the edge alredy existed - if(!done) boost::tie(e,done) = boost::add_edge(source, target, *this); + if(!done) boost::tie(e, done) = boost::add_edge(source, target, *this); + if(!done) return fusion::make_vector(LocalEdge(), GlobalEdge(), false); //init the bundle corecctly for new edge - GlobalEdge global = { fusion::at_c<0>((*this)[source]), fusion::at_c<0>((*this)[target]), m_id->generate() }; + GlobalEdge global = { fusion::at_c<0> ((*this) [source]), fusion::at_c<0> ((*this) [target]), m_id->generate() }; edge_bundle_single s; - fusion::at_c<1>(s) = global; - fusion::at_c<1>((*this)[e]).push_back(s); + fusion::at_c<1> (s) = global; + fusion::at_c<1> ((*this) [e]).push_back(s); setChanged(); return fusion::make_vector(e, global, true); @@ -603,32 +941,34 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, **/ fusion::vector addEdge(GlobalVertex source, GlobalVertex target) { - LocalVertex v1,v2; + LocalVertex v1, v2; LocalEdge e; - bool d1,d2,d3; - boost::tie(v1,d1) = getContainingVertex(source); - boost::tie(v2,d2) = getContainingVertex(target); + bool d1, d2, d3; + boost::tie(v1, d1) = getContainingVertex(source); + boost::tie(v2, d2) = getContainingVertex(target); //if one vertex is not accessible from here this function fails - if(!(d1&&d2)) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + if(!(d1 && d2)) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here - if(v1==v2 && isCluster(v1)) { + if(v1 == v2 && isCluster(v1)) { fusion::vector res = getVertexCluster(v1)->addEdge(source, target); - fusion::at_c<3>(res)=false; + fusion::at_c<3> (res) = false; return res; } //check if we already have that Local edge - boost::tie(e,d3) = boost::edge(v1,v2, *this); - if(!d3) boost::tie(e,d3) = boost::add_edge(v1, v2, *this); + boost::tie(e, d3) = boost::edge(v1, v2, *this); + + if(!d3) boost::tie(e, d3) = boost::add_edge(v1, v2, *this); + if(!d3) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); //init the bundle corectly for new edge GlobalEdge global = { source, target, m_id->generate() }; edge_bundle_single s; - fusion::at_c<1>(s) = global; - fusion::at_c<1>((*this)[e]).push_back(s); + fusion::at_c<1> (s) = global; + fusion::at_c<1> ((*this) [e]).push_back(s); setChanged(); return fusion::make_vector(e, global, true, true); @@ -652,12 +992,12 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, **/ std::pair getGlobalEdges(LocalEdge e) { - std::vector& vec = fusion::at_c<1>((*this)[e]); + std::vector& vec = fusion::at_c<1> ((*this) [e]); global_edge_iterator begin = boost::make_transform_iterator(vec.begin(), global_extractor()); global_edge_iterator end = boost::make_transform_iterator(vec.end(), global_extractor()); setChanged(); - return std::pair(begin, end); + return std::pair (begin, end); }; /** @@ -672,7 +1012,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, **/ int getGlobalEdgeCount(LocalEdge e) { - return fusion::at_c<1>((*this)[e]).size(); + return fusion::at_c<1> ((*this) [e]).size(); }; /** @@ -709,7 +1049,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * @return GlobalVertex **/ GlobalVertex getGlobalVertex(LocalVertex v) const { - return fusion::at_c<0>((*this)[v]); + return fusion::at_c<0> ((*this) [v]); }; /** @@ -723,7 +1063,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * @return GlobalVertex which was assigned **/ GlobalVertex setGlobalVertex(LocalVertex lv, GlobalVertex gv) { - fusion::at_c<0>((*this)[lv]) = gv; + fusion::at_c<0> ((*this) [lv]) = gv; return gv; }; @@ -733,11 +1073,11 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * The GlobalVertex has to be in this cluster or any of it's subclusters. If its in a subcluster, the returned * LocalVertex will represent this cluster. If the GlobalVertex is not in this clusters scope the function fails. * - * @param GlobalVertex + * @param vertex GlobalVertex for which the local one shall be returned * @return std::pair< LocalVertex, bool > The LocalVertex containing the global one and an success indicator **/ - std::pair getLocalVertex(GlobalVertex e) { - return getContainingVertex(e); + std::pair getLocalVertex(GlobalVertex vertex) { + return getContainingVertex(vertex); }; /** @@ -770,15 +1110,16 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, apply_remove_prediacte(Functor& f, GlobalEdge e) : func(f), edge(e), vert(0), isEdge(true) {}; bool operator()(edge_bundle_single& e) { bool res; + if(isEdge) - res = (edge==fusion::at_c<1>(e)); + res = (edge == fusion::at_c<1> (e)); else - res = (vert==fusion::at_c<1>(e).source) || (vert==fusion::at_c<1>(e).target); + res = (vert == fusion::at_c<1> (e).source) || (vert == fusion::at_c<1> (e).target); - if(res || vert<0) - func(fusion::at_c<1>(e)); + if(res || vert < 0) + func(fusion::at_c<1> (e)); - return res || vert<0; + return res || vert < 0; } }; @@ -791,24 +1132,27 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, void downstreamRemoveVertex(GlobalVertex v, Functor& f) { std::pair res = getContainingVertex(v); + if(!res.second) return; //TODO:throw //iterate over every edge that connects to the global vertex or the cluster in which it is in std::vector re; //remove edges std::pair it = boost::out_edges(res.first, *this); + for(; it.first != it.second; it.first++) { - std::vector& vec = fusion::at_c<1>((*this)[*(it.first)]); - vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte(f,v)), vec.end()); + std::vector& vec = fusion::at_c<1> ((*this) [* (it.first)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (f, v)), vec.end()); + if(vec.empty()) - re.push_back(*(it.first)); + re.push_back(* (it.first)); }; std::for_each(re.begin(), re.end(), boost::bind(&ClusterGraph::simpleRemoveEdge, this, _1)); //if we have the real vertex here and not only a containing cluster we can delete it if(!isCluster(res.first)) { - boost::clear_vertex(res.first, *this); //just to make sure, should be done already + boost::clear_vertex(res.first, *this); //just to make sure, should be done already boost::remove_vertex(res.first, *this); }; @@ -820,7 +1164,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, void simpleRemoveEdge(LocalEdge e) { boost::remove_edge(e, *this); }; - + public: /** @@ -832,6 +1176,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * need to make sure it's not, as removing a clustervertex will not delete the coresponding cluster. * * @param id Local Vertex which should be removed from the graph + * @param f functor whose operator(GlobalEdge) is called for every removed edge **/ template void removeVertex(LocalVertex id, Functor& f) { @@ -851,6 +1196,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * needs to implement operato()(LocalEdge edge). * * @param id Global Vertex which should be removed from the graph + * @param f functor whose operator(LocalEdge) is called on every removed edge **/ template void removeVertex(GlobalVertex id, Functor& f) { @@ -873,15 +1219,16 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, **/ void removeEdge(GlobalEdge id) { fusion::vector res = getContainingEdgeGraph(id); - if(!fusion::at_c<2>(res)) + + if(!fusion::at_c<2> (res)) return; //TODO:throw placehoder p; - std::vector& vec = fusion::at_c<1>((*fusion::at_c<1>(res))[fusion::at_c<0>(res)]); - vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte(p,id)), vec.end()); + std::vector& vec = fusion::at_c<1> ((*fusion::at_c<1> (res)) [fusion::at_c<0> (res)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (p, id)), vec.end()); if(vec.empty()) - boost::remove_edge(fusion::at_c<0>(res), *fusion::at_c<1>(res)); + boost::remove_edge(fusion::at_c<0> (res), *fusion::at_c<1> (res)); }; /** @@ -891,13 +1238,14 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * operator()(GlobalEdge). If no functor is needed just use boost::remove_edge. * * @param id Global Edge which should be removed from the graph + * @param f functor whoms operator(GlobalEdge) is called * @return bool indicates if the global id could be removed **/ template void removeEdge(LocalEdge id, Functor& f) { - std::vector& vec = fusion::at_c<1>((*this)[id]); - std::for_each(vec.begin(), vec.end(), boost::bind(boost::ref(apply_remove_prediacte(f,-1)),_1)); + std::vector& vec = fusion::at_c<1> ((*this) [id]); + std::for_each(vec.begin(), vec.end(), boost::bind (boost::ref(apply_remove_prediacte (f, -1)), _1)); boost::remove_edge(id, *this); }; @@ -920,37 +1268,42 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //used with vertex bundle type template - typename boost::enable_if::type>, + typename boost::enable_if < boost::is_same::type>, result_type >::type operator()(bundle& p) { - if(Type::value) fusion::for_each(fusion::at_c<2>(p), details::clear_ptr()); + if(Type::value) fusion::for_each(fusion::at_c<2> (p), details::clear_ptr()); + return object_extractor()(p); } //used with edge bundle type and global edge descriptor template - typename boost::enable_if::type>, - boost::is_same >, result_type>::type operator()(bundle& p) { + typename boost::enable_if < mpl::and_ < boost::is_same::type>, + boost::is_same > , result_type >::type operator()(bundle& p) { edge_single_iterator e; //need to search the edge_bundle for the global descriptor - std::vector& ebsv = fusion::at_c<1>(p); - for(edge_single_iterator it= ebsv.begin(); it != ebsv.end(); it++) { + std::vector& ebsv = fusion::at_c<1> (p); + + for(edge_single_iterator it = ebsv.begin(); it != ebsv.end(); it++) { if(global_extractor()(*it) == m_key) { - if(Type::value) fusion::for_each(fusion::at_c<0>(*it), details::clear_ptr()); + if(Type::value) fusion::for_each(fusion::at_c<0> (*it), details::clear_ptr()); + e = it; break; } } + return object_extractor()(*e); } //used with edge bundle type and local edge descriptor template - typename boost::enable_if::type>, - boost::is_same >, result_type>::type operator()(bundle& p) { - if(Type::value) fusion::for_each(fusion::at_c<0>(fusion::at_c<1>(p).front()), details::clear_ptr()); - return object_extractor()(fusion::at_c<1>(p).front()); + typename boost::enable_if < mpl::and_ < boost::is_same::type>, + boost::is_same > , result_type >::type operator()(bundle& p) { + if(Type::value) fusion::for_each(fusion::at_c<0> (fusion::at_c<1> (p).front()), details::clear_ptr()); + + return object_extractor()(fusion::at_c<1> (p).front()); } key m_key; @@ -979,12 +1332,13 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * case, as it can hold many global edges, each with it's own objetcs. Using a LocalEdge as key will * always return the object for the first GlobalEdge. * - * @param local or global Vertex/Edge descriptor for which the object is desired + * @tparam Obj the object type which shall be returned + * @param k local or global Vertex/Edge descriptor for which the object is desired * @return shared_ptr< Obj > the pointer to the desired object **/ template boost::shared_ptr getObject(key k) { - return apply_to_bundle(k, obj_helper(k)); + return apply_to_bundle(k, obj_helper (k)); }; /** @@ -995,13 +1349,14 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * case, as it can hold many global edges, each with it's own objects. Using a LocalEdge as key will * always set the object for the first GlobalEdge. * + * @tparam Obj the object type which shall be set * @param k local or global Vertex/Edge descriptor for which the object should be set * @param val the object which should be stored * @return void **/ template void setObject(key k, boost::shared_ptr val) { - apply_to_bundle(k, obj_helper(k)) = val; + apply_to_bundle(k, obj_helper (k)) = val; setChanged(); }; @@ -1012,16 +1367,17 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * LocalEdge's can hold multiple global ones and the iterators can be used to access a specific object type in * all global edges hold by this local edge. * + * @tparam Obj the object type over which it shall be iterated * @param k the LocalEdge over which all Objects should be iterated. * @return pair< begin, end > the iterator rang from begin (first element) to end (first undefined element) **/ template std::pair< object_iterator, object_iterator > getObjects(LocalEdge k) { - std::vector& vec = fusion::at_c<1>((*this)[k]); + std::vector& vec = fusion::at_c<1> ((*this) [k]); object_iterator begin(vec.begin(), object_extractor()); object_iterator end(vec.end(), object_extractor()); - return std::pair< object_iterator, object_iterator >(begin, end); + return std::pair< object_iterator, object_iterator > (begin, end); }; /** @@ -1032,6 +1388,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * search is specified, all subclusters are searched too, but the cluster is passt to the Functor * first. So make sure a function overload for clusters exist in this case. * + * @tparam Obj the object type for which the functor shall be used * @param f the functor to which all valid objects get passed to. * @param recursive specifies if the subclusters should be searched for objects too **/ @@ -1039,15 +1396,19 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, void for_each(Functor& f, bool recursive = false) { std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { - boost::shared_ptr ptr = getObject(*(it.first)) ; + boost::shared_ptr ptr = getObject (* (it.first)) ; + if(ptr) f(ptr); } std::pair eit = boost::edges(*this); + for(; eit.first != eit.second; eit.first++) { - std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects(*(eit.first)); + std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects (* (eit.first)); + for(; goit.first != goit.second; goit.first++) { if(*goit.first) f(*goit.first); @@ -1056,9 +1417,10 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, if(recursive) { cluster_iterator cit; - for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { f((*cit).second); - (*cit).second->template for_each(f, recursive); + (*cit).second->template for_each (f, recursive); } } }; @@ -1080,24 +1442,28 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, valid_ptr_apply func(f); std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { - typename details::sps::type& seq = fusion::at_c<2>((*this)[*it.first]); + typename details::sps::type& seq = fusion::at_c<2> ((*this) [*it.first]); fusion::for_each(seq, func); } typedef typename std::vector::iterator iter; std::pair eit = boost::edges(*this); + for(; eit.first != eit.second; eit.first++) { - std::vector& vec = fusion::at_c<1>((*this)[*eit.first]); + std::vector& vec = fusion::at_c<1> ((*this) [*eit.first]); + for(iter git = vec.begin(); git != vec.end(); git++) { - typename details::sps::type& seq = fusion::at_c<0>(*git); + typename details::sps::type& seq = fusion::at_c<0> (*git); fusion::for_each(seq, func); } } if(recursive) { cluster_iterator cit; - for(cit=m_clusters.begin(); cit != m_clusters.end(); cit++) { + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { f((*cit).second); (*cit).second->for_each_object(f, recursive); } @@ -1119,21 +1485,21 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, typedef base_type& result_type; typedef typename mpl::find::type vertex_iterator; typedef typename mpl::find::type edge_iterator; - typedef typename mpl::if_::type >, - edge_iterator, vertex_iterator>::type iterator; + typedef typename mpl::if_ < boost::is_same::type >, + edge_iterator, vertex_iterator >::type iterator; BOOST_MPL_ASSERT((mpl::not_::type > >)); //used with vertex bundle type template - typename boost::enable_if::type>, - result_type>::type operator()(bundle& p) { + typename boost::enable_if < boost::is_same::type>, + result_type >::type operator()(bundle& p) { return property_extractor()(p); } //used with edge bundle type template - typename boost::enable_if::type>, - result_type>::type operator()(bundle& p) { + typename boost::enable_if < boost::is_same::type>, + result_type >::type operator()(bundle& p) { return property_extractor()(p); } @@ -1148,12 +1514,13 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * was set before, a default construced will be returned. Accessing the property at a global edge will return * the property of the holding local edge. * - * @param local or global Vertex/Edge descriptor for which the property is desired + * @tparam property the property type which shall be returned + * @param k local or global Vertex/Edge descriptor for which the property is desired * @return property::type& the reference to the desired property **/ template typename property::type& getProperty(key k) { - return apply_to_bundle(k, get_prop_helper(k)); + return apply_to_bundle(k, get_prop_helper (k)); }; /** @@ -1163,36 +1530,39 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * to objects. Setting the property at a local edge is a special case, as it can hold many global edges, * each with it's own propertys. Using a LocalEdge as key will always set the property for the first GlobalEdge. * + * @tparam property the property type which shall be set * @param k local or global Vertex/Edge descriptor for which the property should be set * @param val the property value which should be stored * @return void **/ template void setProperty(key k, typename property::type val) { - apply_to_bundle(k, get_prop_helper(k)) = val; + apply_to_bundle(k, get_prop_helper (k)) = val; setChanged(); }; - + /** * @brief recreate the internal index maps for edges and vertices * * Quite many boost graph algorithms need the indices for vertices and edges which are provided by property - * maps. As we use list, and not vector, as underlaying storage we don't get that property for free and + * maps. As we use list, and not vector, as underlaying storage we don't get that property for free and * need to create it ourself. To ease that procedure the internal property vertex_index_prop and edge_index_prop * can be used as property maps and can be initialized by calling this function. * * @return void **/ void initIndexMaps() { - - //just iterate over all edges and vertices and give them all a unique index + + //just iterate over all edges and vertices and give them all a unique index std::pair vit = boost::vertices(*this); - for(int c=0; vit.first != vit.second; vit.first++, c++) + + for(int c = 0; vit.first != vit.second; vit.first++, c++) setProperty(*vit.first, c); - - std::pair eit = boost::edges(*this); - for(int c=0; eit.first != eit.second; eit.first++, c++) + + std::pair eit = boost::edges(*this); + + for(int c = 0; eit.first != eit.second; eit.first++, c++) setProperty(*eit.first, c); }; @@ -1256,27 +1626,31 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, /* add the later removed edges to the coressponding existing edges * (or create new edges between adjacent vertices of moved vertex and cluster). * also get the edge between cluster and vertex while iterating */ - for(; it.first!=it.second; it.first++) { + for(; it.first != it.second; it.first++) { LocalVertex target = boost::target(*it.first, *this); + if(target != Cluster) { //get or create the edge between the old edge target and the cluster LocalEdge e; bool done; - boost::tie(e,done) = boost::edge(target, Cluster, *this); - if(!done) boost::tie(e,done) = boost::add_edge(target, Cluster, *this); + boost::tie(e, done) = boost::edge(target, Cluster, *this); + + if(!done) boost::tie(e, done) = boost::add_edge(target, Cluster, *this); + //if(!done) TODO: throw - std::vector& ep = fusion::at_c<1>((*this)[*it.first]); - std::vector& nep = fusion::at_c<1>((*this)[e]); + std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); + std::vector& nep = fusion::at_c<1> ((*this) [e]); nep.insert(nep.end(), ep.begin(), ep.end()); } } /* Create new Vertex in Cluster and map the edge to vertices and clusters in the cluster * if a connection existed */ - LocalVertex nv= boost::add_vertex((*this)[v], *cg); + LocalVertex nv = boost::add_vertex((*this) [v], *cg); + //resort cluster parentship if needed if(isCluster(v)) { @@ -1286,8 +1660,10 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, } std::pair moveedge = boost::edge(v, Cluster, *this); + if(moveedge.second) { - std::vector& vec = fusion::at_c<1>((*this)[moveedge.first]); + std::vector& vec = fusion::at_c<1> ((*this) [moveedge.first]); + for(edge_single_iterator i = vec.begin(); i != vec.end(); i++) { //get the global vertex to which the global edge points and find the local vertex holding this @@ -1302,12 +1678,14 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //get or create the edge between the new vertex and the target LocalEdge e; bool done; - boost::tie(e,done) = boost::edge(nv, res.first, *cg); - if(!done) boost::tie(e,done) = boost::add_edge(nv, res.first, *cg); + boost::tie(e, done) = boost::edge(nv, res.first, *cg); + + if(!done) boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); + //if(!done) TODO: throw //push the global edge to the local edge - fusion::at_c<1>((*cg)[e]).push_back(*i); + fusion::at_c<1> ((*cg) [e]).push_back(*i); }; } @@ -1341,8 +1719,9 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //if(isRoot()) TODO:throw //create new vertex - vertex_bundle& vb = (*this)[v]; + vertex_bundle& vb = (*this) [v]; LocalVertex nv = boost::add_vertex(vb, *parent()); + //regrouping if needed if(isCluster(v)) { parent()->m_clusters[nv] = m_clusters[v]; @@ -1350,20 +1729,23 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, m_clusters.erase(v); } - GlobalVertex gv= fusion::at_c<0>(vb); + GlobalVertex gv = fusion::at_c<0> (vb); //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) std::vector edge_vec; LocalVertex this_v = parent()->getClusterVertex(sp_base::shared_from_this()); std::pair it = boost::out_edges(this_v, *parent()); + for(; it.first != it.second; it.first++) { //iterate all global edges and find relevant ones - std::vector& vec = fusion::at_c<1>((*parent())[*it.first]); + std::vector& vec = fusion::at_c<1> ((*parent()) [*it.first]); edge_single_iterator i = vec.begin(); + while(i != vec.end()) { GlobalEdge global = global_extractor()(*i); GlobalVertex target; + //a bit cumbersome to allow cluster moving if(parent()->getContainingVertex(global.source).first == nv) target = global.target; else if(parent()->getContainingVertex(global.target).first == nv) target = global.source; @@ -1377,14 +1759,17 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //get or create the edge between the new vertex and the target LocalEdge e; bool done; - boost::tie(e,done) = boost::edge(nv, res.first, *parent()); - if(!done) boost::tie(e,done) = boost::add_edge(nv, res.first, *parent()); + boost::tie(e, done) = boost::edge(nv, res.first, *parent()); + + if(!done) boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); + //if(!done) TODO: throw //push the global edge bundle to the new local edge and erase it in the old - fusion::at_c<1>((*parent())[e]).push_back(*i); + fusion::at_c<1> ((*parent()) [e]).push_back(*i); i = vec.erase(i); } + //see if we should destroy this edge (no global edges remain in local one) if(vec.empty()) edge_vec.push_back(*it.first); } @@ -1392,10 +1777,12 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //create a edge between new vertex and this cluster and add all global edges from within this cluster it = boost::out_edges(v, *this); LocalEdge e; + if(it.first != it.second) e = boost::add_edge(nv, this_v, *parent()).first; + for(; it.first != it.second; it.first++) { - std::vector& ep = fusion::at_c<1>((*this)[*it.first]); - std::vector& nep = fusion::at_c<1>((*parent())[e]); + std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); + std::vector& nep = fusion::at_c<1> ((*parent()) [e]); nep.insert(nep.end(), ep.begin(), ep.end()); } @@ -1405,7 +1792,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, boost::remove_vertex(v, *this); //it's possible that some local edges in the parent are empty now, let's destroy them - for(std::vector::iterator it=edge_vec.begin(); it!=edge_vec.end(); it++) + for(std::vector::iterator it = edge_vec.begin(); it != edge_vec.end(); it++) boost::remove_edge(*it, *parent()); setChanged(); @@ -1424,7 +1811,7 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, boost::weak_ptr m_parent; details::IDpointer m_id; bool copy_mode; //no changing itself when copying - + /* Searches the global vertex in all local vertices of this graph, and returns the local * one which holds the global vertex. If not successfull the local vertex returned will be @@ -1436,8 +1823,9 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //check all vertices if they are the id std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { - if(id == fusion::at_c<0>((*this)[*it.first])) + if(id == fusion::at_c<0> ((*this) [*it.first])) return std::make_pair(*it.first, true); } @@ -1445,11 +1833,12 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, if(recursive) { for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { std::pair res = ((*it).second)->getContainingVertex(id); + if(res.second) return std::make_pair((*it).first, true); } } - return std::make_pair((LocalVertex)NULL, false); + return std::make_pair((LocalVertex) NULL, false); }; /* Searches the local vertex holding the specified global one in this and all it's subclusters. @@ -1460,27 +1849,28 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, LocalVertex v; bool done; boost::tie(v, done) = getContainingVertex(id); + if(!done) return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); if(isCluster(v) && (getGlobalVertex(v) != id)) return m_clusters[v]->getContainingVertexGraph(id); - else return fusion::make_vector(v,sp_base::shared_from_this(),true); + else return fusion::make_vector(v, sp_base::shared_from_this(), true); }; - + /* Searches the global edge in all local edges of this graph, and returns the local * one which holds the global edge. If not successfull the local edge returned will be * invalid and the bool parameter will be false. * */ std::pair getContainingEdge(GlobalEdge id) { - LocalVertex v1,v2; - bool d1,d2; - boost::tie(v1,d1) = getContainingVertex(id.source, true); - boost::tie(v2,d2) = getContainingVertex(id.target, true); + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(id.source, true); + boost::tie(v2, d2) = getContainingVertex(id.target, true); - if(!((d1&&d2) && (v1!=v2))) return std::make_pair(LocalEdge(), false); + if(!((d1 && d2) && (v1 != v2))) return std::make_pair(LocalEdge(), false); - return boost::edge(v1,v2,*this); + return boost::edge(v1, v2, *this); }; /* Searches the local edge holding the specified global one in this and all it's subclusters. @@ -1488,25 +1878,26 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, * */ fusion::vector getContainingEdgeGraph(GlobalEdge id) { - LocalVertex v1,v2; - bool d1,d2; - boost::tie(v1,d1) = getContainingVertex(id.source, true); - boost::tie(v2,d2) = getContainingVertex(id.target, true); + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(id.source, true); + boost::tie(v2, d2) = getContainingVertex(id.target, true); + + if(!(d1 && d2)) return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); - if(!(d1&&d2)) return fusion::make_vector(LocalEdge(), (ClusterGraph*)NULL, false); - if(v1==v2) return m_clusters[v1]->getContainingEdgeGraph(id); + if(v1 == v2) return m_clusters[v1]->getContainingEdgeGraph(id); - return fusion::make_vector(boost::edge(v1,v2,*this).first, this, true); + return fusion::make_vector(boost::edge(v1, v2, *this).first, this, true); }; template typename functor::result_type apply_to_bundle(LocalVertex k, functor f) { - return f((*this)[k]); + return f((*this) [k]); }; template typename functor::result_type apply_to_bundle(LocalEdge k, functor f) { - return f((*this)[k]); + return f((*this) [k]); }; template @@ -1514,51 +1905,58 @@ class ClusterGraph : public boost::adjacency_list< boost::listS, boost::listS, //check all vertices if they are the id std::pair it = boost::vertices(*this); + for(; it.first != it.second; it.first++) { - vertex_bundle& p = (*this)[*it.first]; - if(k == fusion::at_c<0>(p)) + vertex_bundle& p = (*this) [*it.first]; + + if(k == fusion::at_c<0> (p)) return f(p); } //check all clusters if they have the object fusion::vector, bool> res = getContainingVertexGraph(k); - if(!fusion::at_c<2>(res)) { + + if(!fusion::at_c<2> (res)) { //TODO: Throw (propeties return reference, but cant init a reference temporarily) } - return fusion::at_c<1>(res)->template apply_to_bundle(k, f); + return fusion::at_c<1> (res)->template apply_to_bundle (k, f); }; template typename functor::result_type apply_to_bundle(GlobalEdge k, functor f) { - LocalVertex v1,v2; - bool d1,d2; - boost::tie(v1,d1) = getContainingVertex(k.source); - boost::tie(v2,d2) = getContainingVertex(k.target); + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(k.source); + boost::tie(v2, d2) = getContainingVertex(k.target); - if(!(d1&&d2)) { + if(!(d1 && d2)) { //TODO:Throw } - if((v1==v2) && isCluster(v1)) return m_clusters[v1]->apply_to_bundle(k, f); + if((v1 == v2) && isCluster(v1)) return m_clusters[v1]->apply_to_bundle(k, f); else { LocalEdge e; bool done; - boost::tie(e, done) = boost::edge(v1,v2,*this); + boost::tie(e, done) = boost::edge(v1, v2, *this); //if(!done) TODO: throw, as there has to be a edge! - return f((*this)[e]); + return f((*this) [e]); }; }; public: - //may hold cluster properties which have Eigen3 objects and therefore need alignment - EIGEN_MAKE_ALIGNED_OPERATOR_NEW + //may hold cluster properties which have Eigen3 objects and therefore need alignment + EIGEN_MAKE_ALIGNED_OPERATOR_NEW }; -} //namespace solver +/** @} */ +/** @} */ + +} //namespace dcm + #endif // CLUSTERGRAPH_HPP diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index 961b6a3cba19..7d162823bf55 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -44,10 +44,12 @@ #include #include +#include + #include "traits.hpp" #include "object.hpp" #include "equations.hpp" -#include +#include "geometry.hpp" class T; namespace mpl = boost::mpl; @@ -58,30 +60,59 @@ namespace dcm { namespace detail { //type erasure container for constraints -template -class Constraint : public Object { +template +class Constraint { - typedef typename system_traits::Kernel Kernel; + typedef typename Sys::Kernel Kernel; typedef typename Kernel::number_type Scalar; typedef typename Kernel::DynStride DS; + typedef typename Kernel::MappedEquationSystem MES; - typedef boost::shared_ptr geom_ptr; + typedef boost::shared_ptr > geom_ptr; typedef std::vector > Vec; + //metafunction to create equation from consraint and tags + template + struct equation { + typedef typename C::template type type; + }; + public: - Constraint(Sys& system, geom_ptr f, geom_ptr s); + Constraint(geom_ptr f, geom_ptr s); ~Constraint(); - virtual boost::shared_ptr clone(Sys& newSys); + //workaround until better analysing class is created + // TODO: remove diasable once analyser is available + void disable() { + content->disable(); + }; + std::vector getGenericEquations(); std::vector getGenericConstraints(); std::vector getEquationTypes(); std::vector getConstraintTypes(); + template + void initializeFromTags(ConstraintVector& obj); template void initialize(ConstraintVector& obj); protected: + //initialising from geometry functions + template + void initializeFirstGeometry(ConstraintVector& cv, boost::mpl::false_); + template + void initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_); + template + void initializeSecondGeometry(ConstraintVector& cv, boost::mpl::false_); + template + void initializeSecondGeometry(ConstraintVector& cv, boost::mpl::true_); + template + inline void intitalizeFinalize(ConstraintVector& cv, boost::mpl::false_); + template + inline void intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_); + + int equationCount(); template< typename creator_type> @@ -105,14 +136,14 @@ class Constraint : public Object { struct EquationSet { EquationSet() : m_diff_first(NULL,0,DS(0,0)), m_diff_first_rot(NULL,0,DS(0,0)), m_diff_second(NULL,0,DS(0,0)), m_diff_second_rot(NULL,0,DS(0,0)), - m_residual(NULL,0,DS(0,0)) {}; + m_residual(NULL,0,DS(0,0)), enabled(true) {}; Equation m_eq; typename Kernel::VectorMap m_diff_first, m_diff_first_rot; //first geometry diff typename Kernel::VectorMap m_diff_second, m_diff_second_rot; //second geometry diff typename Kernel::VectorMap m_residual; - bool pure_rotation; + bool pure_rotation, enabled; typedef Equation eq_type; }; @@ -125,6 +156,7 @@ class Constraint : public Object { virtual int equationCount() = 0; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; + virtual void disable() = 0; virtual placeholder* clone() = 0; //some runtime type infos are needed, as we cant access the contents with arbitrary functors @@ -133,6 +165,7 @@ class Constraint : public Object { virtual std::vector getEquationTypes() = 0; virtual std::vector getConstraintTypes() = 0; }; + int value; public: template< typename ConstraintVector, typename EquationVector> @@ -215,6 +248,27 @@ class Constraint : public Object { void operator()(T& val) const; }; + + struct EquationCounter { + int& count; + + EquationCounter(int& c) : count(c) {}; + + template< typename T > + void operator()(T& val) const { + if(val.enabled) + count++; + }; + }; + + //workaround until we have a better analyser class + struct disabler { + template + void operator()(T& val) const { + val.enabled = false; + }; + }; + struct GenericEquations { std::vector& vec; GenericEquations(std::vector& v); @@ -248,8 +302,9 @@ class Constraint : public Object { virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); virtual placeholder* clone(); - virtual int equationCount() { - return mpl::size::value; + virtual int equationCount(); + virtual void disable() { + fusion::for_each(m_sets, disabler()); }; virtual std::vector getGenericEquations(); @@ -259,27 +314,8 @@ class Constraint : public Object { EquationSets m_sets; Objects m_objects; - }; - -protected: - template< typename ConstraintVector > - struct creator : public boost::static_visitor { - - typedef ConstraintVector Objects; - Objects& objects; - - creator(Objects& obj); - - template - struct equation { - typedef typename C::template type type; - }; - - template - void operator()(const T1&, const T2&); - - placeholder* p; - bool need_swap; + protected: + void for_each(EquationSets m_sets, Calculater Calculater); }; placeholder* content; @@ -295,121 +331,111 @@ class Constraint : public Object { /*****************************************************************************************************************/ -template -Constraint::Constraint(Sys& system, geom_ptr f, geom_ptr s) +template +Constraint::Constraint(geom_ptr f, geom_ptr s) : first(f), second(s), content(0) { - this->m_system = &system; //cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); //cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); }; -template -Constraint::~Constraint() { +template +Constraint::~Constraint() { delete content; //first->template disconnectSignal(cf); //second->template disconnectSignal(cs); }; -template -boost::shared_ptr Constraint::clone(Sys& newSys) { +template +template +void Constraint::initializeFromTags(ConstraintVector& v) { - //copy the standart stuff - boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); - np->m_system = &newSys; - //copy the internals - np->content = content->clone(); - //and get the geometry pointers right - if(first) { - GlobalVertex v = first->template getProperty(); - np->first = newSys.m_cluster->template getObject(v); - } - if(second) { - GlobalVertex v = second->template getProperty(); - np->second = newSys.m_cluster->template getObject(v); - } - return np; -}; + typedef tag_order< tag1, tag2 > order; -template -template -void Constraint::initialize(ConstraintVector& obj) { + //transform the constraints into eqautions with the now known types + typedef typename mpl::fold< ConstraintVector, mpl::vector<>, + mpl::push_back > >::type EquationVector; - //first create the new placeholder - creator c(obj); - boost::apply_visitor(c, first->m_geometry, second->m_geometry); + //and build the placeholder + content = new holder(v); - //and now store it - content = c.p; //geometry order needs to be the one needed by equations - if(c.need_swap) + if(order::swapt::value) first.swap(second); +}; + +template +template +void Constraint::initialize(ConstraintVector& cv) { + //use the compile time unrolling to retrieve the geometry tags + initializeFirstGeometry, ConstraintVector>(cv, mpl::true_()); }; -template -int Constraint::equationCount() { +template +int Constraint::equationCount() { return content->equationCount(); }; -template +template template< typename creator_type> -void Constraint::resetType(creator_type& c) { +void Constraint::resetType(creator_type& c) { boost::apply_visitor(c, first->m_geometry, second->m_geometry); content = c.p; if(c.need_swap) first.swap(second); }; -template -void Constraint::calculate(Scalar scale, bool rotation_only) { +template +void Constraint::calculate(Scalar scale, bool rotation_only) { content->calculate(first, second, scale, rotation_only); }; -template -void Constraint::treatLGZ() { +template +void Constraint::treatLGZ() { content->treatLGZ(first, second); }; -template -void Constraint::setMaps(MES& mes) { +template +void Constraint::setMaps(MES& mes) { content->setMaps(mes, first, second); }; -template -void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { +template +void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { content->collectPseudoPoints(first, second, vec1, vec2); }; -template -std::vector Constraint::getGenericEquations() { +template +std::vector Constraint::getGenericEquations() { return content->getGenericEquations(); }; -template -std::vector Constraint::getGenericConstraints() { +template +std::vector Constraint::getGenericConstraints() { return content->getGenericConstraints(); }; -template -std::vector Constraint::getEquationTypes() { +template +std::vector Constraint::getEquationTypes() { return content->getEquationTypes(); }; -template -std::vector Constraint::getConstraintTypes() { +template +std::vector Constraint::getConstraintTypes() { return content->getConstraintTypes(); }; -template +template template -Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; +Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; -template +template template template -typename boost::enable_if::template holder::template has_option::type, void>::type -Constraint::holder::OptionSetter::operator()(EquationSet& val) const { +typename boost::enable_if::template holder::template has_option::type, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { //get the index of the corresbonding equation typedef typename mpl::find::type iterator; @@ -419,25 +445,29 @@ Constraint::holder(objects).pure_rotation; }; -template +template template template -typename boost::enable_if::template holder::template has_option::type>, void>::type -Constraint::holder::OptionSetter::operator()(EquationSet& val) const { +typename boost::enable_if::template holder::template has_option::type>, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { }; -template +template template -Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) +Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) : first(f), second(s), scale(sc), rot_only(rotation_only) { }; -template +template template template< typename T > -void Constraint::holder::Calculater::operator()(T& val) const { +void Constraint::holder::Calculater::operator()(T& val) const { + + //if the equation is disabled we don't have anything mapped so avoid accessing it + if(!val.enabled) + return; //if we only need pure rotational functions and we are not such a nice thing, everything becomes 0 if(rot_only && !val.pure_rotation) { @@ -520,17 +550,20 @@ void Constraint::holder +template template -Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) +Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) : mes(m), first(f), second(s) { }; -template +template template template< typename T > -void Constraint::holder::MapSetter::operator()(T& val) const { +void Constraint::holder::MapSetter::operator()(T& val) const { + + if(!val.enabled) + return; //when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat //for every parameter in the geometry; @@ -555,17 +588,21 @@ void Constraint::holderm_offset, second->m_parameterCount, val.m_diff_second); }; -template +template template -Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) +Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) : first(f), second(s), points1(vec1), points2(vec2) { }; -template +template template template< typename T > -void Constraint::holder::PseudoCollector::operator()(T& val) const { +void Constraint::holder::PseudoCollector::operator()(T& val) const { + + if(!val.enabled) + return; + if(first->m_isInCluster && second->m_isInCluster) { val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); } @@ -581,21 +618,23 @@ void Constraint::holder +template template -Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) +Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) : first(f), second(s) { }; -template +template template template< typename T > -void Constraint::holder::LGZ::operator()(T& val) const { +void Constraint::holder::LGZ::operator()(T& val) const { + if(!val.enabled) + return; + //to treat local gradient zeros we calculate a approximate second derivative of the equations //only do that if neseccary: residual is not zero - Base::Console().Message("res: %f\n", val.m_residual(0)); if(val.m_residual(0) > 1e-7) { //TODO: use exact precission and scale value //rotations exist only in cluster @@ -604,19 +643,19 @@ void Constraint::holderm_parameter + first->m_diffparam.col(i)*1e-3; + const typename Kernel::Vector p_old = first->m_parameter; + first->m_parameter += first->m_diffparam.col(i)*1e-3; + first->normalize(); //with this changed geometrie we test if a gradient exist now typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); - typename Kernel::VectorMap block2(&incr(0),first->m_parameterCount,1, DS(1,1)); - typename Kernel::number_type res = val.m_eq.calculateGradientFirst(block2, + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, second->m_parameter, block); - + first->m_parameter = p_old; + //let's see if the initial LGZ was a real one - Base::Console().Message("approx second: %f\n", res); if(std::abs(res) > 1e-7) { //is a fake zero, let's correct it @@ -631,19 +670,19 @@ void Constraint::holderm_parameter + second->m_diffparam.col(i)*1e-3; + const typename Kernel::Vector p_old = second->m_parameter; + second->m_parameter += second->m_diffparam.col(i)*1e-3; + second->normalize(); //with this changed geometrie we test if a gradient exist now typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); - typename Kernel::VectorMap block2(&incr(0),second->m_parameterCount,1, DS(1,1)); - typename Kernel::number_type res = val.m_eq.calculateGradientFirst(block2, + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, second->m_parameter, block); + second->m_parameter = p_old; //let's see if the initial LGZ was a real one - Base::Console().Message("approx second: %f\n", res); if(std::abs(res) > 1e-7) { //is a fake zero, let's correct it @@ -655,154 +694,225 @@ void Constraint::holder +template template -Constraint::holder::GenericEquations::GenericEquations(std::vector& v) +Constraint::holder::GenericEquations::GenericEquations(std::vector& v) : vec(v) { }; -template +template template template< typename T > -void Constraint::holder::GenericEquations::operator()(T& val) const { +void Constraint::holder::GenericEquations::operator()(T& val) const { vec.push_back(val.m_eq); }; -template +template template -Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) +Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) : vec(v) { }; -template +template template template< typename T > -void Constraint::holder::GenericConstraints::operator()(T& val) const { +void Constraint::holder::GenericConstraints::operator()(T& val) const { vec.push_back(val); }; -template +template template -Constraint::holder::Types::Types(std::vector& v) +Constraint::holder::Types::Types(std::vector& v) : vec(v) { }; -template +template template template< typename T > -void Constraint::holder::Types::operator()(T& val) const { +void Constraint::holder::Types::operator()(T& val) const { vec.push_back(&typeid(T)); }; -template +template template -Constraint::holder::holder(Objects& obj) : m_objects(obj) { +Constraint::holder::holder(Objects& obj) : m_objects(obj) { //set the initial values in the equations fusion::for_each(m_sets, OptionSetter(obj)); }; -template +template template -void Constraint::holder::calculate(geom_ptr first, geom_ptr second, +void Constraint::holder::calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only) { fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only)); }; -template +template template -void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { +void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { fusion::for_each(m_sets, LGZ(first, second)); }; -template +template template -typename Constraint::placeholder* -Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { +typename Constraint::placeholder* +Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); //if(creator.need_swap) first.swap(second); return NULL; }; -template +template template -void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { +void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { fusion::for_each(m_sets, MapSetter(mes, first, second)); }; -template +template template -void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { +void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { fusion::for_each(m_sets, PseudoCollector(f, s, vec1, vec2)); }; -template +template template -typename Constraint::placeholder* -Constraint::holder::clone() { +typename Constraint::placeholder* +Constraint::holder::clone() { return new holder(*this); }; -template +template +template +int Constraint::holder::equationCount() { + int count = 0; + EquationCounter counter(count); + fusion::for_each(m_sets, counter); + return count; +}; + +template template std::vector -Constraint::holder::getGenericEquations() { +Constraint::holder::getGenericEquations() { std::vector vec; fusion::for_each(m_sets, GenericEquations(vec)); return vec; }; -template +template template std::vector -Constraint::holder::getGenericConstraints() { +Constraint::holder::getGenericConstraints() { std::vector vec; fusion::for_each(m_objects, GenericConstraints(vec)); return vec; }; -template +template template std::vector -Constraint::holder::getEquationTypes() { +Constraint::holder::getEquationTypes() { std::vector vec; mpl::for_each< EquationVector >(Types(vec)); return vec; }; -template +template template std::vector -Constraint::holder::getConstraintTypes() { +Constraint::holder::getConstraintTypes() { std::vector vec; mpl::for_each< ConstraintVector >(Types(vec)); return vec; }; -template -template< typename ConstraintVector > -Constraint::creator::creator(Objects& obj) : objects(obj) { +/****************************************************************/ +/** compiletime unrolled geometry initialising */ +/****************************************************************/ + +template +template +void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { + //this function is only for breaking the compilation loop, it should never be called + BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist +}; + +template +template +void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { + + typedef typename Sys::geometries geometries; + + switch(first->getExactType()) { + +#ifdef BOOST_PP_LOCAL_ITERATE +#define BOOST_PP_LOCAL_MACRO(n) \ + case (WhichType::value + n): \ + return initializeSecondGeometry,\ + typename mpl::at_c::type,\ + ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ + break; +#define BOOST_PP_LOCAL_LIMITS (0, 10) +#include BOOST_PP_LOCAL_ITERATE() +#endif //BOOST_PP_LOCAL_ITERATE + default: + typedef typename mpl::int_ next_which_t; + return initializeFirstGeometry (cv, + typename mpl::less< next_which_t, typename mpl::size::type >::type()); + } +}; +template +template +void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { + //this function is only for breaking the compilation loop, it should never be called + BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist +}; + +template +template +void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { + + typedef typename Sys::geometries geometries; + switch(second->getExactType()) { + +#ifdef BOOST_PP_LOCAL_ITERATE +#define BOOST_PP_LOCAL_MACRO(n) \ + case (WhichType::value + n): \ + return intitalizeFinalize::type,\ + ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ + break; +#define BOOST_PP_LOCAL_LIMITS (0, 10) +#include BOOST_PP_LOCAL_ITERATE() +#endif //BOOST_PP_LOCAL_ITERATE + default: + typedef typename mpl::int_ next_which_t; + return initializeSecondGeometry + (cv, typename mpl::less + < next_which_t + , typename mpl::size::type>::type() + ); + } }; -template -template< typename ConstraintVector > -template -void Constraint::creator::operator()(const T1&, const T2&) { +template +template +inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_ /*is_unrolled_t*/) { - typedef tag_order< typename geometry_traits::tag, typename geometry_traits::tag > order; + initializeFromTags(cv); +}; - //transform the constraints into eqautions with the now known types - typedef typename mpl::fold< ConstraintVector, mpl::vector<>, - mpl::push_back > >::type EquationVector; +template +template +inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::false_ /*is_unrolled_t*/) { + //Should never be here at runtime; only required to block code generation that deref's the sequence out of bounds + BOOST_ASSERT(false); +} - //and build the placeholder - p = new holder(objects); - need_swap = order::swapt::value; -}; };//detail @@ -811,3 +921,5 @@ void Constraint::creator #endif //GCM_CONSTRAINT_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 09c12d0b7e5a..6484b67b309c 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -44,11 +44,6 @@ namespace mpl = boost::mpl; namespace dcm { -//a few exceptions to handle unsupported combinations -struct constraint_error : virtual boost::exception { }; -typedef boost::error_info error_type_first_geometry; -typedef boost::error_info error_type_second_geometry; - struct no_option {}; template diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index a8c5d6746992..4a145cfce494 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -33,7 +33,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -43,7 +45,6 @@ #include -#include "object.hpp" #include "traits.hpp" #include "logging.hpp" #include "transformation.hpp" @@ -53,6 +54,9 @@ namespace fusion = boost::fusion; namespace dcm { +//signal we use for recalculation +struct recalculated {}; + namespace tag { struct undefined { @@ -62,13 +66,73 @@ struct undefined { //we need to order tags, this values make it easy for module tags namespace weight { -struct direction : mpl::int_<0> {}; -struct point : mpl::int_<1> {}; -struct line : mpl::int_<2> {}; -struct plane : mpl::int_<3> {}; -struct cylinder : mpl::int_<4> {}; -} +struct parameter : mpl::int_<0> {}; +struct direction : mpl::int_<1> {}; +struct point : mpl::int_<2> {}; +struct line : mpl::int_<3> {}; +struct segment : mpl::int_<4> {}; +struct circle : mpl::int_<5> {}; +struct arc : mpl::int_<6> {}; +struct ellipse : mpl::int_<7> {}; +struct elliptical_arc : mpl::int_<8> {}; +struct plane : mpl::int_<9> {}; +struct cylinder : mpl::int_<10> {}; } +} // tag + +namespace details { + +struct bg {}; //struct to allow test for basic geometry + +template< typename weight_type, int params, bool rotatable, bool translatable> +struct basic_geometry : public bg { + + typedef mpl::int_ parameters; + typedef typename mpl::if_c, mpl::int_<0> >::type translations; + typedef typename mpl::if_c, mpl::int_<0> >::type rotations; + typedef weight_type weight; + typedef mpl::vector0<> sub_stack; +}; + +//build up stacked geometry. these are geometrys which can be splitted into multiple basic geometries. For +//example lines can be splittet into a point and a direction. Make sure you order the basic geometry in a +//sensible rotation/translation manner. Remember: geometrie is first rotated, than translated. Therefore +//everything that gets rotated and translated needs to be first, than the rotation only stuff, then the +//untransformed. For a line this would be +template +struct stacked2_geometry { + + //be sure we only stack base geometrys + BOOST_MPL_ASSERT((boost::is_base_of< bg, T1 >)); + BOOST_MPL_ASSERT((boost::is_base_of< bg, T2 >)); + + typedef typename mpl::plus::type parameters; + typedef typename mpl::plus::type rotations; + typedef typename mpl::plus::type translations; + typedef weight_type weight; + typedef mpl::vector2 sub_stack; +}; + +template +struct stacked3_geometry { + + //be sure we only stack base geometrys + BOOST_MPL_ASSERT((boost::is_base_of< bg, T1 >)); + BOOST_MPL_ASSERT((boost::is_base_of< bg, T2 >)); + BOOST_MPL_ASSERT((boost::is_base_of< bg, T3 >)); + + typedef typename mpl::plus::type parameters; + typedef typename mpl::plus::type rotations; + typedef typename mpl::plus::type translations; + typedef weight_type weight; + typedef mpl::vector3 sub_stack; +}; +} //details + +namespace tag { +//a parameter is universal, so let's define it here +struct parameter : details::basic_geometry {}; +} //tag struct orderd_bracket_accessor { @@ -124,41 +188,26 @@ struct geometry_clone_traits { }; }; -struct reset {}; //signal namespace +namespace details { -namespace detail { +// the parameter a geometr needs in a mapped equation system need to be managed seperate, as +// we may want to access the same parameter space from different geometries (if they are linked) +// this is done by the parameter space class +template +struct parameter_space { -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -class Geometry : public Object) > >, - mpl::pair) > > , - mpl::pair)> > > > { + void init(typename Kernel::MappedEquationSystem* mes); - typedef mpl::map3< mpl::pair) > >, - mpl::pair) > >, - mpl::pair)> > > Signals; +}; + +template > +class Geometry { - typedef typename boost::make_variant_over< GeometrieTypeList >::type Variant; - typedef Object Base; - typedef typename system_traits::Kernel Kernel; - typedef typename system_traits::Cluster Cluster; typedef typename Kernel::number_type Scalar; typedef typename Kernel::DynStride DS; typedef typename Kernel::template transform_type::type Transform; typedef typename Kernel::template transform_type::diff_type DiffTransform; - struct cloner : boost::static_visitor { - typedef typename boost::make_variant_over< GeometrieTypeList >::type Variant; - - Variant variant; - cloner(Variant& v) : variant(v) {}; - - template - void operator()(T& t) { - variant = geometry_clone_traits()(t); - }; - }; - #ifdef USE_LOGGING protected: src::logger log; @@ -167,23 +216,26 @@ class Geometry : public Object Dimension; - Geometry(Sys& system); - - template - Geometry(const T& geometry, Sys& system); - - template - void set(const T& geometry); + Geometry(); - template - typename Visitor::result_type apply(Visitor& vis) { - return boost::apply_visitor(vis, m_geometry); + //basic ations + template + void setValue(const Eigen::MatrixBase& t) { + init(); + m_global = t; + }; + typename Kernel::Vector& getValue() { + return m_global; }; - - //basic ation void transform(const Transform& t); - virtual boost::shared_ptr clone(Sys& newSys); + int getGeneralType() { + return m_general_type; + }; + + int getExactType() { + return m_exact_type; + }; //allow accessing the internal values in unittests without making them public, //so that access control of the internal classes is not changed and can be tested @@ -212,12 +264,19 @@ class Geometry : public Object + void test_linkTo(boost::shared_ptr< Geometry< Kernel, Dim > > geom, int offset) { + linkTo(geom, offset); + }; + bool test_isLinked() { + return isLinked(); + }; #endif //protected would be the right way, however, visual studio 10 does not find a way to access them even when constraint::holder structs //are declared friend //protected: - Variant m_geometry; //Variant holding the real geometry type + int m_general_type, m_exact_type; //hold the type numbers for easy identification int m_BaseParameterCount; //count of the parameters the variant geometry type needs int m_parameterCount; //count of the used parameters (when in cluster:6, else m_BaseParameterCount) int m_offset, m_offset_rot; //the starting point of our parameters in the math system parameter vector @@ -230,13 +289,16 @@ class Geometry : public Object - void init(const T& t); + template + void init(); void normalize(); - typename Sys::Kernel::VectorMap& getParameterMap(); - void initMap(); + typename Kernel::VectorMap& getParameterMap(); + void initMap(typename Kernel::MappedEquationSystem* mes); + bool isInitialised() { + return m_init; + }; void setClusterMode(bool iscluster, bool isFixed); bool getClusterMode() { @@ -246,22 +308,19 @@ class Geometry : public Object > m_link; - typename Kernel::Vector3 getPoint() { - return m_toplocal.template segment(0); + template + void linkTo(boost::shared_ptr< Geometry< Kernel, Dim, TagList > > geom, int offset); + bool isLinked() { + return m_link!=0; }; - //visitor to write the calculated value into the variant - struct apply_visitor : public boost::static_visitor { + void recalculate(DiffTransform& trans); - apply_visitor(typename Kernel::Vector& v) : value(v) {}; - template - void operator()(T& t) const { - (typename geometry_traits::modell()).template inject::accessor >(t, value); - } - typename Kernel::Vector& value; + typename Kernel::Vector3 getPoint() { + return m_toplocal.template segment(0); }; //use m_value or parametermap as new value, dependend on the solving mode @@ -270,6 +329,11 @@ class Geometry : public Object void transform(const Transform& t, VectorType& vec); void scale(Scalar value); + + //let the derived class decide what happens on significant events + virtual void reset() = 0; + virtual void recalculated() = 0; + virtual void removed() = 0; }; @@ -279,71 +343,37 @@ class Geometry : public Object -Geometry::Geometry(Sys& system) +template< typename Kernel, int Dim, typename TagList> +Geometry::Geometry() : m_isInCluster(false), m_parameter(NULL,0,DS(0,0)), m_clusterFixed(false), m_init(false) { #ifdef USE_LOGGING - log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); + log.add_attribute("Tag", attrs::constant< std::string >("Geometry")); #endif - this->m_system = &system; }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -template -Geometry::Geometry(const T& geometry, Sys& system) - : m_isInCluster(false), m_geometry(geometry), m_parameter(NULL,0,DS(0,0)), - m_clusterFixed(false), m_init(false) { - -#ifdef USE_LOGGING - log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); -#endif - - this->m_system = &system; - init(geometry); -}; - -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -template -void Geometry::set(const T& geometry) { - m_geometry = geometry; - init(geometry); - //Base::template emitSignal( ((Derived*)this)->shared_from_this() ); -}; - -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::transform(const Transform& t) { +template< typename Kernel, int Dim, typename TagList> +void Geometry::transform(const Transform& t) { if(m_isInCluster) transform(t, m_toplocal); - else if(m_init) - transform(t, m_rotated); else - transform(t, m_global); + if(m_init) + transform(t, m_rotated); + else + transform(t, m_global); }; -template -boost::shared_ptr Geometry::clone(Sys& newSys) { - - //copy the standart stuff - boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); - np->m_system = &newSys; - //it's possible that the variant contains pointers, so we need to clone them - cloner clone_fnc(np->m_geometry); - boost::apply_visitor(clone_fnc, m_geometry); - return np; -}; +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::init() { -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -template -void Geometry::init(const T& t) { - - m_BaseParameterCount = geometry_traits::tag::parameters::value; + m_BaseParameterCount = tag::parameters::value; m_parameterCount = m_BaseParameterCount; - m_rotations = geometry_traits::tag::rotations::value; - m_translations = geometry_traits::tag::translations::value; + m_rotations = tag::rotations::value; + m_translations = tag::translations::value; m_toplocal.setZero(m_parameterCount); m_global.resize(m_parameterCount); @@ -353,8 +383,9 @@ void Geometry::init(const T& t) { m_diffparam.resize(m_parameterCount,6); m_diffparam.setZero(); - (typename geometry_traits::modell()).template extract::accessor >(t, m_global); + m_general_type = tag::weight::value; + m_exact_type = mpl::find::type::pos::value; + normalize(); //new value which is not set into parameter, so init is false @@ -366,45 +397,73 @@ void Geometry::init(const T& t) { }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::normalize() { +template< typename Kernel, int Dim, typename TagList> +void Geometry::normalize() { //directions are not nessessarily normalized, but we need to ensure this in cluster mode for(int i=m_translations; i!=m_rotations; i++) m_global.template segment(i*Dim).normalize(); }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -typename Sys::Kernel::VectorMap& Geometry::getParameterMap() { +template< typename Kernel, int Dim, typename TagList> +typename Kernel::VectorMap& Geometry::getParameterMap() { m_isInCluster = false; m_parameterCount = m_BaseParameterCount; return m_parameter; }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::initMap() { - //when direct parameter solving the global value is wanted (as it's the initial rotation*toplocal) - m_parameter = m_global; - m_init = true; +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::linkTo(boost::shared_ptr > geom, int offset) { + + init(); + m_link = geom; + m_link_offset = offset; + m_global = geom->m_global.segment(offset, m_BaseParameterCount); +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::initMap(typename Kernel::MappedEquationSystem* mes) { + + //check should not be needed, but how knows... + if(!m_init) { + + if(!isLinked()) { + m_offset = mes->setParameterMap(m_parameterCount, getParameterMap()); + m_parameter = m_global; + m_init = true; + } + else { + //it's important that the linked geometry is initialised, as we going to access its parameter map + if(!m_link->isInitialised()) + m_link->initMap(mes); + + m_offset = m_link->m_offset + m_link_offset; + new(&getParameterMap()) typename Kernel::VectorMap(&m_link->getParameterMap()(m_link_offset), m_parameterCount, typename Kernel::DynStride(1,1)); + } + } }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::setClusterMode(bool iscluster, bool isFixed) { +template< typename Kernel, int Dim, typename TagList> +void Geometry::setClusterMode(bool iscluster, bool isFixed) { m_isInCluster = iscluster; m_clusterFixed = isFixed; if(iscluster) { //we are in cluster, therfore the parameter map should not point to a solver value but to //the rotated original value; - new(&m_parameter) typename Sys::Kernel::VectorMap(&m_rotated(0), m_parameterCount, DS(1,1)); + new(&m_parameter) typename Kernel::VectorMap(&m_rotated(0), m_parameterCount, DS(1,1)); //the local value is the global one as no transformation was applied yet m_toplocal = m_global; m_rotated = m_global; - } else new(&m_parameter) typename Sys::Kernel::VectorMap(&m_global(0), m_parameterCount, DS(1,1)); + } + else + new(&m_parameter) typename Kernel::VectorMap(&m_global(0), m_parameterCount, DS(1,1)); }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::recalculate(DiffTransform& trans) { - if(!m_isInCluster) return; +template< typename Kernel, int Dim, typename TagList> +void Geometry::recalculate(DiffTransform& trans) { + if(!m_isInCluster) + return; for(int i=0; i!=m_rotations; i++) { //first rotate the original to the transformed value @@ -432,8 +491,8 @@ void Geometry::recalculate(DiffTransform& }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::finishCalculation() { +template< typename Kernel, int Dim, typename TagList> +void Geometry::finishCalculation() { //if fixed nothing needs to be changed if(m_isInCluster) { //recalculate(1.); //remove scaling to get right global value @@ -450,18 +509,16 @@ void Geometry::finishCalculation() { BOOST_LOG(log) << "Finish calculation"; #endif }; - apply_visitor v(m_global); - apply(v); + m_init = false; m_isInCluster = false; - - //emit the signal for recalculation - Base::template emitSignal( ((Derived*)this)->shared_from_this() ); + + recalculated(); }; -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> +template< typename Kernel, int Dim, typename TagList> template -void Geometry::transform(const Transform& t, VectorType& vec) { +void Geometry::transform(const Transform& t, VectorType& vec) { //everything that needs to be translated needs to be fully transformed for(int i=0; i!=m_translations; i++) { @@ -480,8 +537,8 @@ void Geometry::transform(const Transform& #endif } -template< typename Sys, typename Derived, typename GeometrieTypeList, int Dim> -void Geometry::scale(Scalar value) { +template< typename Kernel, int Dim, typename TagList> +void Geometry::scale(Scalar value) { for(int i=0; i!=m_translations; i++) m_parameter.template segment(i*Dim) *= 1./value; diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 1e738ad827e9..2e788f8de55b 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -35,6 +35,8 @@ #include "transformation.hpp" #include "logging.hpp" +#include "defines.hpp" +#include "multimap.hpp" namespace dcm { @@ -47,15 +49,11 @@ struct nothing { //the parameter types enum ParameterType { - general, - rotation, - complete + general, //every non-rotation parameter, therefore every translation and non transformed parameter + rotation, //all rotation parameters + complete //all parameter }; -//all solving related errors -typedef boost::error_info error_message; -struct solving_error : virtual boost::exception { }; - template struct Dogleg { @@ -219,7 +217,6 @@ struct Dogleg { number_type dF=0, dL=0; number_type rho; - //handle possible lgz's if(iter==0) sys.removeLocalGradientZeros(); @@ -492,7 +489,7 @@ struct Kernel { }; virtual void recalculate() = 0; - virtual void removeLocalGradientZeros() = 0; + virtual void removeLocalGradientZeros() = 0; }; @@ -530,3 +527,4 @@ struct Kernel { + diff --git a/src/Mod/Assembly/App/opendcm/core/object.hpp b/src/Mod/Assembly/App/opendcm/core/object.hpp index 3218602d8040..29c70663a9f8 100644 --- a/src/Mod/Assembly/App/opendcm/core/object.hpp +++ b/src/Mod/Assembly/App/opendcm/core/object.hpp @@ -52,6 +52,10 @@ namespace mpl = boost::mpl; namespace fusion = boost::fusion; +/* Preprocessor implementation of emit signal. As we need many overloads with diffrent number of + * templated parameters we use boost preprocessor to do the hard repetive work. The definition and + * implementation are definded first as they need to be known before usage + * */ #define EMIT_ARGUMENTS(z, n, data) \ BOOST_PP_CAT(data, n) @@ -63,16 +67,16 @@ namespace fusion = boost::fusion; void emitSignal( \ BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ ); - + #define EMIT_CALL_DEC(z, n, data) \ - template \ + template \ template < \ typename S \ BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ > \ - void Object::emitSignal( \ - BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ - ) \ + void SignalOwner::emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ) \ { \ typedef typename mpl::find::type iterator; \ typedef typename mpl::distance::type, iterator>::type distance; \ @@ -84,12 +88,68 @@ namespace fusion = boost::fusion; namespace dcm { +/** @defgroup Objects Objects + * + * @brief Concept and functionality of the dcm objects + * + * + **/ + //few standart signal names struct remove {}; -struct recalculated {}; typedef boost::any Connection; +template +struct SignalOwner { + + /** + * @brief Connects a slot to a specified signal. + * + * Slots are boost::functions which get called when the signal is emitted. Any valid boost::function + * which ressembles the signal tyes signature can be registert. It is important that the signal type + * was registerd to this object on creation by the appropriate template parameter. + * + * @tparam S the signal which should be intercepted + * @param function boost::function which resembles the signal type's signature + * @return void + **/ + template + Connection connectSignal(typename mpl::at::type function); + + /** + * @brief Disconnects a slot for a specific signal. + * + * Disconnects a slot so that it dosn't get called at signal emittion. It's important to + * disconnect the slot by the same boost:function it was connected with. + * + * @tparam S the signal type of interest + * @param c connection with which the slot was initialy connected + * @return void + **/ + template + void disconnectSignal(Connection c); + + //with no vararg templates before c++11 we need preprocessor to create the overloads of emit signal we need + BOOST_PP_REPEAT(5, EMIT_CALL_DEF, ~) + +protected: + /*signal handling + * extract all signal types to allow index search (inex search on signal functions would fail as same + * signatures are supported for multiple signals). Create std::vectors to allow multiple slots per signal + * and store these vectors in a fusion::vector for easy access. + * */ + typedef typename mpl::fold < SigMap, mpl::vector<>, + mpl::push_back > >::type sig_name; + typedef typename mpl::fold < SigMap, mpl::vector<>, + mpl::push_back > >::type sig_functions; + typedef typename mpl::fold < sig_functions, mpl::vector<>, + mpl::push_back > >::type sig_vectors; + typedef typename fusion::result_of::as_vector::type Signals; + + Signals m_signals; +}; + /** * @brief Base class for all object types * @@ -103,7 +163,9 @@ typedef boost::any Connection; * \tparam Sig a mpl::map specifing the object's signals by (type - boost::function) pairs **/ template -struct Object : public boost::enable_shared_from_this { +struct Object : public PropertyOwner::type>, + public SignalOwner, + boost::enable_shared_from_this { Object() {}; Object(Sys& system); @@ -120,87 +182,7 @@ struct Object : public boost::enable_shared_from_this { **/ virtual boost::shared_ptr clone(Sys& newSys); - /** - * @brief Access properties - * - * Returns a reference to the propertys actual value. The property type has to be registerd to the - * System type which was given as template parameter to this object. - * @tparam Prop property type which should be accessed - * @return Prop::type& a reference to the properties actual value. - **/ - template - typename Prop::type& getProperty(); - - /** - * @brief Set properties - * - * Set'S the value of a specified property. The property type has to be registerd to the - * System type which was given as template parameter to this object. Note that setProperty(value) - * is equivalent to getProperty() = value. - * @tparam Prop property type which should be setProperty - * @param value value of type Prop::type which should be set in this object - **/ - template - void setProperty(typename Prop::type value); - - /** - * @brief Connects a slot to a specified signal. - * - * Slots are boost::functions which get called when the signal is emitted. Any valid boost::function - * which ressembles the signal tyes signature can be registert. It is important that the signal type - * was registerd to this object on creation by the appropriate template parameter. - * - * @tparam S the signal which should be intercepted - * @param function boost::function which resembles the signal type's signature - * @return void - **/ - template - Connection connectSignal(typename mpl::at::type function); - - /** - * @brief Disconnects a slot for a specific signal. - * - * Disconnects a slot so that it dosn't get called at signal emittion. It's important to - * disconnect the slot by the same boost:function it was connected with. - * - * @tparam S the signal type of interest - * @param function boost::function with which the slot was connected - * @return void - **/ - template - void disconnectSignal(Connection c); - - /*properties - * search the property map of the system class and get the mpl::vector of properties for the - * derived type. It's imortant to not store the properties but their types. These types are - * stored and accessed as fusion vector. - * */ - typedef typename mpl::at::type Mapped; - typedef typename mpl::if_< boost::is_same, mpl::vector0<>, Mapped>::type Sequence; - typedef typename details::pts::type Properties; - - Properties m_properties; Sys* m_system; - -protected: - /*signal handling - * extract all signal types to allow index search (inex search on signal functions would fail as same - * signatures are supported for multiple signals). Create std::vectors to allow multiple slots per signal - * and store these vectors in a fusion::vector for easy access. - * */ - typedef typename mpl::fold< Sig, mpl::vector<>, - mpl::push_back > >::type sig_name; - typedef typename mpl::fold< Sig, mpl::vector<>, - mpl::push_back > >::type sig_functions; - typedef typename mpl::fold< sig_functions, mpl::vector<>, - mpl::push_back > >::type sig_vectors; - typedef typename fusion::result_of::as_vector::type Signals; - - Signals m_signals; - -public: - //with no vararg templates before c++11 we need preprocessor to create the overloads of emit signal we need - BOOST_PP_REPEAT(5, EMIT_CALL_DEF, ~) }; @@ -214,44 +196,29 @@ template Object::Object(Sys& system) : m_system(&system) {}; template -boost::shared_ptr Object::clone(Sys& newSys) { +boost::shared_ptr Object::clone(Sys& newSys) +{ boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); np->m_system = &newSys; return np; }; -template -template -typename Prop::type& Object::getProperty() { - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - return fusion::at(m_properties); -}; - -template -template -void Object::setProperty(typename Prop::type value) { - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - fusion::at(m_properties) = value; -}; - -template +template template -Connection Object::connectSignal(typename mpl::at::type function) { +Connection SignalOwner::connectSignal(typename mpl::at::type function) +{ typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; typedef typename fusion::result_of::value_at::type list_type; list_type& list = fusion::at(m_signals); - return list.insert(list.begin(),function); + return list.insert(list.begin(), function); }; -template +template template -void Object::disconnectSignal(Connection c) { +void SignalOwner::disconnectSignal(Connection c) +{ typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp index b42b1f018f48..1c3e63d363b2 100644 --- a/src/Mod/Assembly/App/opendcm/core/property.hpp +++ b/src/Mod/Assembly/App/opendcm/core/property.hpp @@ -27,21 +27,150 @@ #include #include +#include +#include +#include + #include #include +#include "kernel.hpp" namespace mpl = boost::mpl; namespace fusion = boost::fusion; namespace dcm { +/** @addtogroup Core + * @{ */ + +/** @defgroup Property Properties + * + * @brief Concept and handling of properties for generic data storage and type extension. + * + * Properties are a basic building block of the dcm and fullfill two essential tasks: First, build a + * infrastructure for storing data in any kind of object and second, make this data universally accessible. + * Universally accessible means in this context, that it shall be possible to retrieve data only by + * knowing some kind of identifier. No data type specific get/set functions or access to class members + * should be needed to access the stored values. The usage of identifiers allows to design interfaces + * for properties in a type interchangable way. Therefore no restrictions are imposed on the interface, + * no matter what or how much data is stored. + * + * The connection of data type and identifier is achieved through the property structs, which all follow + * the same concept: Identifier is the struct type, the stored data is exposed as 'type' typedef. The data + * type can be every c++ type (including classes and structs) which is default constructable. They don't need + * to be assignable or copyable by default, thats only nesseccary if you want to change the hole stored + * object by assigning. If not, the data object can be uncopyable and it should be used by + * retrieving it's reference with get-methods. + * + * Propertys are further designed to fit in the concept of compile-time modularisation. To allow the extension + * of all data-holding entitys with new data types, propertys store their own purpose. Thats + * done by extending the property struct with a second typedef which is named kind and which specifies of which + * kind the property is. That means, that this typedef defines when the property shall be used and for which + * context it is designed for. Dependend on the propertys kind, it will be added to diffrent places inside the dcm. + * A property of kind @ref vertex_property will added to vertices, a property of kind @ref object_property to all + * objects and so on. + * + * If the property type is a standart c++ type like int or bool, the defualt value can't be set by using its + * constructor. Therefore a interface for setting default values is added to the property. If you want + * to assign a default value you just need to add a struct default_value which returns the wanted default + * value with the operator(). If you don't want a default value, just don't add the struct. The implementation + * assignes the default value to the property, therefore it should only be used with assignalble types. + * + * + * A property implementation for storing integers at a graph edge with the identifier + * 'test'property' may look like that: + * @code + * struct test_property { + * typedef int type; + * typedef edge_property kind; + * } + * @endcode + * + * The same property with a default value would be implemented like this: + * @code + * struct test_property { + * typedef int type; + * typedef edge_property kind; + * struct default_value { + * int operator()() { + * return 3; + * }; + * }; + * } + * @endcode + * + * + * If you want to use properties in your class you should derive from PropertyOwner class, as it doas all the + * hanling needed and gives you get and set functions which work with the designed identifiers. + * + * @{ */ + +/** + * @brief Exeption for property errors + * + * This exception is thrown when a property related error is detected, for example if a objects is ask for a + * property which it does not own. This exceptions own the error-code range from 300-399. + **/ +struct property_error : virtual boost::exception { }; + +/** + * @brief Identifier for vertex properties + * + * This is a identifier structure for vertex properties. Every property with this struct as 'kind' type + * will be added to all vertices of a cluster. It is accessible through global and local vertex + * descriptors. These properties are intended for use in boost algorithms in combination with + * \ref property_map . + */ struct vertex_property {}; +/** + * @brief Identifier for edge properties + * + * This is a identifier structure for edge properties. Every property with this struct as 'kind' type + * will be added to all local edges of a cluster. It is accessible through local edge + * descriptors, or global one by getting it's holding local edge first. Note that global edges don't + * have properties, as the properties are intended for use inside boost graph algorithms and therefore + * only needed in local edges. @see property_map + */ struct edge_property {}; + +/** + * @brief Identifier for cluster properties + * + * A ClusterGraph has it's own properties, and ever property with this identifier as 'kind' type will be + * added to it. This is intended for internal dcm usage, its possible to give the abstract cluster a meaning + * by adding special properties to it. It can be accessed by special ClusterGraph functions designed for this + * purpose. + **/ struct cluster_property {}; + +/** + *@brief Identifier for general object properties + * + * Aproperty with this struct as 'kind' type will be added to all existing objects, no matter of individual + * type. Use this only for general, sharable properties. To add a property to a single object, use it's + * type as 'kind'. + **/ struct object_property {}; +/** + *@brief Identifier for system setting properties + * + * Aproperty with this struct as 'kind' type will be added to the system class. Use this for user settings, + * which are just properties which are accessed horugh "setting" functions. + **/ +struct setting_property {}; + namespace details { +/** @addtogroup Metafunctions + * @{ + * @brief Get vertex property information + * + * This traits struct is used to get property information regarding ClusterGraph vertices. It + * allows access to the local descriptor, the mpl property sequence and the position, at which the + * fusion property sequence is stored inside the bundle. It's used to allow generic property + * selection in combination with @ref property_selector + **/ template struct vertex_selector { typedef typename boost::graph_traits::vertex_descriptor key_type; @@ -49,6 +178,13 @@ struct vertex_selector { typedef mpl::int_<1> property_distance; }; +/** @brief Get edge property information + * + * This traits struct is used to get property information regarding ClusterGraph edges. It + * allows access to the local descriptor, the mpl property sequence and the position, at which the + * fusion property sequence is stored inside the bundle. It's used to allow generic property + * selection in combination with @ref property_selector + **/ template struct edge_selector { typedef typename boost::graph_traits::edge_descriptor key_type; @@ -56,145 +192,421 @@ struct edge_selector { typedef mpl::int_<0> property_distance; }; +/** + * @brief Select property information trait depending on property type + * + * Allows generic access to property information like descriptor or property sequence by exposing + * a specific selector type ( @ref vertex_selector or @ref edge_selector ) dependend on the supplied + * property. + **/ template< typename Kind, typename Graph> -struct property_selector : public mpl::if_, +struct property_selector : public mpl::if_ < boost::is_same, vertex_selector, edge_selector >::type {}; +/** + * @brief Metafunction to expose the property storage type + **/ template struct property_type { typedef typename T::type type; }; +/** + * @brief Metafunction to expose which kid of property this is + **/ template struct property_kind { typedef typename T::kind type; }; -//property vector to a fusion sequence of the propety types +/** + * @brief Metafunction to get all properties for a given kind from a property sequence + **/ +template +struct properties_by_kind { + + typedef typename mpl::fold, + mpl::if_< + boost::is_same >, + mpl::push_back, + mpl::_1 + > + >::type type; +}; + +/** + * @brief Metafunction to get all properties for a given object from a property sequence. This includes + * the properties with the object types and all general object properties + **/ +template +struct properties_by_object { + + typedef typename properties_by_kind::type object_props; + typedef typename properties_by_kind::type general_props; + typedef typename mpl::fold< object_props, general_props, mpl::push_back >::type type; +}; + +/** + * @brief Metafunction to ensures that a property is in a lists + * + * Checks for the existence of a given Property in the mpl::vector supplied and adds the property if it is not found. + * @tparam List mpl::vector with property types + * @tparam Prop the property which should be in the supplied list + **/ +template +struct ensure_property { + + typedef typename mpl::if_ < + boost::is_same < + typename mpl::find::type, + typename mpl::end::type > , + typename mpl::push_back::type, + List >::type type; +}; + +/** + * @brief Metafunction to ensures that multiple properties are in the lists + * + * Checks for the existence of all Property's given in the mpl::vector supplied and adds the properties if it is not found. + * @tparam List mpl::vector with property types + * @tparam PropList mpl::vector with properties which should be in the supplied list + **/ +template +struct ensure_properties { + + typedef typename mpl::fold < PropList, List, + mpl::if_ < + boost::is_same< mpl::find, mpl::end >, + mpl::push_back, + mpl::_1 + > >::type type; +}; + +/** + * @brief Property vector to a fusion sequence of the propety storage types + * + * Properties are passed around as mpl sequences, mostly vectors. To store actual values, they need to + * be transformed into fusion sequences. However, only the storage type needs to be in the vector, not + * the 'kind' information (as this is only used as meta information for type creation). This struct + * exposes a fusion vector which can hold all property storage types. + **/ template struct pts { //property type sequence typedef typename mpl::transform >::type ptv; typedef typename fusion::result_of::as_vector< ptv >::type type; }; + +/** + * @brief Type traits to detect if the property has a default value + * + * If the user want to provide a default value for a property than he adds a default_value static function. + * To check if the this function is available we add a type traits which searches for this special function. + */ +BOOST_MPL_HAS_XXX_TRAIT_DEF(default_value) + +/**@}*/ + +/** + * @brief Functor to assign default values to property + * + * This functor holds a pointer to the PropertyOwner in question. The operator() get the properties which + * hold a default value and assigns this value to the property the owner holds. + */ +template +struct apply_default { + + PropertyOwner* owner; + apply_default(PropertyOwner* o) : owner(o) {}; + template + void operator()(const T& t) { + owner->template getProperty() = typename T::default_value()(); + }; +}; } +/** @addtogroup Metafunctions + * @{*/ +/** + * @brief Expose if this is a edge property + **/ template -struct is_edge_property : boost::is_same {}; - +struct is_edge_property : boost::is_same {}; +/** + * @brief Expose if this is a vertex property + **/ template -struct is_vertex_property : boost::is_same {}; - +struct is_vertex_property : boost::is_same {}; +/** + * @brief Expose if this is a cluster property + **/ template -struct is_cluster_property : boost::is_same {}; - +struct is_cluster_property : boost::is_same {}; +/** + * @brief Expose if this is a general object property + **/ template -struct is_object_property : boost::is_same {}; - +struct is_object_property : boost::is_same {}; +/**@}*/ + +/** + * @brief Adapter to use dcm vertex and edge properties as boost property_maps in bgl algorithms + * + * Boost graph algorithms use property maps as generic storage for process data. In most cases the user + * needs to provide these maps. The simplest way is to create them on the stack right before their + * usage. If, however, the stored information is of use and one wants to store it permanently, this way + * is not practical. Therefor vertex and edge properties were introduced, they allow to store arbitrary + * information at their entity. To use this in combination with boost graph algorithms, this class can + * be used to expose vertex and edge properties as propertie maps to the boost algorithms. All process + * information is then stored permanently at the relevant position. + **/ template class property_map { public: + //expose boost property map interface types typedef typename dcm::details::property_selector::key_type key_type; typedef typename Property::type value_type; typedef typename Property::type& reference; typedef boost::lvalue_property_map_tag category; + //expose cutom types for easy access typedef Property property; typedef typename dcm::details::property_selector::sequence_type sequence; typedef typename dcm::details::property_selector::property_distance distance; + /** + * @brief Links property map with the ClusterGraph which shall be accessed + * + * As boost graph algorithms work with local descriptors, the property map needs to know in which + * graph they are valid. this graph has to be passed to the map. Of course this has to be the one + * on which the algorithm is used on + * + * @param g shared ptr of the cluster graph on which the algorithm is used + **/ property_map(boost::shared_ptr g) : m_graph(g) { } boost::shared_ptr m_graph; }; +/** + * @brief Parent class for all property holding classes in the dcm + * + * To ease the work with properties this class is provided. It receives all the properties, which shall be + * handled, in a mpl::vector typelist as its template argument. Than easy access to all properties by get + * and set functions is achieved. + * + **/ +template +struct PropertyOwner { + + /** + * @brief Constructor assigning default values + * + * It's important to initialise the property fusion sequences with this constructor + * as much handling has to be done to ensure the users default values are added correctly + **/ + PropertyOwner(); + + /** + * @brief Access properties + * + * Returns a reference to the propertys actual value. The property type has to be owned by this class, + * which means it needs to be in the typelist that was given as template parameter to this class. + * @tparam Prop property type which should be accessed + * @return Prop::type& a reference to the properties actual value. + **/ + template + typename Prop::type& getProperty(); + + /** + * @brief Set properties + * + * Sets the value of a specified property. The property type has to be owned by this class, + * which means it needs to be in the typelist that was given as template parameter to this class. + * Note that setProperty(value) is equivalent to getProperty() = value. + * @tparam Prop property type which should be setProperty + * @param value value of type Prop::type which should be set in this object + **/ + template + void setProperty(typename Prop::type value); + + /* It's imortant to not store the properties but their types. These types are + * stored and accessed as fusion vector. + * */ + typedef PropertyList PropertySequence; + typedef typename details::pts::type Properties; + + Properties m_properties; +}; + +template +void pretty(T t) { + std::cout<<__PRETTY_FUNCTION__< +PropertyOwner::PropertyOwner() { + + //get a vies of all types which have a default value + typedef typename mpl::filter_view >::type view; + //set the default value + details::apply_default func(this); + mpl::for_each(func); + +#if defined(BOOST_MPL_CFG_NO_HAS_XXX) + throw property_error() << boost::errinfo_errno(301) << error_message("no default values supported"); +#endif +}; + +/** + * @brief Convienience spezialisation to ease interaction with system class + * + * Normaly property lists are retrieved from the system class, however, there are no empty lists. If no + * property is supplied for a PropertyOwner derived class, a mpl::void_ type will be retrieved. To + * remove the burdon of checking for that type in the class definition this spezialisation is supplied. + **/ +template<> +struct PropertyOwner { + template + typename Prop::type& getProperty() { + throw property_error() << boost::errinfo_errno(300) << error_message("unknown property type"); + }; + + template + void setProperty(typename Prop::type value) { + throw property_error() << boost::errinfo_errno(300) << error_message("unknown property type"); + }; +}; + +template +template +typename Prop::type& PropertyOwner::getProperty() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at (m_properties); +}; + +template +template +void PropertyOwner::setProperty(typename Prop::type value) { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + fusion::at (m_properties) = value; +}; + + //now create some standart properties //*********************************** +/** + * @brief Dummy property + **/ struct empty_prop { - typedef int kind; - typedef int type; + typedef int kind; + typedef int type; }; //type of a graph cluster +/** + * @brief Add a type to clusters + * + * Allows to specify special types to ClusterGraphs and make a it possibe to distuingish between + * diffrent purposes. The cluster types need to be int. + **/ struct type_prop { //states the type of a cluster typedef cluster_property kind; typedef int type; }; //cluster in graph changed? +/** + * @brief Was the cluster changed? + * + * Adds a boolean to the cluster which indicates if the cluster was changedsince the last + * processing. It should be set to true if vertices and edges were added or removed, Subclusters + * created or deleted and so on. + **/ struct changed_prop { typedef cluster_property kind; typedef bool type; }; -//vertex index for bgl algorithms +/** + * @brief Add an index to vertices + * + * Most boost graph algorithms need a index for vertices, ranging from 0 to vertex count. As this can + * be useful for many other things it is added as vertex property. + **/ struct vertex_index_prop { typedef vertex_property kind; typedef int type; }; -//edge index for bgl algorithms +/** + * @brief Add an index to edges + * + * Most boost graph algorithms need a index for edges, ranging from 0 to edge count. As this can + * be useful for many other things it is added as edge property. + **/ struct edge_index_prop { typedef edge_property kind; typedef int type; }; -//vertex color for bgl algorithms -struct vertex_color_prop { - typedef vertex_property kind; - typedef boost::default_color_type type; -}; -//edge color for bgl algorithms -struct edge_color_prop { - typedef edge_property kind; - typedef boost::default_color_type type; -}; - - -//object id's +/** + * @brief Add an ID to objects + * + * It may be wanted to add identification markers to objects, this property can be used for that. It + * is special, as it takes its storage type as template parameter. This property can therefore not be + * directly accessed with this struct, the template parameter has to be known. + * @tparam T the identifier type + **/ template struct id_prop { typedef object_property kind; typedef T type; }; +/**@}*/ //Property +/**@}*/ //Core } -template -void pretty(T t) { - std::cout<<__PRETTY_FUNCTION__< -typename dcm::property_map::value_type get(const dcm::property_map& map, - typename dcm::property_map::key_type key) { +typename dcm::property_map::value_type get(const dcm::property_map& map, + typename dcm::property_map::key_type key) +{ - typedef dcm::property_map map_t; + typedef dcm::property_map map_t; typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; - return fusion::at(fusion::at::distance>(map.m_graph->operator[](key))); + return fusion::at (fusion::at::distance> (map.m_graph->operator[](key))); }; template -void put(const dcm::property_map& map, - typename dcm::property_map::key_type key, - const typename dcm::property_map::value_type& value) { +void put(const dcm::property_map& map, + typename dcm::property_map::key_type key, + const typename dcm::property_map::value_type& value) +{ - typedef dcm::property_map map_t; + typedef dcm::property_map map_t; typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; - fusion::at(fusion::at::distance>(map.m_graph->operator[](key))) = value; + fusion::at (fusion::at::distance> (map.m_graph->operator[](key))) = value; }; template -typename dcm::property_map::reference at(const dcm::property_map& map, - typename dcm::property_map::key_type key) { - typedef dcm::property_map map_t; +typename dcm::property_map::reference at(const dcm::property_map& map, + typename dcm::property_map::key_type key) +{ + typedef dcm::property_map map_t; typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; - return fusion::at(fusion::at::distance>(map.m_graph->operator[](key))); + return fusion::at (fusion::at::distance> (map.m_graph->operator[](key))); } } diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp index 2b0ac11be6f1..371ddbcc4de5 100644 --- a/src/Mod/Assembly/App/opendcm/core/system.hpp +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -76,12 +76,6 @@ struct obj_fold : mpl::fold< seq, state, boost::is_same< details::property_kind, obj>, is_object_property >, mpl::push_back, mpl::_1 > > {}; -template -struct property_map_fold { - typedef typename mpl::fold< - objects, mpl::map<>, mpl::insert< mpl::_1, mpl::pair< - mpl::_2, details::obj_fold, mpl::_2 > > > >::type type; -}; template struct get_identifier { typedef typename T::Identifier type; @@ -100,6 +94,7 @@ struct EmptyModule { struct inheriter {}; typedef mpl::vector<> properties; typedef mpl::vector<> objects; + typedef mpl::vector<> geometries; typedef Unspecified_Identifier Identifier; static void system_init(T& sys) {}; @@ -153,14 +148,20 @@ class System : public T1::template type< System >::inherit typename details::vector_fold > >::type >::type>::type properties; + + //get all geometries we support + typedef typename details::vector_fold >::type >::type>::type geometries; //make the subcomponent lists of objects and properties - typedef typename details::edge_fold< properties, mpl::vector<> >::type edge_properties; - typedef typename details::vertex_fold< properties, mpl::vector<> >::type vertex_properties; + typedef typename details::edge_fold< properties, + mpl::vector1 >::type edge_properties; + typedef typename details::vertex_fold< properties, + mpl::vector1 >::type vertex_properties; typedef typename details::cluster_fold< properties, - mpl::vector >::type cluster_properties; - - typedef typename details::property_map_fold::type object_properties; + mpl::vector2 >::type cluster_properties; protected: //object storage @@ -178,6 +179,11 @@ class System : public T1::template type< System >::inherit vector.clear(); }; }; + + //we hold our own PropertyOwner which we use for system settings. Don't inherit it as the user + //should not access the settings via the proeprty getter and setter functions. + typedef PropertyOwner::type> SettingOwner; + SettingOwner m_settings; #ifdef USE_LOGGING boost::shared_ptr< sink_t > sink; @@ -267,9 +273,19 @@ class System : public T1::template type< System >::inherit System* s = new System(); s->m_cluster = m_cluster->createCluster().first; s->m_storage = m_storage; - s->m_cluster->template setClusterProperty(details::subcluster); + s->m_cluster->template setProperty(details::subcluster); return s; }; + + template + typename Setting::type& getSetting() { + return m_settings.template getProperty(); + }; + + template + void setSetting(typename Setting::type value){ + m_settings.template setProperty(value); + }; private: struct cloner { @@ -321,3 +337,10 @@ class System : public T1::template type< System >::inherit + + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/traits.hpp b/src/Mod/Assembly/App/opendcm/core/traits.hpp index 1d296f820a5b..e53bebf79282 100644 --- a/src/Mod/Assembly/App/opendcm/core/traits.hpp +++ b/src/Mod/Assembly/App/opendcm/core/traits.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -36,8 +37,8 @@ namespace dcm { template< typename T > struct system_traits { - typedef typename T::Kernel Kernel; - typedef typename T::Cluster Cluster; + //typedef typename T::Kernel Kernel; + //typedef typename T::Cluster Cluster; template struct getModule { @@ -46,7 +47,7 @@ struct system_traits { typedef typename mpl::if_< boost::is_base_of, test1, typename T::Type3 >::type test2; typedef typename mpl::if_< boost::is_base_of, test2, mpl::void_ >::type type; - typedef boost::is_same has_module; + typedef mpl::not_ > has_module; }; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d.hpp b/src/Mod/Assembly/App/opendcm/module3d.hpp index 92206745f3dd..13c3b239657e 100644 --- a/src/Mod/Assembly/App/opendcm/module3d.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d.hpp @@ -33,6 +33,7 @@ #include "module3d/parallel.hpp" #include "module3d/angle.hpp" #include "module3d/coincident.hpp" +#include "module3d/alignment.hpp" #include "module3d/module.hpp" #ifdef DCM_USE_MODULESTATE diff --git a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp index 4c9d7885020d..46067fadba10 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp @@ -61,7 +61,7 @@ inline void calcGradFirstComp(const T& d1, const T& grad) { typename Kernel::number_type norm = d1.norm()*d2.norm(); - const_cast< T& >(grad) = d2/norm - (d1.dot(d2)/std::pow(norm,2))*d1/d1.norm(); + const_cast< T& >(grad) = d2/norm - d1.dot(d2)*d1/(std::pow(d1.norm(),3)*d2.norm()); }; template @@ -70,7 +70,7 @@ inline void calcGradSecondComp(const T& d1, const T& grad) { typename Kernel::number_type norm = d1.norm()*d2.norm(); - const_cast< T& >(grad) = d1/norm - (d1.dot(d2)/std::pow(norm,2))*d2/d2.norm(); + const_cast< T& >(grad) = d1/norm - d1.dot(d2)*d2/(std::pow(d2.norm(),3)*d1.norm()); }; } diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp index 97592cc00c17..1d3be6e6df86 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -29,8 +29,6 @@ #include #include "defines.hpp" -#include "Base/Console.h" - #define MAXFAKTOR 1.2 //the maximal distance allowd by a point normed to the cluster size #define MINFAKTOR 0.8 //the minimal distance allowd by a point normed to the cluster size #define SKALEFAKTOR 1. //the faktor by which the biggest size is multiplied to get the scale value @@ -52,8 +50,8 @@ template struct ClusterMath { public: - typedef typename system_traits::Kernel Kernel; - typedef typename system_traits::Cluster Cluster; + typedef typename Sys::Kernel Kernel; + typedef typename Sys::Cluster Cluster; typedef typename system_traits::template getModule::type module3d; typedef typename module3d::Geometry3D Geometry3D; typedef boost::shared_ptr Geom; @@ -154,7 +152,7 @@ struct ClusterMath { template ClusterMath::ClusterMath() : m_normQ(NULL), m_translation(NULL), init(false) { - m_resetTransform = typename Kernel::Quaternion(1,1,1,1); + m_resetTransform = Eigen::AngleAxisd(M_PI*2./3., Eigen::Vector3d(1,1,1).normalized()); m_shift.setZero(); #ifdef USE_LOGGING @@ -453,8 +451,8 @@ void ClusterMath::mapClusterDownstreamGeometry(boost::shared_ptr c BOOST_LOG(log) << "Map downstream geometry"; #endif - map_downstream down(cluster->template getClusterProperty(), - cluster->template getClusterProperty()); + map_downstream down(cluster->template getProperty(), + cluster->template getProperty()); cluster->template for_each(down, true); //TODO: if one subcluster is fixed the hole cluster should be too, as there are no // dof's remaining between parts and so nothing can be moved when one part is fixed. diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index fd45c6b69fc1..7bc899094a28 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -38,7 +38,7 @@ struct ci_orientation : public Equation { struct type : public PseudoScale { type() { - throw constraint_error() << boost::errinfo_errno(103) << error_message("unsupported geometry in coincidence/alignment orientation constraint") + throw constraint_error() << boost::errinfo_errno(103) << error_message("unsupported geometry in coincidence orientation constraint") << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); }; @@ -113,9 +113,6 @@ struct ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm template< typename Kernel > struct ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D > {}; -template< typename Kernel > -struct ci_orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::cylinder3D > {}; - template< typename Kernel > struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; @@ -132,7 +129,7 @@ struct ci_distance : public Equation { struct type : public PseudoScale { type() { - throw constraint_error() << boost::errinfo_errno(104) << error_message("unsupported geometry in coincidence/alignment distance constraint") + throw constraint_error() << boost::errinfo_errno(104) << error_message("unsupported geometry in coincidence distance constraint") << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); }; @@ -172,22 +169,19 @@ template< typename Kernel > struct ci_distance::type< Kernel, tag::point3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::plane3D > {}; template< typename Kernel > -struct ci_distance::type< Kernel, tag::point3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::cylinder3D > {}; +struct ci_distance::type< Kernel, tag::point3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; template< typename Kernel > struct ci_distance::type< Kernel, tag::line3D, tag::line3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; template< typename Kernel > -struct ci_distance::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::plane3D > {}; - -template< typename Kernel > -struct ci_distance::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::cylinder3D > {}; +struct ci_distance::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::line3D, tag::plane3D > {}; template< typename Kernel > -struct ci_distance::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::plane3D > {}; +struct ci_distance::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; template< typename Kernel > -struct ci_distance::type< Kernel, tag::plane3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::cylinder3D > {}; +struct ci_distance::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Distance::type< Kernel, tag::plane3D, tag::plane3D > {}; template< typename Kernel > struct ci_distance::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Distance::type< Kernel, tag::point3D, tag::line3D > {}; @@ -207,39 +201,8 @@ struct Coincidence : public dcm::constraint_sequence< fusion::vector2< details:: }; }; -struct Alignment : public dcm::constraint_sequence< fusion::vector2< details::ci_distance, details::ci_orientation > > { - //allow to set the distance - Alignment& operator()(Direction val) { - fusion::at_c<1>(*this) = val; - return *this; - }; - Alignment& operator()(double val) { - fusion::at_c<0>(*this) = val; - return *this; - }; - Alignment& operator()(double val1, Direction val2) { - fusion::at_c<0>(*this) = val1; - fusion::at_c<1>(*this) = val2; - return *this; - }; - Alignment& operator()(Direction val1, double val2) { - fusion::at_c<0>(*this) = val2; - fusion::at_c<1>(*this) = val1; - return *this; - }; - Alignment& operator=(Direction val) { - fusion::at_c<1>(*this) = val; - return *this; - }; - Alignment& operator=(double val) { - fusion::at_c<0>(*this) = val; - return *this; - }; -}; - //no standart equation, create our own object static Coincidence coincidence; -static Alignment alignment; }//dcm diff --git a/src/Mod/Assembly/App/opendcm/module3d/defines.hpp b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp index fb49f2cd32cd..60549e18cb36 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/defines.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/defines.hpp @@ -20,8 +20,6 @@ #ifndef GCM_DEFINES_3D_H #define GCM_DEFINES_3D_H -#include - namespace dcm { namespace details { @@ -30,11 +28,6 @@ enum { cluster3D = 100}; struct m3d {}; //base of module3d::type to allow other modules check for it } - -//exception codes are needed by the user -//typedef boost::error_info solver_failure_type; -struct creation_error : virtual boost::exception {}; - } #endif diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp index 273efc7aaa21..08d4bc67aae8 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -411,8 +411,9 @@ struct Distance::type< Kernel, tag::line3D, tag::plane3D > : public Distance::ty #endif typedef typename Kernel::VectorMap Vector; void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { - Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); - g.segment(3,3).setZero(); + typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,grad); + g.segment(3,3).setZero(); }; }; @@ -451,7 +452,8 @@ struct Distance::type< Kernel, tag::plane3D, tag::plane3D > : public Distance::t #endif typedef typename Kernel::VectorMap Vector; void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { - Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,g); + typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,grad); g.segment(3,3).setZero(); }; }; @@ -488,7 +490,8 @@ struct Distance::type< Kernel, tag::plane3D, tag::cylinder3D > : public Distance }; void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { - Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p2,p1,g); + typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); + Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p2,p1,grad); g.segment(3,3).setZero(); g(6) = -1; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp b/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp index 9fedadc8e8a5..6a3531fb58e7 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/geometry.hpp @@ -25,41 +25,13 @@ namespace dcm { namespace tag { -struct point3D { - typedef mpl::int_<3> parameters; - typedef mpl::int_<1> rotations; - typedef mpl::int_<1> translations; - typedef weight::point weight; -}; - -struct direction3D { - typedef mpl::int_<3> parameters; - typedef mpl::int_<1> rotations; - typedef mpl::int_<0> translations; - typedef weight::direction weight; -}; - -struct line3D { - typedef mpl::int_<6> parameters; - typedef mpl::int_<2> rotations; - typedef mpl::int_<1> translations; - typedef weight::line weight; -}; - -struct plane3D { - typedef mpl::int_<6> parameters; - typedef mpl::int_<2> rotations; - typedef mpl::int_<1> translations; - typedef weight::plane weight; -}; +struct point3D : details::basic_geometry {}; +struct direction3D : details::basic_geometry {}; +struct line3D : details::stacked2_geometry {}; +struct plane3D : details::stacked2_geometry {}; +struct cylinder3D : details::stacked3_geometry {}; -struct cylinder3D { - typedef mpl::int_<7> parameters; - typedef mpl::int_<2> rotations; - typedef mpl::int_<1> translations; - typedef weight::cylinder weight; -}; -} +} //tag namespace modell { @@ -155,6 +127,27 @@ namespace modell { } +//dummy accessor +struct dummy_accessor { + + template + Scalar get(T& t) { + return 1; + }; + template + void set(Scalar value, T& t) { + //TODO: throw + }; +}; + +//dummy geometry traits for boost blank, wil bever be used +template<> +struct geometry_traits { + typedef tag::direction3D tag; + typedef modell::XYZ modell; + typedef dummy_accessor accessor; +}; + } #endif //GCM_GEOMETRY_3D_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index a511dbb1e478..b30fedb5c93f 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -40,10 +40,10 @@ #include "opendcm/core.hpp" #include "opendcm/core/object.hpp" +#include "opendcm/core/geometry.hpp" #include "opendcm/core/clustergraph.hpp" #include "opendcm/core/sheduler.hpp" #include "opendcm/core/traits.hpp" -#include "opendcm/core/geometry.hpp" #include "geometry.hpp" #include "distance.hpp" #include "parallel.hpp" @@ -52,6 +52,7 @@ #include "defines.hpp" #include "clustermath.hpp" + namespace mpl = boost::mpl; namespace dcm { @@ -69,6 +70,8 @@ struct distance { namespace dcm { +struct reset {}; //signal name + template struct Module3D { @@ -82,25 +85,106 @@ struct Module3D { typedef boost::shared_ptr Geom; typedef boost::shared_ptr Cons; + typedef mpl::map3< mpl::pair >, + mpl::pair > , + mpl::pair > > GeomSig; typedef mpl::map1< mpl::pair > > ConsSignal; typedef ID Identifier; - typedef Typelist geometry_types; + typedef Typelist geometry_types; typedef details::MES MES; typedef details::SystemSolver SystemSolver; template - class Geometry3D_id : public detail::Geometry { + class Geometry3D_base : public details::Geometry, + public Object { + + typedef details::Geometry Base; + typedef Object ObjBase; + typedef typename Sys::Kernel Kernel; + typedef typename Kernel::number_type Scalar; + + public: + Geometry3D_base(Sys& system); + + template + Geometry3D_base(const T& geometry, Sys& system); + + template + void set(const T& geometry); + + bool holdsType() { + return m_geometry.which()!=0; + }; + int whichType() { + return m_geometry.which()-1; + }; + + template + typename Visitor::result_type apply(Visitor& vis) { + return boost::apply_visitor(vis, m_geometry); + }; + + template + T convertTo() { + T t; + (typename geometry_traits::modell()).template inject::accessor >(t, Base::m_global); + return t; + }; + + virtual boost::shared_ptr clone(Sys& newSys); + + protected: + typedef typename mpl::push_front::type ExtTypeList; + typedef typename boost::make_variant_over< ExtTypeList >::type Variant; + + struct cloner : boost::static_visitor { + typedef typename boost::make_variant_over< ExtTypeList >::type Variant; + + Variant variant; + cloner(Variant& v) : variant(v) {}; + + template + void operator()(T& t) { + variant = geometry_clone_traits()(t); + }; + }; + + //visitor to write the calculated value into the variant + struct apply_visitor : public boost::static_visitor { + + apply_visitor(typename Kernel::Vector& v) : value(v) {}; + template + void operator()(T& t) const { + (typename geometry_traits::modell()).template inject::accessor >(t, value); + } + typename Kernel::Vector& value; + }; - typedef detail::Geometry Base; + Variant m_geometry; //Variant holding the real geometry type + + //override protected event functions to emit signals + void reset(); + void recalculated(); + void removed(); + + friend class Constraint3D; + }; + + template + class Geometry3D_id : public Geometry3D_base { + + typedef Geometry3D_base Base; #ifdef USE_LOGGING attrs::mutable_constant< std::string > log_id; #endif public: - Geometry3D_id(Sys& system); - + Geometry3D_id(Sys& system); + template Geometry3D_id(const T& geometry, Sys& system); @@ -115,12 +199,12 @@ struct Module3D { }; struct Geometry3D : public mpl::if_, - detail::Geometry, Geometry3D_id >::type { + Geometry3D_base, Geometry3D_id >::type { typedef vertex_prop vertex_propertie; Geometry3D(Sys& system); - + template Geometry3D(const T& geometry, Sys& system); @@ -129,17 +213,28 @@ struct Module3D { friend struct details::ClusterMath::map_downstream; friend struct details::SystemSolver; friend struct details::SystemSolver::Rescaler; - friend class detail::Constraint; + friend class inheriter_base; - public: - //the geometry class itself does not hold an aligned eigen object, but maybe the variant - EIGEN_MAKE_ALIGNED_OPERATOR_NEW + public: + //the geometry class itself does not hold an aligned eigen object, but maybe the variant + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + }; + + template + class Constraint3D_base : public detail::Constraint, public Object { + + typedef detail::Constraint CBase; + public: + Constraint3D_base(Sys& system, Geom f, Geom s) : detail::Constraint(f,s), + Object(system) {}; + + virtual boost::shared_ptr clone(Sys& newSys); }; template - class Constraint3D_id : public detail::Constraint { + class Constraint3D_id : public Constraint3D_base { - typedef detail::Constraint base; + typedef Constraint3D_base base; public: Constraint3D_id(Sys& system, Geom f, Geom s); @@ -148,7 +243,7 @@ struct Module3D { }; struct Constraint3D : public mpl::if_, - detail::Constraint, + Constraint3D_base, Constraint3D_id >::type { Constraint3D(Sys& system, Geom first, Geom second); @@ -168,15 +263,28 @@ struct Module3D { T, fusion::vector >::type type; }; + template + struct initalizer : public boost::static_visitor { + + Cons constraint; + covec& cov; + initalizer(Cons c, covec& co) : constraint(c), cov(co) {}; + template + void operator()(const T1& t1, const T2& t2) { + constraint->template initialize< typename geometry_traits::tag, + typename geometry_traits::tag, covec>(cov); + }; + }; + struct set_constraint_option { template - typename boost::enable_if, typename fusion_vec::type >::type + typename boost::enable_if, typename fusion_vec::type >::type operator()(T& val) { return val; }; template - typename boost::disable_if, typename fusion_vec::type >::type + typename boost::disable_if, typename fusion_vec::type >::type operator()(T& val) { typename fusion_vec::type vec; fusion::at_c<0>(vec) = val; @@ -188,6 +296,7 @@ struct Module3D { template Geom createGeometry3D(T geom); + Geom createGeometry3D(); void removeGeometry3D(Geom g); template @@ -207,13 +316,14 @@ struct Module3D { public: template Geom createGeometry3D(T geom, Identifier id); + Geom createGeometry3D(Identifier id); template Cons createConstraint3D(Identifier id, Geom first, Geom second, T constraint1); void removeGeometry3D(Identifier id); void removeConstraint3D(Identifier id); - using inheriter_base::removeGeometry3D; - using inheriter_base::removeConstraint3D; + using inheriter_base::removeGeometry3D; + using inheriter_base::removeConstraint3D; bool hasGeometry3D(Identifier id); Geom getGeometry3D(Identifier id); @@ -241,7 +351,8 @@ struct Module3D { }; typedef mpl::vector4 properties; - typedef mpl::vector objects; + typedef mpl::vector2 objects; + typedef mpl::vector5 geometries; static void system_init(Sys& sys) { sys.m_sheduler.addProcessJob(new SystemSolver()); @@ -295,13 +406,100 @@ typename boost::add_reference::type get(G geom) { /*****************************************************************************************************************/ /*****************************************************************************************************************/ +template +template +template +Module3D::type::Geometry3D_base::Geometry3D_base(Sys& system) + : Object(system) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif +}; + +template +template +template +template +Module3D::type::Geometry3D_base::Geometry3D_base(const T& geometry, Sys& system) + : Object(system) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif + + m_geometry = geometry; + //first init, so that the geometry internal vector has the right size + Base::template init< typename geometry_traits::tag >(); + //now write the value; + (typename geometry_traits::modell()).template extract::accessor >(geometry, Base::getValue()); +}; + +template +template +template +template +void Module3D::type::Geometry3D_base::set(const T& geometry) { + + m_geometry = geometry; + //first init, so that the geometry internal vector has the right size + Base::template init< typename geometry_traits::tag >(); + //now write the value; + (typename geometry_traits::modell()).template extract::accessor >(geometry, Base::getValue()); + + reset(); +}; + +template +template +template +boost::shared_ptr Module3D::type::Geometry3D_base::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //it's possible that the variant contains pointers, so we need to clone them + cloner clone_fnc(np->m_geometry); + boost::apply_visitor(clone_fnc, m_geometry); + return np; +}; + +template +template +template +void Module3D::type::Geometry3D_base::recalculated() { + + apply_visitor v(Base::getValue()); + apply(v); + + ObjBase::template emitSignal(((Derived*)this)->shared_from_this()); +}; + +template +template +template +void Module3D::type::Geometry3D_base::removed() { + + ObjBase::template emitSignal(((Derived*)this)->shared_from_this()); +}; + +template +template +template +void Module3D::type::Geometry3D_base::reset() { + + ObjBase::template emitSignal(((Derived*)this)->shared_from_this()); +}; + template template template Module3D::type::Geometry3D_id::Geometry3D_id(Sys& system) - : detail::Geometry(system) + : Module3D::template type::template Geometry3D_base(system) #ifdef USE_LOGGING - , log_id("No ID") +, log_id("No ID") #endif { @@ -315,9 +513,9 @@ template template template Module3D::type::Geometry3D_id::Geometry3D_id(const T& geometry, Sys& system) - : detail::Geometry(geometry, system) + : Module3D::template type::template Geometry3D_base(geometry, system) #ifdef USE_LOGGING - , log_id("No ID") +, log_id("No ID") #endif { @@ -368,7 +566,7 @@ template template Module3D::type::Geometry3D::Geometry3D(Sys& system) : mpl::if_, - detail::Geometry, + Geometry3D_base, Geometry3D_id >::type(system) { }; @@ -378,16 +576,38 @@ template template Module3D::type::Geometry3D::Geometry3D(const T& geometry, Sys& system) : mpl::if_, - detail::Geometry, + Geometry3D_base, Geometry3D_id >::type(geometry, system) { }; +template +template +template +boost::shared_ptr Module3D::type::Constraint3D_base::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //copy the internals + np->content = CBase::content->clone(); + //and get the geometry pointers right + if(CBase::first) { + GlobalVertex v = boost::static_pointer_cast(CBase::first)->template getProperty(); + np->first = newSys.m_cluster->template getObject(v); + } + if(CBase::second) { + GlobalVertex v = boost::static_pointer_cast(CBase::second)->template getProperty(); + np->second = newSys.m_cluster->template getObject(v); + } + return np; +}; + template template template Module3D::type::Constraint3D_id::Constraint3D_id(Sys& system, Geom f, Geom s) - : detail::Constraint(system, f, s) { + : Constraint3D_base(system, f, s) { }; @@ -410,7 +630,7 @@ template template Module3D::type::Constraint3D::Constraint3D(Sys& system, Geom first, Geom second) : mpl::if_, - detail::Constraint, + Constraint3D_base, Constraint3D_id >::type(system, first, second) { }; @@ -421,6 +641,19 @@ Module3D::type::inheriter_base::inheriter_base() { m_this = ((Sys*) this); }; +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_base::createGeometry3D() { + + Geom g(new Geometry3D(* ((Sys*) this))); + fusion::vector res = m_this->m_cluster->addVertex(); + m_this->m_cluster->template setObject (fusion::at_c<0> (res), g); + g->template setProperty(fusion::at_c<1>(res)); + m_this->push_back(g); + return g; +}; + template template template @@ -466,12 +699,12 @@ Module3D::type::inheriter_base::createConstraint3D(Geom first typedef typename fusion_vec::type covec; //set the objects - covec cv = set_constraint_option()( constraint1 ); + covec cv = set_constraint_option()(constraint1); //now create the constraint Cons c(new Constraint3D(*m_this, first, second)); - //set the type and values - c->template initialize(cv); + //initialize constraint + c->initialize(cv); //add it to the clustergraph fusion::vector res; @@ -518,6 +751,15 @@ Module3D::type::inheriter_id::createGeometry3D(T geom, Identi return g; }; +template +template +typename Module3D::template type::Geom +Module3D::type::inheriter_id::createGeometry3D(Identifier id) { + Geom g = inheriter_base::createGeometry3D(); + g->setIdentifier(id); + return g; +}; + template template void Module3D::type::inheriter_id::removeGeometry3D(Identifier id) { @@ -549,7 +791,8 @@ void Module3D::type::inheriter_id::removeConstraint3D(Identif template template bool Module3D::type::inheriter_id::hasGeometry3D(Identifier id) { - if(getGeometry3D(id)) return true; + if(getGeometry3D(id)) + return true; return false; }; @@ -560,7 +803,8 @@ Module3D::type::inheriter_id::getGeometry3D(Identifier id) { std::vector< Geom >& vec = inheriter_base::m_this->template objectVector(); typedef typename std::vector::iterator iter; for(iter it=vec.begin(); it!=vec.end(); it++) { - if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + if(compare_traits::compare((*it)->getIdentifier(), id)) + return *it; }; return Geom(); }; @@ -568,7 +812,8 @@ Module3D::type::inheriter_id::getGeometry3D(Identifier id) { template template bool Module3D::type::inheriter_id::hasConstraint3D(Identifier id) { - if(getConstraint3D(id)) return true; + if(getConstraint3D(id)) + return true; return false; }; @@ -579,7 +824,8 @@ Module3D::type::inheriter_id::getConstraint3D(Identifier id) std::vector< Cons >& vec = inheriter_base::m_this->template objectVector(); typedef typename std::vector::iterator iter; for(iter it=vec.begin(); it!=vec.end(); it++) { - if(compare_traits::compare((*it)->getIdentifier(), id)) return *it; + if(compare_traits::compare((*it)->getIdentifier(), id)) + return *it; }; return Cons(); }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index 75fc9ff2719d..6c347e5468e8 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -22,6 +22,7 @@ #include "defines.hpp" #include "clustermath.hpp" +#include "opendcm/core/clustergraph.hpp" #include "opendcm/core/sheduler.hpp" #include "opendcm/core/traits.hpp" #include @@ -32,17 +33,14 @@ #include #include -#include "Base/Console.h" -#include - namespace dcm { namespace details { template -struct MES : public system_traits::Kernel::MappedEquationSystem { +struct MES : public Sys::Kernel::MappedEquationSystem { - typedef typename system_traits::Kernel Kernel; - typedef typename system_traits::Cluster Cluster; + typedef typename Sys::Kernel Kernel; + typedef typename Sys::Cluster Cluster; typedef typename system_traits::template getModule::type module3d; typedef typename module3d::Geometry3D Geometry3D; typedef boost::shared_ptr Geom; @@ -51,7 +49,7 @@ struct MES : public system_traits::Kernel::MappedEquationSystem { typedef typename module3d::math_prop math_prop; typedef typename module3d::fix_prop fix_prop; typedef typename Kernel::number_type Scalar; - typedef typename system_traits::Kernel::MappedEquationSystem base; + typedef typename Sys::Kernel::MappedEquationSystem Base; boost::shared_ptr m_cluster; @@ -63,8 +61,8 @@ struct MES : public system_traits::Kernel::MappedEquationSystem { template struct SystemSolver : public Job { - typedef typename system_traits::Cluster Cluster; - typedef typename system_traits::Kernel Kernel; + typedef typename Sys::Cluster Cluster; + typedef typename Sys::Kernel Kernel; typedef typename Kernel::number_type Scalar; typedef typename system_traits::template getModule::type module3d; typedef typename module3d::Geometry3D Geometry3D; @@ -127,7 +125,7 @@ struct SystemSolver : public Job { template -MES::MES(boost::shared_ptr cl, int par, int eqn) : base(par, eqn), m_cluster(cl) { +MES::MES(boost::shared_ptr cl, int par, int eqn) : Base(par, eqn), m_cluster(cl) { }; @@ -139,8 +137,8 @@ void MES::recalculate() { std::pair cit = m_cluster->clusters(); for(; cit.first != cit.second; cit.first++) { - if(!(*cit.first).second->template getClusterProperty()) - (*cit.first).second->template getClusterProperty().recalculate(); + if(!(*cit.first).second->template getProperty()) + (*cit.first).second->template getProperty().recalculate(); }; @@ -154,7 +152,7 @@ void MES::recalculate() { std::pair< oiter, oiter > oit = m_cluster->template getObjects(*eit.first); for(; oit.first != oit.second; oit.first++) { if(*oit.first) - (*oit.first)->calculate(base::Scaling, base::rot_only); + (*oit.first)->calculate(Base::Scaling, Base::rot_only); } } }; @@ -162,7 +160,6 @@ void MES::recalculate() { template void MES::removeLocalGradientZeros() { - Base::Console().Message("remove local gradient zero\n"); //let the constraints treat the local zeros typedef typename Cluster::template object_iterator oiter; typedef typename boost::graph_traits::edge_iterator eiter; @@ -178,6 +175,7 @@ void MES::removeLocalGradientZeros() { } }; + template SystemSolver::Rescaler::Rescaler(boost::shared_ptr c, Mes& m) : cluster(c), mes(m), rescales(0) { @@ -198,11 +196,11 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() Scalar sc = 0; for(cit = cluster->clusters(); cit.first != cit.second; cit.first++) { //fixed cluster are irrelevant for scaling - if((*cit.first).second->template getClusterProperty()) + if((*cit.first).second->template getProperty()) continue; //get the biggest scale factor - details::ClusterMath& math = (*cit.first).second->template getClusterProperty(); + details::ClusterMath& math = (*cit.first).second->template getProperty(); math.m_pseudo.clear(); collectPseudoPoints(cluster, (*cit.first).first, math.m_pseudo); @@ -219,8 +217,8 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() if(cluster->isCluster(*it.first)) { boost::shared_ptr c = cluster->getVertexCluster(*it.first); - c->template getClusterProperty().applyClusterScale(sc, - c->template getClusterProperty()); + c->template getProperty().applyClusterScale(sc, + c->template getProperty()); } else { Geom g = cluster->template getObject(*it.first); @@ -238,20 +236,20 @@ void SystemSolver::Rescaler::collectPseudoPoints( Eigen::aligned_allocator::Kernel::Vector3> >& vec) { std::vector > vec2; - typedef typename Cluster::template object_iterator c_iter; + typedef typename Cluster::global_edge_iterator c_iter; typedef typename boost::graph_traits::out_edge_iterator e_iter; std::pair it = boost::out_edges(cluster, *parent); for(; it.first != it.second; it.first++) { - std::pair< c_iter, c_iter > cit = parent->template getObjects(*it.first); + std::pair< c_iter, c_iter > cit = parent->template getGlobalEdges(*it.first); for(; cit.first != cit.second; cit.first++) { - Cons c = *(cit.first); + Cons c = parent->template getObject(*cit.first); if(!c) continue; //get the first global vertex and see if we have it in the wanted cluster or not - GlobalVertex v = c->first->template getProperty(); + GlobalVertex v = cit.first->source; std::pair res = parent->getLocalVertex(v); if(!res.second) return; //means the geometry is in non of the clusters which is not allowed @@ -287,8 +285,8 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy for(; cit.first != cit.second; cit.first++) { boost::shared_ptr c = (*cit.first).second; - if(c->template getClusterProperty() && - c->template getClusterProperty() == details::cluster3D) + if(c->template getProperty() && + c->template getProperty() == details::cluster3D) solveCluster(c, sys); } @@ -338,9 +336,9 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy if(cluster->isCluster(*it.first)) { boost::shared_ptr c = cluster->getVertexCluster(*it.first); - details::ClusterMath& cm = c->template getClusterProperty(); + details::ClusterMath& cm = c->template getProperty(); //only get maps and propagate downstream if not fixed - if(!c->template getClusterProperty()) { + if(!c->template getProperty()) { //set norm Quaternion as map to the parameter vector int offset_rot = mes.setParameterMap(cm.getNormQuaternionMap(), rotation); //set translation as map to the parameter vector @@ -363,10 +361,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy } else { Geom g = cluster->template getObject(*it.first); - int offset = mes.setParameterMap(g->m_parameterCount, g->getParameterMap()); - g->m_offset = offset; - //init the parametermap with initial values - g->initMap(); + g->initMap(&mes); } } @@ -404,12 +399,17 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy // always need the full solver power bool has_cycle; cycle_dedector cd(has_cycle); - //create te needed property map, fill it and run the test + //create te needed property maps and fill it property_map vi_map(cluster); - property_map vc_map(cluster); - property_map ec_map(cluster); cluster->initIndexMaps(); - boost::undirected_dfs(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map).vertex_color_map(vc_map).edge_color_map(ec_map)); + typedef std::map< LocalVertex, boost::default_color_type> vcmap; + typedef std::map< LocalEdge, boost::default_color_type> ecmap; + vcmap v_cm; + ecmap e_cm; + boost::associative_property_map< vcmap > v_cpm(v_cm); + boost::associative_property_map< ecmap > e_cpm(e_cm); + + boost::undirected_dfs(*cluster.get(), boost::visitor(cd).vertex_index_map(vi_map).vertex_color_map(v_cpm).edge_color_map(e_cpm)); bool done = false; if(!has_cycle) { @@ -419,7 +419,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //cool, lets do uncylic. first all rotational constraints with rotational parameters mes.setAccess(rotation); mes.setGeneralEquationAccess(false); - //solve can be done without catching exceptions, because this only fails if the system is + //solve can be done without catching exceptions, because this only fails if the system in //unsolvable DummyScaler re; Kernel::solve(mes, re); @@ -465,11 +465,11 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy if(cluster->isCluster(*it.first)) { boost::shared_ptr c = cluster->getVertexCluster(*it.first); if(!cluster->template getSubclusterProperty(*it.first)) - c->template getClusterProperty().finishCalculation(); + c->template getProperty().finishCalculation(); else - c->template getClusterProperty().finishFixCalculation(); + c->template getProperty().finishFixCalculation(); - std::vector& vec = c->template getClusterProperty().getGeometry(); + std::vector& vec = c->template getProperty().getGeometry(); for(typename std::vector::iterator vit = vec.begin(); vit != vec.end(); vit++) (*vit)->finishCalculation(); @@ -481,7 +481,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy } } //we have solved this cluster - cluster->template setClusterProperty(false); + cluster->template setProperty(false); } catch(boost::exception&) { diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp index 38457fec11b7..3cf167a1debc 100644 --- a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -70,8 +70,8 @@ struct ModulePart { typedef typename boost::make_variant_over< Typelist >::type Variant; typedef Object base; - typedef typename system_traits::Kernel Kernel; - typedef typename system_traits::Cluster Cluster; + typedef typename Sys::Kernel Kernel; + typedef typename Sys::Cluster Cluster; typedef typename Kernel::number_type Scalar; typedef typename Kernel::Transform3D Transform; @@ -117,12 +117,9 @@ struct ModulePart { template void set(const T& geometry); - //access the parts transformation template T& get(); - //get the transformation from part local to overall global. In multi layer systems - //this means the successive transformation from this part to the toplevel cluster template T getGlobal(); @@ -187,7 +184,7 @@ struct ModulePart { void setTransformation(const T& geom) { typedef typename system_traits::template getModule::type module3d; - details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); + details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getProperty(); (typename geometry_traits::modell()).template extract::accessor >(geom, cm.getTransform()); @@ -204,7 +201,7 @@ struct ModulePart { void getTransformation(T& geom) { typedef typename system_traits::template getModule::type module3d; - details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getClusterProperty(); + details::ClusterMath& cm = ((Sys*)this)->m_cluster->template getProperty(); (typename geometry_traits::modell()).template inject::accessor >(geom, cm.getTransform()); @@ -215,7 +212,7 @@ struct ModulePart { //function object to emit remove signal too al geometry which is deleted by part deletion struct remover { - typedef typename system_traits::Cluster Cluster; + typedef typename Sys::Cluster Cluster; typedef typename system_traits::template getModule::type module3d; typedef typename module3d::Geometry3D Geometry3D; typedef boost::shared_ptr Geom; @@ -244,11 +241,12 @@ struct ModulePart { typedef mpl::vector0<> properties; typedef mpl::vector1 objects; + typedef mpl::vector0<> geometries; struct PrepareCluster : public Job { - typedef typename system_traits::Cluster Cluster; - typedef typename system_traits::Kernel Kernel; + typedef typename Sys::Cluster Cluster; + typedef typename Sys::Kernel Kernel; typedef typename system_traits::template getModule::type module3d; PrepareCluster(); @@ -257,8 +255,8 @@ struct ModulePart { struct EvaljuateCluster : public Job { - typedef typename system_traits::Cluster Cluster; - typedef typename system_traits::Kernel Kernel; + typedef typename Sys::Cluster Cluster; + typedef typename Sys::Kernel Kernel; typedef typename system_traits::template getModule::type module3d; EvaljuateCluster(); @@ -286,10 +284,10 @@ ModulePart::type::Part_base::Part_base(const T& geometry, Sys (typename geometry_traits::modell()).template extract::accessor >(geometry, m_transform); - cluster->template setClusterProperty(false); + cluster->template setProperty(false); //the the clustermath transform - m_cluster->template getClusterProperty().getTransform() = m_transform; + m_cluster->template getProperty().getTransform() = m_transform; #ifdef USE_LOGGING BOOST_LOG(log) << "Init: "< typename ModulePart::template type::Part_base::Geom ModulePart::type::Part_base::addGeometry3D(const T& geom, CoordinateFrame frame) { Geom g(new Geometry3D(geom, *m_system)); - if(frame == Local) { //we need to collect all transforms up to this part! - Transform t; + Transform t;//(m_transform); transform_traverse(t, m_cluster); g->transform(t); @@ -328,10 +325,10 @@ ModulePart::type::Part_base::addGeometry3D(const T& geom, Coo template template -void ModulePart::type::Part_base::transform_traverse(typename ModulePart::template type::Part_base::Transform& t, - boost::shared_ptr::template type::Part_base::Cluster> c) { +void ModulePart::type::Part_base::transform_traverse(ModulePart::type::Part_base::Transform& t, + boost::shared_ptr::type::Part_base::Cluster> c) { - t *= c->template getClusterProperty().m_transform; + t *= c->template getProperty().m_transform; if(c->isRoot()) return; @@ -349,6 +346,7 @@ void ModulePart::type::Part_base::set(const T& geometry) { //set the clustermath transform m_cluster->template getClusterProperty().getTransform() = m_transform; + }; template @@ -419,7 +417,7 @@ void ModulePart::type::Part_base::finishCalculation() { template template void ModulePart::type::Part_base::fix(bool fix_value) { - m_cluster->template setClusterProperty(fix_value); + m_cluster->template setProperty(fix_value); }; template @@ -502,14 +500,14 @@ template typename ModulePart::template type::Partptr ModulePart::type::inheriter_base::createPart(const T& geometry) { - typedef typename system_traits::Cluster Cluster; + typedef typename Sys::Cluster Cluster; std::pair, LocalVertex> res = m_this->m_cluster->createCluster(); Partptr p(new Part(geometry, * ((Sys*) this), res.first)); m_this->m_cluster->template setObject (res.second, p); m_this->push_back(p); - res.first->template setClusterProperty(clusterPart); + res.first->template setProperty(clusterPart); return p; }; @@ -598,7 +596,7 @@ void ModulePart::type::PrepareCluster::execute(Sys& sys) { typedef typename std::vector::iterator iter; for(iter it = sys.template begin(); it != sys.template end(); it++) { - details::ClusterMath& cm = (*it)->m_cluster->template getClusterProperty(); + details::ClusterMath& cm = (*it)->m_cluster->template getProperty(); cm.getTransform() = (*it)->m_transform; }; }; @@ -616,7 +614,7 @@ void ModulePart::type::EvaljuateCluster::execute(Sys& sys) { typedef typename std::vector::iterator iter; for(iter it = sys.template begin(); it != sys.template end(); it++) { - details::ClusterMath& cm = (*it)->m_cluster->template getClusterProperty(); + details::ClusterMath& cm = (*it)->m_cluster->template getProperty(); (*it)->m_transform = cm.getTransform(); (*it)->finishCalculation(); }; @@ -629,5 +627,3 @@ void ModulePart::type::EvaljuateCluster::execute(Sys& sys) { - - diff --git a/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp index ad740c7b7f74..22485512b124 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/extractor.hpp @@ -81,7 +81,7 @@ struct Injector { void setClusterProperties(typename Sys::Cluster* cluster, typename details::pts::type& prop) { - cluster->m_cluster_bundle = prop; + cluster->m_properties = prop; }; void setVertexProperties(typename Sys::Cluster* cluster, LocalVertex v, typename details::pts::type& prop) { @@ -101,13 +101,13 @@ struct Injector { fusion::at_c<1>(cluster->operator[](e)) = bundles; }; void setVertexProperty(typename Sys::Cluster* cluster, int value) { - cluster->template setClusterProperty(value); + cluster->template setProperty(value); }; void addClusters(std::vector& clusters, typename Sys::Cluster* cluster) { typename std::vector::iterator it; for(it = clusters.begin(); it != clusters.end(); it++) { - LocalVertex v = cluster->getLocalVertex((*it)->template getClusterProperty()).first; + LocalVertex v = cluster->getLocalVertex((*it)->template getProperty()).first; cluster->m_clusters[v] = boost::shared_ptr(*it); }; }; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp index d55d2c83d7a7..8ab4b53df968 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator.hpp @@ -56,7 +56,7 @@ template struct generator : karma::grammar { typedef typename Sys::Cluster graph; - typedef typename graph::cluster_bundle graph_bundle; + typedef typename graph::Properties graph_bundle; typedef typename boost::graph_traits::vertex_iterator viter; typedef typename boost::graph_traits::edge_iterator eiter; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp index f7bb6bc6bbcf..3dc441ed8e2d 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/generator_imp.hpp @@ -32,7 +32,7 @@ BOOST_FUSION_ADAPT_TPL_STRUCT( (T1)(T2)(T3)(T4), (dcm::ClusterGraph) (T1)(T2)(T3)(T4), (int, test) - (typename dcm::details::pts::type, m_cluster_bundle)) + (typename dcm::details::pts::type, m_properties)) namespace boost { namespace spirit { namespace traits diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp index 9c42fd515733..4a18e6691abf 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator.hpp @@ -21,10 +21,10 @@ namespace details { struct obj_grammar : public karma::grammar()> { typename Gen::generator subrule; karma::rule()> start; - details::prop_gen prop; + details::prop_gen prop; obj_grammar(); - static void getProperties(boost::shared_ptr ptr, typename details::pts::type& seq); + static void getProperties(boost::shared_ptr ptr, typename details::pts::type& seq); }; //when objects should not be generated we need to get a empy rule, as obj_rule_init diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp index df6491e46492..a90fc5536154 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_generator_imp.hpp @@ -29,7 +29,7 @@ obj_grammar::obj_grammar() : obj_grammar::base }; template -void obj_grammar::getProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { +void obj_grammar::getProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { if(ptr) seq = ptr->m_properties; else { diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp index a2d669c3473a..86a5d109651a 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser.hpp @@ -34,11 +34,11 @@ template struct obj_parser : public qi::grammar::type*, Sys*), qi::space_type> { typename Par::parser subrule; qi::rule::type*, Sys*), qi::space_type> start; - prop_par prop; + prop_par prop; obj_parser(); - static void setProperties(boost::shared_ptr ptr, typename details::pts::type& seq); + static void setProperties(boost::shared_ptr ptr, typename details::pts::type& seq); }; //when objects should not be generated we need to get a empy rule, as obj_rule_init diff --git a/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp index 268979c5fd74..0c7a51b13853 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/object_parser_imp.hpp @@ -57,7 +57,7 @@ obj_parser::obj_parser(): obj_parser::base_type(start }; template -void obj_parser::setProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { +void obj_parser::setProperties(boost::shared_ptr ptr, typename details::pts::type& seq) { if(ptr) ptr->m_properties = seq; }; diff --git a/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp index 605c506643ff..22c490dbe946 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/parser_imp.hpp @@ -31,7 +31,7 @@ BOOST_FUSION_ADAPT_TPL_STRUCT( (T1)(T2)(T3)(T4), (dcm::ClusterGraph) (T1)(T2)(T3)(T4), - (typename dcm::details::pts::type, m_cluster_bundle)) + (typename dcm::details::pts::type, m_properties)) #include "parser.hpp" diff --git a/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp index be8956505222..3079b04d20e0 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/property_parser.hpp @@ -59,7 +59,7 @@ struct prop_parser_fold : mpl::fold< seq, state, mpl::push_back > >, mpl::_1 > > {}; -//grammar for a fusion sequence of properties. currently max. 10 properties are supported +//grammar for a fusion sequence of properties. template struct prop_par : qi::grammar::type(), qi::space_type> { From a2359adb2e512e536302a810106a8b7bcb473c9b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 30 Sep 2013 21:50:05 +0200 Subject: [PATCH 212/664] Unify code of Dressup features (part 1: Draft) --- src/Mod/PartDesign/Gui/AppPartDesignGui.cpp | 4 + src/Mod/PartDesign/Gui/CMakeLists.txt | 5 + .../PartDesign/Gui/TaskDraftParameters.cpp | 281 ++++----------- .../Gui/TaskDraftParameters.cpp.orig | 332 ++++++++++++++++++ src/Mod/PartDesign/Gui/TaskDraftParameters.h | 61 +--- .../PartDesign/Gui/TaskDraftParameters.h.orig | 96 +++++ src/Mod/PartDesign/Gui/TaskDraftParameters.ui | 8 +- .../PartDesign/Gui/TaskDressUpParameters.cpp | 252 +++++++++++++ .../PartDesign/Gui/TaskDressUpParameters.h | 112 ++++++ src/Mod/PartDesign/Gui/ViewProviderDraft.cpp | 4 +- src/Mod/PartDesign/Gui/ViewProviderDraft.h | 4 +- .../PartDesign/Gui/ViewProviderDressUp.cpp | 121 +++++++ src/Mod/PartDesign/Gui/ViewProviderDressUp.h | 70 ++++ 13 files changed, 1066 insertions(+), 284 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskDraftParameters.cpp.orig create mode 100644 src/Mod/PartDesign/Gui/TaskDraftParameters.h.orig create mode 100644 src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp create mode 100644 src/Mod/PartDesign/Gui/TaskDressUpParameters.h create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp create mode 100644 src/Mod/PartDesign/Gui/ViewProviderDressUp.h diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index ac2ec7f27563..58e146b835d9 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -41,6 +41,7 @@ #include "ViewProviderChamfer.h" #include "ViewProviderFillet.h" #include "ViewProviderDraft.h" +#include "ViewProviderDressUp.h" #include "ViewProviderRevolution.h" #include "ViewProviderGroove.h" #include "ViewProviderMirrored.h" @@ -48,6 +49,7 @@ #include "ViewProviderPolarPattern.h" #include "ViewProviderScaled.h" #include "ViewProviderMultiTransform.h" +#include "ViewProviderTransformed.h" #include "ViewProviderDatumPoint.h" #include "ViewProviderDatumLine.h" #include "ViewProviderDatumPlane.h" @@ -114,10 +116,12 @@ PyMODINIT_FUNC initPartDesignGui() PartDesignGui::ViewProviderPocket ::init(); PartDesignGui::ViewProviderPad ::init(); PartDesignGui::ViewProviderRevolution ::init(); + PartDesignGui::ViewProviderDressUp ::init(); PartDesignGui::ViewProviderGroove ::init(); PartDesignGui::ViewProviderChamfer ::init(); PartDesignGui::ViewProviderFillet ::init(); PartDesignGui::ViewProviderDraft ::init(); + PartDesignGui::ViewProviderTransformed ::init(); PartDesignGui::ViewProviderMirrored ::init(); PartDesignGui::ViewProviderLinearPattern ::init(); PartDesignGui::ViewProviderPolarPattern ::init(); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 7fa5810d6a38..f294593220c2 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -35,6 +35,7 @@ set(PartDesignGui_MOC_HDRS TaskChamferParameters.h TaskFilletParameters.h TaskDraftParameters.h + TaskDressUpParameters.h TaskHoleParameters.h TaskRevolutionParameters.h TaskGrooveParameters.h @@ -91,6 +92,8 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderFillet.h ViewProviderDraft.cpp ViewProviderDraft.h + ViewProviderDressUp.cpp + ViewProviderDressUp.h ViewProviderRevolution.cpp ViewProviderRevolution.h ViewProviderGroove.cpp @@ -143,6 +146,8 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskDraftParameters.ui TaskDraftParameters.cpp TaskDraftParameters.h + TaskDressUpParameters.cpp + TaskDressUpParameters.h TaskRevolutionParameters.ui TaskRevolutionParameters.cpp TaskRevolutionParameters.h diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index 2bc3ca7d3445..a967509c62b7 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -43,8 +43,6 @@ #include #include #include -#include -#include #include using namespace PartDesignGui; @@ -52,11 +50,9 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskDraftParameters */ -TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("PartDesign_Draft"),tr("Draft parameters"),true, parent),DraftView(DraftView) +TaskDraftParameters::TaskDraftParameters(ViewProviderDressUp *DressUpView,QWidget *parent) + : TaskDressUpParameters(DressUpView, parent) { - selectionMode = none; - // we need a separate container widget to add all controls to proxy = new QWidget(this); ui = new Ui_TaskDraftParameters(); @@ -67,10 +63,10 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p this, SLOT(onAngleChanged(double))); connect(ui->checkReverse, SIGNAL(toggled(bool)), this, SLOT(onReversedChanged(bool))); - connect(ui->buttonFaceAdd, SIGNAL(toggled(bool)), - this, SLOT(onButtonFaceAdd(bool))); - connect(ui->buttonFaceRemove, SIGNAL(toggled(bool)), - this, SLOT(onButtonFaceRemove(bool))); + connect(ui->buttonRefAdd, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefAdd(bool))); + connect(ui->buttonRefRemove, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefRemove(bool))); connect(ui->buttonPlane, SIGNAL(toggled(bool)), this, SLOT(onButtonPlane(bool))); connect(ui->buttonLine, SIGNAL(toggled(bool)), @@ -78,7 +74,7 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p this->groupLayout()->addWidget(proxy); - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); double a = pcDraft->Angle.getValue(); ui->draftAngle->setMinimum(0.0); @@ -93,13 +89,13 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDraft *DraftView,QWidget *p std::vector strings = pcDraft->Base.getSubValues(); for (std::vector::const_iterator i = strings.begin(); i != strings.end(); ++i) { - ui->listWidgetFaces->insertItem(0, QString::fromStdString(*i)); + ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); } // Create context menu QAction* action = new QAction(tr("Remove"), this); - ui->listWidgetFaces->addAction(action); - connect(action, SIGNAL(triggered()), this, SLOT(onFaceDeleted())); - ui->listWidgetFaces->setContextMenuPolicy(Qt::ActionsContextMenu); + ui->listWidgetReferences->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onRefDeleted())); + ui->listWidgetReferences->setContextMenuPolicy(Qt::ActionsContextMenu); App::DocumentObject* ref = pcDraft->NeutralPlane.getValue(); strings = pcDraft->NeutralPlane.getSubValues(); @@ -116,55 +112,15 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) return; if (msg.Type == Gui::SelectionChanges::AddSelection) { - - if (strcmp(msg.pDocName, DraftView->getObject()->getDocument()->getName()) != 0) - return; - - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); - App::DocumentObject* base = this->getBase(); - // TODO: Must we make a copy here instead of assigning to const char* ? - const char* fname = base->getNameInDocument(); - std::string subName(msg.pSubName); - - if ((selectionMode == faceAdd) && (subName.size() > 4 && subName.substr(0,4) == "Face")) { - - if (strcmp(msg.pObjectName, fname) != 0) - return; - - std::vector faces = pcDraft->Base.getSubValues(); - if (std::find(faces.begin(), faces.end(), subName) == faces.end()) { - faces.push_back(subName); - pcDraft->Base.setValue(base, faces); - ui->listWidgetFaces->insertItem(0, QString::fromStdString(subName)); - - clearButtons(NULL); - DraftView->highlightReferences(false); - exitSelectionMode(); - pcDraft->getDocument()->recomputeFeature(pcDraft); - } - } else if ((selectionMode == faceRemove) && (subName.size() > 4 && subName.substr(0,4) == "Face")) { - - if (strcmp(msg.pObjectName, fname) != 0) - return; - - std::vector faces = pcDraft->Base.getSubValues(); - std::vector::iterator f = std::find(faces.begin(), faces.end(), subName); - if (f != faces.end()) { - faces.erase(f); - pcDraft->Base.setValue(base, faces); - QList items = ui->listWidgetFaces->findItems(QString::fromStdString(subName), Qt::MatchExactly); - if (!items.empty()) { - for (QList::const_iterator i = items.begin(); i != items.end(); ++i) { - QListWidgetItem* it = ui->listWidgetFaces->takeItem(ui->listWidgetFaces->row(*i)); - delete it; - } - } - clearButtons(NULL); - DraftView->highlightReferences(false); - exitSelectionMode(); - pcDraft->getDocument()->recomputeFeature(pcDraft); - } - } else if ((selectionMode == plane)) { + if (referenceSelected(msg)) { + if (selectionMode == refAdd) + ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + else + removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); + clearButtons(none); + exitSelectionMode(); + } else if (selectionMode == plane) { + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); std::vector planes; App::DocumentObject* selObj; getReferencedSelection(pcDraft, msg, selObj, planes); @@ -172,9 +128,10 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) ui->linePlane->setText(getRefStr(selObj, planes)); pcDraft->getDocument()->recomputeFeature(pcDraft); - ui->buttonPlane->setChecked(false); + clearButtons(none); exitSelectionMode(); - } else if ((selectionMode == line) && (subName.size() > 4 && subName.substr(0,4) == "Edge")) { + } else if (selectionMode == line) { + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); std::vector edges; App::DocumentObject* selObj; getReferencedSelection(pcDraft, msg, selObj, edges); @@ -182,90 +139,50 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) ui->lineLine->setText(getRefStr(selObj, edges)); pcDraft->getDocument()->recomputeFeature(pcDraft); - ui->buttonLine->setChecked(false); + clearButtons(none); exitSelectionMode(); } } } -void TaskDraftParameters::clearButtons(const QToolButton* notThis) +void TaskDraftParameters::clearButtons(const selectionModes notThis) { - if (ui->buttonFaceAdd != notThis) ui->buttonFaceAdd->setChecked(false); - if (ui->buttonFaceRemove != notThis) ui->buttonFaceRemove->setChecked(false); - if (ui->buttonLine != notThis) ui->buttonLine->setChecked(false); - if (ui->buttonPlane != notThis) ui->buttonPlane->setChecked(false); -} - -void TaskDraftParameters::onButtonFaceAdd(bool checked) -{ - if (checked) { - clearButtons(ui->buttonFaceAdd); - hideObject(); - selectionMode = faceAdd; - Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); - DraftView->highlightReferences(true); - } else { - exitSelectionMode(); - } -} - -void TaskDraftParameters::onButtonFaceRemove(bool checked) -{ - if (checked) { - clearButtons(ui->buttonFaceRemove); - hideObject(); - selectionMode = faceRemove; - Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); - DraftView->highlightReferences(true); - } else { - exitSelectionMode(); - } + if (notThis != refAdd) ui->buttonRefAdd->setChecked(false); + if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); + if (notThis != line) ui->buttonLine->setChecked(false); + if (notThis != plane) ui->buttonPlane->setChecked(false); } void TaskDraftParameters::onButtonPlane(bool checked) { if (checked) { - clearButtons(ui->buttonPlane); + clearButtons(plane); hideObject(); selectionMode = plane; Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), true, true, true)); - } else { - exitSelectionMode(); } } void TaskDraftParameters::onButtonLine(bool checked) { if (checked) { - clearButtons(ui->buttonLine); + clearButtons(line); hideObject(); selectionMode = line; Gui::Selection().clearSelection(); Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), true, false, true)); - } else { - exitSelectionMode(); } } -const std::vector TaskDraftParameters::getFaces(void) const -{ - std::vector result; - for (int i = 0; i < ui->listWidgetFaces->count(); i++) - result.push_back(ui->listWidgetFaces->item(i)->text().toStdString()); - return result; -} - -void TaskDraftParameters::onFaceDeleted(void) +void TaskDraftParameters::onRefDeleted(void) { - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); App::DocumentObject* base = pcDraft->Base.getValue(); std::vector faces = pcDraft->Base.getSubValues(); - faces.erase(faces.begin() + ui->listWidgetFaces->currentRow()); + faces.erase(faces.begin() + ui->listWidgetReferences->currentRow()); pcDraft->Base.setValue(base, faces); - ui->listWidgetFaces->model()->removeRow(ui->listWidgetFaces->currentRow()); + ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); pcDraft->getDocument()->recomputeFeature(pcDraft); } @@ -273,7 +190,7 @@ void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector(1,""); QStringList parts = ui->linePlane->text().split(QChar::fromAscii(':')); - obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + obj = DressUpView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); if (parts.size() > 1) sub[0] = parts[1].toStdString(); } @@ -282,35 +199,15 @@ void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector(1,""); QStringList parts = ui->lineLine->text().split(QChar::fromAscii(':')); - obj = DraftView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + obj = DressUpView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); if (parts.size() > 1) sub[0] = parts[1].toStdString(); } -void TaskDraftParameters::hideObject() -{ - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - App::DocumentObject* base = getBase(); - if (doc != NULL && base != NULL) { - doc->setHide(DraftView->getObject()->getNameInDocument()); - doc->setShow(base->getNameInDocument()); - } -} - -void TaskDraftParameters::showObject() -{ - Gui::Document* doc = Gui::Application::Instance->activeDocument(); - App::DocumentObject* base = getBase(); - if (doc != NULL && base != NULL) { - doc->setShow(DraftView->getObject()->getNameInDocument()); - doc->setHide(base->getNameInDocument()); - } -} - void TaskDraftParameters::onAngleChanged(double angle) { - clearButtons(NULL); - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); + clearButtons(none); + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); pcDraft->Angle.setValue(angle); pcDraft->getDocument()->recomputeFeature(pcDraft); } @@ -321,8 +218,8 @@ const double TaskDraftParameters::getAngle(void) const } void TaskDraftParameters::onReversedChanged(const bool on) { - clearButtons(NULL); - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); + clearButtons(none); + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); pcDraft->Reversed.setValue(on); pcDraft->getDocument()->recomputeFeature(pcDraft); } @@ -332,12 +229,6 @@ const bool TaskDraftParameters::getReversed(void) const return ui->checkReverse->isChecked(); } -App::DocumentObject* TaskDraftParameters::getBase(void) const -{ - PartDesign::Draft* pcDraft = static_cast(DraftView->getObject()); - return pcDraft->Base.getValue(); -} - TaskDraftParameters::~TaskDraftParameters() { Gui::Selection().rmvSelectionGate(); @@ -352,24 +243,16 @@ void TaskDraftParameters::changeEvent(QEvent *e) } } -void TaskDraftParameters::exitSelectionMode() -{ - selectionMode = none; - Gui::Selection().rmvSelectionGate(); - Gui::Selection().clearSelection(); - showObject(); -} //************************************************************************** //************************************************************************** // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgDraftParameters::TaskDlgDraftParameters(ViewProviderDraft *DraftView) - : TaskDialog(),DraftView(DraftView) +TaskDlgDraftParameters::TaskDlgDraftParameters(ViewProviderDraft *DressUpView) + : TaskDlgDressUpParameters(DressUpView) { - assert(DraftView); - parameter = new TaskDraftParameters(DraftView); + parameter = new TaskDraftParameters(DressUpView); Content.push_back(parameter); } @@ -382,19 +265,14 @@ TaskDlgDraftParameters::~TaskDlgDraftParameters() //==== calls from the TaskView =============================================================== -void TaskDlgDraftParameters::open() -{ - // a transaction is already open at creation time of the draft - if (!Gui::Command::hasPendingCommand()) { - QString msg = QObject::tr("Edit draft"); - Gui::Command::openCommand((const char*)msg.toUtf8()); - } -} - -void TaskDlgDraftParameters::clicked(int) -{ - -} +//void TaskDlgDraftParameters::open() +//{ +// // a transaction is already open at creation time of the draft +// if (!Gui::Command::hasPendingCommand()) { +// QString msg = QObject::tr("Edit draft"); +// Gui::Command::openCommand((const char*)msg.toUtf8()); +// } +//} bool TaskDlgDraftParameters::accept() { @@ -403,7 +281,8 @@ bool TaskDlgDraftParameters::accept() // Force the user to select a neutral plane std::vector strings; App::DocumentObject* obj; - parameter->getPlane(obj, strings); + TaskDraftParameters* draftparameter = static_cast(parameter); + draftparameter->getPlane(obj, strings); std::string neutralPlane = getPythonStr(obj, strings); if (neutralPlane.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"), @@ -411,62 +290,22 @@ bool TaskDlgDraftParameters::accept() return false; } - std::string name = DraftView->getObject()->getNameInDocument(); - - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),parameter->getReversed()); - try { - std::vector faces = parameter->getFaces(); - std::stringstream str; - str << "App.ActiveDocument." << name.c_str() << ".Base = (App.ActiveDocument." - << parameter->getBase()->getNameInDocument() << ",["; - for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) - str << "\"" << *it << "\","; - str << "])"; - Gui::Command::doCommand(Gui::Command::Doc,str.str().c_str()); - } - catch (const Base::Exception& e) { - QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); - return false; - } + std::string name = DressUpView->getObject()->getNameInDocument(); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),draftparameter->getAngle()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),draftparameter->getReversed()); if (!neutralPlane.empty()) { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), neutralPlane.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = None", name.c_str()); - parameter->getLine(obj, strings); + draftparameter->getLine(obj, strings); std::string pullDirection = getPythonStr(obj, strings); if (!pullDirection.empty()) { Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), pullDirection.c_str()); } else Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = None", name.c_str()); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - Gui::Command::commitCommand(); - - return true; -} -bool TaskDlgDraftParameters::reject() -{ - // roll back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // Body housekeeping - if (ActivePartObject != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - return true; + return TaskDlgDressUpParameters::accept(); } - - #include "moc_TaskDraftParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp.orig new file mode 100644 index 000000000000..37cd97bfd858 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp.orig @@ -0,0 +1,332 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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 +#endif + +#include "ui_TaskDraftParameters.h" +#include "TaskDraftParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskDraftParameters */ + +TaskDraftParameters::TaskDraftParameters(ViewProviderDressUp *DressUpView,QWidget *parent) + : TaskDressUpParameters(DressUpView, parent) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui_TaskDraftParameters(); + ui->setupUi(proxy); + QMetaObject::connectSlotsByName(this); + + connect(ui->draftAngle, SIGNAL(valueChanged(double)), + this, SLOT(onAngleChanged(double))); + connect(ui->checkReverse, SIGNAL(toggled(bool)), + this, SLOT(onReversedChanged(bool))); + connect(ui->buttonRefAdd, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefAdd(bool))); + connect(ui->buttonRefRemove, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefRemove(bool))); + connect(ui->buttonPlane, SIGNAL(toggled(bool)), + this, SLOT(onButtonPlane(bool))); + connect(ui->buttonLine, SIGNAL(toggled(bool)), + this, SLOT(onButtonLine(bool))); + + this->groupLayout()->addWidget(proxy); + + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + double a = pcDraft->Angle.getValue(); + + ui->draftAngle->setMinimum(0.0); + ui->draftAngle->setMaximum(89.99); + ui->draftAngle->setValue(a); + ui->draftAngle->selectAll(); + QMetaObject::invokeMethod(ui->draftAngle, "setFocus", Qt::QueuedConnection); + + bool r = pcDraft->Reversed.getValue(); + ui->checkReverse->setChecked(r); + + std::vector strings = pcDraft->Base.getSubValues(); + for (std::vector::const_iterator i = strings.begin(); i != strings.end(); ++i) + { + ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); + } + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetReferences->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onRefDeleted())); + ui->listWidgetReferences->setContextMenuPolicy(Qt::ActionsContextMenu); + + App::DocumentObject* ref = pcDraft->NeutralPlane.getValue(); + strings = pcDraft->NeutralPlane.getSubValues(); + ui->linePlane->setText(getRefStr(ref, strings)); + + ref = pcDraft->PullDirection.getValue(); + strings = pcDraft->PullDirection.getSubValues(); + ui->lineLine->setText(getRefStr(ref, strings)); +} + +void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == none) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (referenceSelected(msg)) { + if (selectionMode == refAdd) + ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + else + removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); + clearButtons(none); + exitSelectionMode(); + } else if (selectionMode == plane) { + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + std::vector planes; + App::DocumentObject* selObj; + getReferencedSelection(pcDraft, msg, selObj, planes); + pcDraft->NeutralPlane.setValue(selObj, planes); + ui->linePlane->setText(getRefStr(selObj, planes)); + + pcDraft->getDocument()->recomputeFeature(pcDraft); + clearButtons(none); + exitSelectionMode(); + } else if (selectionMode == line) { + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + std::vector edges; + App::DocumentObject* selObj; + getReferencedSelection(pcDraft, msg, selObj, edges); + pcDraft->PullDirection.setValue(selObj, edges); + ui->lineLine->setText(getRefStr(selObj, edges)); + + pcDraft->getDocument()->recomputeFeature(pcDraft); + clearButtons(none); + exitSelectionMode(); + } + } +} + +void TaskDraftParameters::clearButtons(const selectionModes notThis) +{ + if (notThis != refAdd) ui->buttonRefAdd->setChecked(false); + if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); + if (notThis != line) ui->buttonLine->setChecked(false); + if (notThis != plane) ui->buttonPlane->setChecked(false); +} + +void TaskDraftParameters::onButtonPlane(bool checked) +{ + if (checked) { + clearButtons(plane); + hideObject(); + selectionMode = plane; + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), true, true, true)); + } +} + +void TaskDraftParameters::onButtonLine(bool checked) +{ + if (checked) { + clearButtons(line); + hideObject(); + selectionMode = line; + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), true, false, true)); + } +} + +void TaskDraftParameters::onRefDeleted(void) +{ + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + App::DocumentObject* base = pcDraft->Base.getValue(); + std::vector faces = pcDraft->Base.getSubValues(); + faces.erase(faces.begin() + ui->listWidgetReferences->currentRow()); + pcDraft->Base.setValue(base, faces); + ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); + pcDraft->getDocument()->recomputeFeature(pcDraft); +} + +void TaskDraftParameters::getPlane(App::DocumentObject*& obj, std::vector& sub) const +{ + sub = std::vector(1,""); + QStringList parts = ui->linePlane->text().split(QChar::fromAscii(':')); + obj = DressUpView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); +} + +void TaskDraftParameters::getLine(App::DocumentObject*& obj, std::vector& sub) const +{ + sub = std::vector(1,""); + QStringList parts = ui->lineLine->text().split(QChar::fromAscii(':')); + obj = DressUpView->getObject()->getDocument()->getObject(parts[0].toStdString().c_str()); + if (parts.size() > 1) + sub[0] = parts[1].toStdString(); +} + +void TaskDraftParameters::onAngleChanged(double angle) +{ + clearButtons(none); + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + pcDraft->Angle.setValue(angle); + pcDraft->getDocument()->recomputeFeature(pcDraft); +} + +const double TaskDraftParameters::getAngle(void) const +{ + return ui->draftAngle->value().getValue(); +} + +void TaskDraftParameters::onReversedChanged(const bool on) { + clearButtons(none); + PartDesign::Draft* pcDraft = static_cast(DressUpView->getObject()); + pcDraft->Reversed.setValue(on); + pcDraft->getDocument()->recomputeFeature(pcDraft); +} + +const bool TaskDraftParameters::getReversed(void) const +{ + return ui->checkReverse->isChecked(); +} + +TaskDraftParameters::~TaskDraftParameters() +{ + Gui::Selection().rmvSelectionGate(); + delete ui; +} + +void TaskDraftParameters::changeEvent(QEvent *e) +{ + TaskBox::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(proxy); + } +} + + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgDraftParameters::TaskDlgDraftParameters(ViewProviderDraft *DressUpView) + : TaskDlgDressUpParameters(DressUpView) +{ + parameter = new TaskDraftParameters(DressUpView); + + Content.push_back(parameter); +} + +TaskDlgDraftParameters::~TaskDlgDraftParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +//void TaskDlgDraftParameters::open() +//{ +// // a transaction is already open at creation time of the draft +// if (!Gui::Command::hasPendingCommand()) { +// QString msg = QObject::tr("Edit draft"); +// Gui::Command::openCommand((const char*)msg.toUtf8()); +// } +//} + +bool TaskDlgDraftParameters::accept() +{ + parameter->showObject(); + + // Force the user to select a neutral plane + std::vector strings; + App::DocumentObject* obj; + TaskDraftParameters* draftparameter = static_cast(parameter); + draftparameter->getPlane(obj, strings); + std::string neutralPlane = getPythonStr(obj, strings); + if (neutralPlane.empty()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Missing neutral plane"), + QObject::tr("Please select a plane or an edge plus a pull direction")); + return false; + } + +<<<<<<< 7e34fb3b6f610a533bbd50991d4b09cf063cda7b + std::string name = DraftView->getObject()->getNameInDocument(); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),parameter->getReversed()); + try { + std::vector faces = parameter->getFaces(); + std::stringstream str; + str << "App.ActiveDocument." << name.c_str() << ".Base = (App.ActiveDocument." + << parameter->getBase()->getNameInDocument() << ",["; + for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) + str << "\"" << *it << "\","; + str << "])"; + Gui::Command::doCommand(Gui::Command::Doc,str.str().c_str()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromLatin1(e.what())); + return false; + } +======= + std::string name = DressUpView->getObject()->getNameInDocument(); + + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),draftparameter->getAngle()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %u",name.c_str(),draftparameter->getReversed()); +>>>>>>> Unify code of Dressup features (part 1: Draft) + if (!neutralPlane.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = %s", name.c_str(), neutralPlane.c_str()); + } else + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.NeutralPlane = None", name.c_str()); + draftparameter->getLine(obj, strings); + std::string pullDirection = getPythonStr(obj, strings); + if (!pullDirection.empty()) { + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = %s", name.c_str(), pullDirection.c_str()); + } else + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.PullDirection = None", name.c_str()); + + return TaskDlgDressUpParameters::accept(); +} + +#include "moc_TaskDraftParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.h b/src/Mod/PartDesign/Gui/TaskDraftParameters.h index 2b8c60636ba9..e09b08283d00 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.h @@ -24,31 +24,19 @@ #ifndef GUI_TASKVIEW_TaskDraftParameters_H #define GUI_TASKVIEW_TaskDraftParameters_H -#include -#include -#include - +#include "TaskDressUpParameters.h" #include "ViewProviderDraft.h" class Ui_TaskDraftParameters; -namespace App { -class Property; -} - -namespace Gui { -class ViewProvider; -} - - namespace PartDesignGui { -class TaskDraftParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +class TaskDraftParameters : public TaskDressUpParameters { Q_OBJECT public: - TaskDraftParameters(ViewProviderDraft *DraftView, QWidget *parent=0); + TaskDraftParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); ~TaskDraftParameters(); const double getAngle(void) const; @@ -56,41 +44,25 @@ class TaskDraftParameters : public Gui::TaskView::TaskBox, public Gui::Selection const std::vector getFaces(void) const; void getPlane(App::DocumentObject*& obj, std::vector& sub) const; void getLine(App::DocumentObject*& obj, std::vector& sub) const; - App::DocumentObject *getBase(void) const; - - void hideObject(); - void showObject(); private Q_SLOTS: void onAngleChanged(double angle); void onReversedChanged(bool reversed); - void onButtonFaceAdd(const bool checked); - void onButtonFaceRemove(const bool checked); void onButtonPlane(const bool checked); void onButtonLine(const bool checked); - void onFaceDeleted(void); - -protected: - void exitSelectionMode(); + void onRefDeleted(void); protected: + virtual void clearButtons(const selectionModes notThis); void changeEvent(QEvent *e); virtual void onSelectionChanged(const Gui::SelectionChanges& msg); private: - void clearButtons(const QToolButton* notThis); - -private: - QWidget* proxy; Ui_TaskDraftParameters* ui; - ViewProviderDraft *DraftView; - - enum selectionModes { none, faceAdd, faceRemove, plane, line }; - selectionModes selectionMode; }; /// simulation dialog for the TaskView -class TaskDlgDraftParameters : public Gui::TaskView::TaskDialog +class TaskDlgDraftParameters : public TaskDlgDressUpParameters { Q_OBJECT @@ -98,30 +70,9 @@ class TaskDlgDraftParameters : public Gui::TaskView::TaskDialog TaskDlgDraftParameters(ViewProviderDraft *DraftView); ~TaskDlgDraftParameters(); - ViewProviderDraft* getDraftView() const - { return DraftView; } - - public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); - /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } - -protected: - ViewProviderDraft *DraftView; - - TaskDraftParameters *parameter; }; } //namespace PartDesignGui diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.h.orig b/src/Mod/PartDesign/Gui/TaskDraftParameters.h.orig new file mode 100644 index 000000000000..87b60526352b --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.h.orig @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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 GUI_TASKVIEW_TaskDraftParameters_H +#define GUI_TASKVIEW_TaskDraftParameters_H + +#include "TaskDressUpParameters.h" +#include "ViewProviderDraft.h" + +class Ui_TaskDraftParameters; + +namespace PartDesignGui { + +class TaskDraftParameters : public TaskDressUpParameters +{ + Q_OBJECT + +public: + TaskDraftParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); + ~TaskDraftParameters(); + + const double getAngle(void) const; + const bool getReversed(void) const; + const std::vector getFaces(void) const; + void getPlane(App::DocumentObject*& obj, std::vector& sub) const; + void getLine(App::DocumentObject*& obj, std::vector& sub) const; + +private Q_SLOTS: + void onAngleChanged(double angle); + void onReversedChanged(bool reversed); + void onButtonPlane(const bool checked); + void onButtonLine(const bool checked); + void onRefDeleted(void); + +protected: + virtual void clearButtons(const selectionModes notThis); + void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +private: + Ui_TaskDraftParameters* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgDraftParameters : public TaskDlgDressUpParameters +{ + Q_OBJECT + +public: + TaskDlgDraftParameters(ViewProviderDraft *DraftView); + ~TaskDlgDraftParameters(); + +public: + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); +<<<<<<< 7e34fb3b6f610a533bbd50991d4b09cf063cda7b + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderDraft *DraftView; + + TaskDraftParameters *parameter; +======= +>>>>>>> Unify code of Dressup features (part 1: Draft) +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.ui b/src/Mod/PartDesign/Gui/TaskDraftParameters.ui index 9e5703bc6d5b..32b5fa4accd7 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.ui @@ -17,7 +17,7 @@ - + Add face @@ -27,7 +27,7 @@ - + Remove face @@ -39,7 +39,7 @@ - + @@ -114,7 +114,7 @@ checkReverse - listWidgetFaces + listWidgetReferences diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp new file mode 100644 index 000000000000..7420b3a83c0e --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp @@ -0,0 +1,252 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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 +# include +#endif + +#include "TaskDressUpParameters.h" +#include "Workbench.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace PartDesignGui; +using namespace Gui; + +/* TRANSLATOR PartDesignGui::TaskDressUpParameters */ + +TaskDressUpParameters::TaskDressUpParameters(ViewProviderDressUp *DressUpView,QWidget *parent) + : TaskBox(Gui::BitmapFactory().pixmap((std::string("PartDesign_") + DressUpView->featureName).c_str()), + QString::fromAscii((DressUpView->featureName + " parameters").c_str()), + true, + parent), + DressUpView(DressUpView) +{ + selectionMode = none; +} + +TaskDressUpParameters::~TaskDressUpParameters() +{ + // make sure to remove selection gate in all cases + Gui::Selection().rmvSelectionGate(); +} + +const bool TaskDressUpParameters::referenceSelected(const Gui::SelectionChanges& msg) +{ + if ((msg.Type == Gui::SelectionChanges::AddSelection) && ( + (selectionMode == refAdd) || (selectionMode == refRemove))) { + + if (strcmp(msg.pDocName, DressUpView->getObject()->getDocument()->getName()) != 0) + return false; + + PartDesign::DressUp* pcDressUp = static_cast(DressUpView->getObject()); + App::DocumentObject* base = this->getBase(); + // TODO: Must we make a copy here instead of assigning to const char* ? + const char* fname = base->getNameInDocument(); + if (strcmp(msg.pObjectName, fname) != 0) + return false; + + std::string subName(msg.pSubName); + std::vector refs = pcDressUp->Base.getSubValues(); + std::vector::iterator f = std::find(refs.begin(), refs.end(), subName); + + if (selectionMode == refAdd) { + if (f == refs.end()) + refs.push_back(subName); + else + return false; // duplicate selection + } else { + if (f != refs.end()) + refs.erase(f); + else + return false; + } + pcDressUp->Base.setValue(base, refs); + DressUpView->highlightReferences(false); + pcDressUp->getDocument()->recomputeFeature(pcDressUp); + + return true; + } + + return false; +} + +void TaskDressUpParameters::onButtonRefAdd(bool checked) +{ + if (checked) { + clearButtons(refAdd); + hideObject(); + selectionMode = refAdd; + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); + DressUpView->highlightReferences(true); + } +} + +void TaskDressUpParameters::onButtonRefRemove(const bool checked) +{ + if (checked) { + clearButtons(refRemove); + hideObject(); + selectionMode = refRemove; + Gui::Selection().clearSelection(); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); + DressUpView->highlightReferences(true); + } +} + +const std::vector TaskDressUpParameters::getReferences() const +{ + PartDesign::DressUp* pcDressUp = static_cast(DressUpView->getObject()); + std::vector result = pcDressUp->Base.getSubValues(); + return result; +} + +// TODO: This code is identical with TaskTransformedParameters::removeItemFromListWidget() +void TaskDressUpParameters::removeItemFromListWidget(QListWidget* widget, const char* itemstr) +{ + QList items = widget->findItems(QString::fromAscii(itemstr), Qt::MatchExactly); + if (!items.empty()) { + for (QList::const_iterator i = items.begin(); i != items.end(); i++) { + QListWidgetItem* it = widget->takeItem(widget->row(*i)); + delete it; + } + } +} + +void TaskDressUpParameters::hideObject() +{ + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + App::DocumentObject* base = getBase(); + if (doc != NULL && base != NULL) { + doc->setHide(DressUpView->getObject()->getNameInDocument()); + doc->setShow(base->getNameInDocument()); + } +} + +void TaskDressUpParameters::showObject() +{ + Gui::Document* doc = Gui::Application::Instance->activeDocument(); + App::DocumentObject* base = getBase(); + if (doc != NULL && base != NULL) { + doc->setShow(DressUpView->getObject()->getNameInDocument()); + doc->setHide(base->getNameInDocument()); + } +} + +App::DocumentObject* TaskDressUpParameters::getBase(void) const +{ + PartDesign::DressUp* pcDressUp = static_cast(DressUpView->getObject()); + return pcDressUp->Base.getValue(); +} + +void TaskDressUpParameters::exitSelectionMode() +{ + selectionMode = none; + Gui::Selection().rmvSelectionGate(); + Gui::Selection().clearSelection(); + showObject(); +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgDressUpParameters::TaskDlgDressUpParameters(ViewProviderDressUp *DressUpView) + : TaskDialog(),DressUpView(DressUpView) +{ + assert(DressUpView); +} + +TaskDlgDressUpParameters::~TaskDlgDressUpParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + +bool TaskDlgDressUpParameters::accept() +{ + std::string name = DressUpView->getObject()->getNameInDocument(); + + try { + std::vector refs = parameter->getReferences(); + std::stringstream str; + str << "App.ActiveDocument." << name.c_str() << ".Base = (App.ActiveDocument." + << parameter->getBase()->getNameInDocument() << ",["; + for (std::vector::const_iterator it = refs.begin(); it != refs.end(); ++it) + str << "\"" << *it << "\","; + str << "])"; + Gui::Command::doCommand(Gui::Command::Doc,str.str().c_str()); + } + catch (const Base::Exception& e) { + QMessageBox::warning(parameter, tr("Input error"), QString::fromAscii(e.what())); + return false; + } + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + + return true; +} + +bool TaskDlgDressUpParameters::reject() +{ + // roll back the done things + Gui::Command::abortCommand(); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + + // Body housekeeping + if (ActivePartObject != NULL) { + // Make the new Tip and the previous solid feature visible again + App::DocumentObject* tip = ActivePartObject->Tip.getValue(); + App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); + if (tip != NULL) { + Gui::Application::Instance->getViewProvider(tip)->show(); + if ((tip != prev) && (prev != NULL)) + Gui::Application::Instance->getViewProvider(prev)->show(); + } + } + + return true; +} + + + +#include "moc_TaskDressUpParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.h b/src/Mod/PartDesign/Gui/TaskDressUpParameters.h new file mode 100644 index 000000000000..ce69f94a404c --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.h @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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 GUI_TASKVIEW_TaskDressUpParameters_H +#define GUI_TASKVIEW_TaskDressUpParameters_H + +#include +#include +#include + +#include "ViewProviderDressUp.h" + +class QListWidget; + +namespace PartDesignGui { + +class TaskDressUpParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT + +public: + TaskDressUpParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); + virtual ~TaskDressUpParameters(); + + const std::vector getReferences(void) const; + App::DocumentObject *getBase(void) const; + + void hideObject(); + void showObject(); + +protected Q_SLOTS: + void onButtonRefAdd(const bool checked); + void onButtonRefRemove(const bool checked); + virtual void onRefDeleted(void)=0; + +protected: + void exitSelectionMode(); + const bool referenceSelected(const Gui::SelectionChanges& msg); + +protected: + enum selectionModes { none, refAdd, refRemove, plane, line }; + virtual void clearButtons(const selectionModes notThis) = 0; + virtual void changeEvent(QEvent *e) = 0; + static void removeItemFromListWidget(QListWidget* widget, const char* itemstr); + +protected: + QWidget* proxy; + ViewProviderDressUp *DressUpView; + + + selectionModes selectionMode; +}; + +/// simulation dialog for the TaskView +class TaskDlgDressUpParameters : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgDressUpParameters(ViewProviderDressUp *DressUpView); + virtual ~TaskDlgDressUpParameters(); + + ViewProviderDressUp* getDressUpView() const + { return DressUpView; } + + +public: + /// is called the TaskView when the dialog is opened + virtual void open() {} + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int) {} + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderDressUp *DressUpView; + + TaskDressUpParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TaskDressUpParameters_H diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp index dd82ec2aaaad..f4394776fdd0 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp @@ -42,7 +42,7 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderDraft,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderDraft,PartDesignGui::ViewProviderDressUp) ViewProviderDraft::ViewProviderDraft() { @@ -70,7 +70,7 @@ bool ViewProviderDraft::setEdit(int ModNum) // the task panel Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); TaskDlgDraftParameters *draftDlg = qobject_cast(dlg); - if (draftDlg && draftDlg->getDraftView() != this) + if (draftDlg && draftDlg->getDressUpView() != this) draftDlg = 0; // another pad left open its task panel if (dlg && !draftDlg) { QMessageBox msgBox; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.h b/src/Mod/PartDesign/Gui/ViewProviderDraft.h index 16b03f6c7e92..694a078d7cb7 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.h @@ -24,12 +24,12 @@ #ifndef PARTGUI_ViewProviderDraft_H #define PARTGUI_ViewProviderDraft_H -#include "ViewProvider.h" +#include "ViewProviderDressUp.h" namespace PartDesignGui { -class PartDesignGuiExport ViewProviderDraft : public ViewProvider +class PartDesignGuiExport ViewProviderDraft : public ViewProviderDressUp { PROPERTY_HEADER(PartDesignGui::ViewProviderDraft); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp new file mode 100644 index 000000000000..c55bac981375 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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 +# include +# include +# include +# include +# include +#endif + +#include "ViewProviderDressUp.h" +#include "TaskDressUpParameters.h" +#include +#include +#include +#include +#include + + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderDressUp,PartDesignGui::ViewProvider) + +void ViewProviderDressUp::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr((std::string("Edit ") + featureName + " feature").c_str()), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +const bool ViewProviderDressUp::checkDlgOpen(TaskDlgDressUpParameters* dressUpDlg) { + // When double-clicking on the item for this feature the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + dressUpDlg = qobject_cast(dlg); + + if ((dressUpDlg != NULL) && (dressUpDlg->getDressUpView() != this)) + dressUpDlg = NULL; // another transformed feature left open its task panel + + if ((dlg != NULL) && (dressUpDlg == NULL)) { + QMessageBox msgBox; + msgBox.setText(QObject::tr("A dialog is already open in the task panel")); + msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::Yes); + int ret = msgBox.exec(); + if (ret == QMessageBox::Yes) + Gui::Control().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // Continue (usually in virtual method setEdit()) + return true; +} + +bool ViewProviderDressUp::onDelete(const std::vector &s) +{ + return ViewProvider::onDelete(s); +} + +void ViewProviderDressUp::highlightReferences(const bool on) +{ + PartDesign::DressUp* pcDressUp = static_cast(getObject()); + Part::Feature* base = static_cast(pcDressUp->Base.getValue()); + if (base == NULL) return; + PartGui::ViewProviderPart* vp = dynamic_cast( + Gui::Application::Instance->getViewProvider(base)); + if (vp == NULL) return; + + if (on) { + std::vector SubVals = pcDressUp->Base.getSubValuesStartsWith("Face"); + if (SubVals.size() == 0) return; + + TopTools_IndexedMapOfShape fMap; + TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); + + originalColors = vp->DiffuseColor.getValues(); + std::vector colors = originalColors; + colors.resize(fMap.Extent(), ShapeColor.getValue()); + + for (std::vector::const_iterator f = SubVals.begin(); f != SubVals.end(); f++) { + int idx = atoi(f->substr(4).c_str()) - 1; + // TODO: Find a better colour + colors[idx] = App::Color(0.2,1,0.2); + } + vp->DiffuseColor.setValues(colors); + } else { + vp->DiffuseColor.setValues(originalColors); + } +} + diff --git a/src/Mod/PartDesign/Gui/ViewProviderDressUp.h b/src/Mod/PartDesign/Gui/ViewProviderDressUp.h new file mode 100644 index 000000000000..723dd2312743 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderDressUp.h @@ -0,0 +1,70 @@ +/*************************************************************************** + * Copyright (c) 2012 Jan Rheinländer * + * * + * 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_ViewProviderDressUp_H +#define PARTGUI_ViewProviderDressUp_H + +#include "ViewProvider.h" + + +namespace PartDesignGui { + +class TaskDlgDressUpParameters; + +class PartDesignGuiExport ViewProviderDressUp : public ViewProvider +{ + PROPERTY_HEADER(PartDesignGui::ViewProviderDressUp); + +public: + /// constructor + ViewProviderDressUp() + : featureName("undefined") {} + /// destructor + virtual ~ViewProviderDressUp() + {} + + /// grouping handling + void setupContextMenu(QMenu*, QObject*, const char*); + + virtual bool onDelete(const std::vector &); + + /// Highlight the references that have been selected + void highlightReferences(const bool on); + + // The feature name of the subclass + std::string featureName; + +protected: + const bool checkDlgOpen(TaskDlgDressUpParameters* dressUpDlg); + +private: + std::vector originalColors; + +}; + + + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderDressUp_H From 3229b322ec57528bf076dbbf3fa64805a2a4de66 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 30 Sep 2013 21:53:21 +0200 Subject: [PATCH 213/664] Fix some errors in the PartDesign ViewProvider code --- src/Mod/PartDesign/Gui/ViewProviderBody.h | 2 +- src/Mod/PartDesign/Gui/ViewProviderGroove.h | 2 +- src/Mod/PartDesign/Gui/ViewProviderHole.h | 2 +- .../Gui/ViewProviderLinearPattern.cpp | 2 +- .../Gui/ViewProviderLinearPattern.h | 2 +- src/Mod/PartDesign/Gui/ViewProviderMainPart.h | 2 +- .../PartDesign/Gui/ViewProviderMirrored.cpp | 2 +- src/Mod/PartDesign/Gui/ViewProviderMirrored.h | 2 +- .../Gui/ViewProviderMultiTransform.cpp | 2 +- .../Gui/ViewProviderMultiTransform.h | 2 +- src/Mod/PartDesign/Gui/ViewProviderPad.h | 2 +- .../Gui/ViewProviderPolarPattern.cpp | 2 +- .../PartDesign/Gui/ViewProviderPolarPattern.h | 2 +- .../PartDesign/Gui/ViewProviderRevolution.h | 2 +- src/Mod/PartDesign/Gui/ViewProviderScaled.cpp | 2 +- src/Mod/PartDesign/Gui/ViewProviderScaled.h | 2 +- .../Gui/ViewProviderTransformed.cpp | 19 +------------------ .../PartDesign/Gui/ViewProviderTransformed.h | 8 +------- 18 files changed, 18 insertions(+), 41 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index 34aa9b5a2b70..6c2539a95645 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -37,7 +37,7 @@ namespace PartDesignGui { */ class PartDesignGuiExport ViewProviderBody : public PartGui::ViewProviderPart { - PROPERTY_HEADER(PartGui::ViewProviderBody); + PROPERTY_HEADER(PartDesignGui::ViewProviderBody); public: /// constructor diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.h b/src/Mod/PartDesign/Gui/ViewProviderGroove.h index c569d3dfca40..92f3e4b4a391 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderGroove.h +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.h @@ -31,7 +31,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderGroove : public ViewProvider { - PROPERTY_HEADER(PartGui::ViewProviderGroove); + PROPERTY_HEADER(PartDesignGui::ViewProviderGroove); public: /// constructor diff --git a/src/Mod/PartDesign/Gui/ViewProviderHole.h b/src/Mod/PartDesign/Gui/ViewProviderHole.h index c8bd8d7dddd7..6eaca17b75f3 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderHole.h +++ b/src/Mod/PartDesign/Gui/ViewProviderHole.h @@ -31,7 +31,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderHole : public ViewProvider { - PROPERTY_HEADER(PartGui::ViewProviderHole); + PROPERTY_HEADER(PartDesignGui::ViewProviderHole); public: /// constructor diff --git a/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp b/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp index f23c64b89d91..ab22de86dffb 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.cpp @@ -36,7 +36,7 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderLinearPattern,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderLinearPattern,PartDesignGui::ViewProviderTransformed) bool ViewProviderLinearPattern::setEdit(int ModNum) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.h b/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.h index 454062eb54e7..04a4eef4d370 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.h +++ b/src/Mod/PartDesign/Gui/ViewProviderLinearPattern.h @@ -30,7 +30,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderLinearPattern : public ViewProviderTransformed { - PROPERTY_HEADER(PartGui::ViewProviderLinearPattern); + PROPERTY_HEADER(PartDesignGui::ViewProviderLinearPattern); public: ViewProviderLinearPattern() { featureName = std::string("LinearPattern"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderMainPart.h b/src/Mod/PartDesign/Gui/ViewProviderMainPart.h index cda6bfec5796..343bfda172bf 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMainPart.h +++ b/src/Mod/PartDesign/Gui/ViewProviderMainPart.h @@ -31,7 +31,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderMainPart : public PartGui::ViewProviderPart { - PROPERTY_HEADER(PartGui::ViewProviderMainPart); + PROPERTY_HEADER(PartDesignGui::ViewProviderMainPart); public: /// constructor diff --git a/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp b/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp index cd7c14c56483..8c7384cb25de 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderMirrored.cpp @@ -36,7 +36,7 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderMirrored,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderMirrored,PartDesignGui::ViewProviderTransformed) bool ViewProviderMirrored::setEdit(int ModNum) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderMirrored.h b/src/Mod/PartDesign/Gui/ViewProviderMirrored.h index 3d089907931d..0bbb3018df14 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMirrored.h +++ b/src/Mod/PartDesign/Gui/ViewProviderMirrored.h @@ -30,7 +30,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderMirrored : public ViewProviderTransformed { - PROPERTY_HEADER(PartGui::ViewProviderMirrored); + PROPERTY_HEADER(PartDesignGui::ViewProviderMirrored); public: ViewProviderMirrored() { featureName = std::string("Mirrored"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp index 86105a19b8d9..72c777b2ce39 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.cpp @@ -36,7 +36,7 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderMultiTransform,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderMultiTransform,PartDesignGui::ViewProviderTransformed) bool ViewProviderMultiTransform::setEdit(int ModNum) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h index 253fec60980d..261497a0c33e 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h +++ b/src/Mod/PartDesign/Gui/ViewProviderMultiTransform.h @@ -30,7 +30,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderMultiTransform : public ViewProviderTransformed { - PROPERTY_HEADER(PartGui::ViewProviderMultiTransform); + PROPERTY_HEADER(PartDesignGui::ViewProviderMultiTransform); public: ViewProviderMultiTransform() { featureName = std::string("MultiTransform"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderPad.h b/src/Mod/PartDesign/Gui/ViewProviderPad.h index 71fb2c334c22..7f7b82ed66ff 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPad.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPad.h @@ -30,7 +30,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderPad : public ViewProvider { - PROPERTY_HEADER(PartGui::ViewProviderPad); + PROPERTY_HEADER(PartDesignGui::ViewProviderPad); public: /// constructor diff --git a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp index 7ec126da5497..d72468c4854c 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.cpp @@ -36,7 +36,7 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderPolarPattern,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderPolarPattern,PartDesignGui::ViewProviderTransformed) bool ViewProviderPolarPattern::setEdit(int ModNum) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h index f75f5e80d710..cf0dc4984b3d 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h +++ b/src/Mod/PartDesign/Gui/ViewProviderPolarPattern.h @@ -30,7 +30,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderPolarPattern : public ViewProviderTransformed { - PROPERTY_HEADER(PartGui::ViewProviderPolarPattern); + PROPERTY_HEADER(PartDesignGui::ViewProviderPolarPattern); public: ViewProviderPolarPattern() { featureName = std::string("PolarPattern"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderRevolution.h b/src/Mod/PartDesign/Gui/ViewProviderRevolution.h index a2dbeaeaf6d1..42d17ecd3791 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderRevolution.h +++ b/src/Mod/PartDesign/Gui/ViewProviderRevolution.h @@ -31,7 +31,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderRevolution : public ViewProvider { - PROPERTY_HEADER(PartGui::ViewProviderRevolution); + PROPERTY_HEADER(PartDesignGui::ViewProviderRevolution); public: /// constructor diff --git a/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp b/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp index 9a4e8f45588f..ff09edb24830 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderScaled.cpp @@ -36,7 +36,7 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderScaled,PartDesignGui::ViewProvider) +PROPERTY_SOURCE(PartDesignGui::ViewProviderScaled,PartDesignGui::ViewProviderTransformed) bool ViewProviderScaled::setEdit(int ModNum) { diff --git a/src/Mod/PartDesign/Gui/ViewProviderScaled.h b/src/Mod/PartDesign/Gui/ViewProviderScaled.h index f3bc99d7d67c..a7fde745f949 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderScaled.h +++ b/src/Mod/PartDesign/Gui/ViewProviderScaled.h @@ -30,7 +30,7 @@ namespace PartDesignGui { class PartDesignGuiExport ViewProviderScaled : public ViewProviderTransformed { - PROPERTY_HEADER(PartGui::ViewProviderScaled); + PROPERTY_HEADER(PartDesignGui::ViewProviderScaled); public: ViewProviderScaled() { featureName = std::string("Scaled"); diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp index b7228e8278de..41e4f96acfba 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.cpp @@ -115,24 +115,7 @@ bool ViewProviderTransformed::setEdit(int ModNum) void ViewProviderTransformed::unsetEdit(int ModNum) { - // return to the WB we were in before editing the PartDesign feature - Gui::Command::assureWorkbench(oldWb.c_str()); - - if (ModNum == ViewProvider::Default) { - // when pressing ESC make sure to close the dialog - Gui::Control().closeDialog(); - if ((PartDesignGui::ActivePartObject != NULL) && (oldTip != NULL)) { - Gui::Selection().clearSelection(); - Gui::Selection().addSelection(oldTip->getDocument()->getName(), oldTip->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); - oldTip = NULL; - } else { - oldTip = NULL; - } - } - else { - PartGui::ViewProviderPart::unsetEdit(ModNum); - } + ViewProvider::unsetEdit(ModNum); while (pcRejectedRoot->getNumChildren() > 7) { SoSeparator* sep = static_cast(pcRejectedRoot->getChild(7)); diff --git a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h index 8ecd67e7d5da..962676cc11a1 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderTransformed.h +++ b/src/Mod/PartDesign/Gui/ViewProviderTransformed.h @@ -26,19 +26,13 @@ #include "ViewProvider.h" -class SoCoordinate3; -class SoIndexedFaceSet; -class SoMultipleCopy; -class SoNormal; -class SoSeparator; - namespace PartDesignGui { class TaskDlgTransformedParameters; class PartDesignGuiExport ViewProviderTransformed : public ViewProvider { - PROPERTY_HEADER(PartGui::ViewProviderTransformed); + PROPERTY_HEADER(PartDesignGui::ViewProviderTransformed); public: /// constructor From 8b19d2cf16a19fb1e3321d1a25dda6613d124da9 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Mon, 30 Sep 2013 21:54:48 +0200 Subject: [PATCH 214/664] Unify code of Dressup features (part 2: Draft) --- src/Mod/PartDesign/Gui/ViewProviderDraft.cpp | 98 +++----------------- src/Mod/PartDesign/Gui/ViewProviderDraft.h | 20 +--- 2 files changed, 17 insertions(+), 101 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp index f4394776fdd0..4d7de9aaac35 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.cpp @@ -44,99 +44,29 @@ using namespace PartDesignGui; PROPERTY_SOURCE(PartDesignGui::ViewProviderDraft,PartDesignGui::ViewProviderDressUp) -ViewProviderDraft::ViewProviderDraft() -{ - sPixmap = "PartDesign_Draft.svg"; -} - -ViewProviderDraft::~ViewProviderDraft() -{ -} - - -void ViewProviderDraft::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) -{ - QAction* act; - act = menu->addAction(QObject::tr("Edit draft"), receiver, member); - act->setData(QVariant((int)ViewProvider::Default)); - PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); -} - bool ViewProviderDraft::setEdit(int ModNum) { if (ModNum == ViewProvider::Default ) { - // When double-clicking on the item for this fillet the - // object unsets and sets its edit mode without closing - // the task panel - Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); - TaskDlgDraftParameters *draftDlg = qobject_cast(dlg); - if (draftDlg && draftDlg->getDressUpView() != this) - draftDlg = 0; // another pad left open its task panel - if (dlg && !draftDlg) { - QMessageBox msgBox; - msgBox.setText(QObject::tr("A dialog is already open in the task panel")); - msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::Yes); - int ret = msgBox.exec(); - if (ret == QMessageBox::Yes) - Gui::Control().reject(); - else - return false; - } - - // clear the selection (convenience) - Gui::Selection().clearSelection(); + TaskDlgDressUpParameters *dressUpDlg = NULL; - // always change to PartDesign WB, remember where we come from - oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + if (checkDlgOpen(dressUpDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); - // start the edit dialog - if (draftDlg) - Gui::Control().showDialog(draftDlg); - else - Gui::Control().showDialog(new TaskDlgDraftParameters(this)); + // start the edit dialog + if (dressUpDlg) + Gui::Control().showDialog(dressUpDlg); + else + Gui::Control().showDialog(new TaskDlgDraftParameters(this)); - return true; + return true; + } else { + return false; + } } else { - return PartGui::ViewProviderPart::setEdit(ModNum); + return ViewProviderDressUp::setEdit(ModNum); } } -bool ViewProviderDraft::onDelete(const std::vector &s) -{ - return ViewProvider::onDelete(s); -} - -void ViewProviderDraft::highlightReferences(const bool on) -{ - PartDesign::Draft* pcDraft = static_cast(getObject()); - Part::Feature* base = static_cast(pcDraft->Base.getValue()); - if (base == NULL) return; - PartGui::ViewProviderPart* vp = dynamic_cast( - Gui::Application::Instance->getViewProvider(base)); - if (vp == NULL) return; - - if (on) { - std::vector SubVals = pcDraft->Base.getSubValuesStartsWith("Face"); - if (SubVals.size() == 0) return; - - TopTools_IndexedMapOfShape fMap; - TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); - - originalColors = vp->DiffuseColor.getValues(); - std::vector colors = originalColors; - colors.resize(fMap.Extent(), ShapeColor.getValue()); - - for (std::vector::const_iterator f = SubVals.begin(); f != SubVals.end(); f++) { - int idx = atoi(f->substr(4).c_str()) - 1; - // TODO: Find a better colour - colors[idx] = App::Color(0.2,1,0.2); - } - vp->DiffuseColor.setValues(colors); - } else { - vp->DiffuseColor.setValues(originalColors); - } -} diff --git a/src/Mod/PartDesign/Gui/ViewProviderDraft.h b/src/Mod/PartDesign/Gui/ViewProviderDraft.h index 694a078d7cb7..b918c58e6127 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDraft.h +++ b/src/Mod/PartDesign/Gui/ViewProviderDraft.h @@ -35,28 +35,14 @@ class PartDesignGuiExport ViewProviderDraft : public ViewProviderDressUp public: /// constructor - ViewProviderDraft(); - /// destructor - virtual ~ViewProviderDraft(); - - /// grouping handling - void setupContextMenu(QMenu*, QObject*, const char*); - - virtual bool onDelete(const std::vector &); - - /// Highlight the faces that have been selected - void highlightReferences(const bool on); + ViewProviderDraft() + { featureName = std::string("Draft"); + sPixmap = "PartDesign_Draft.svg"; } protected: virtual bool setEdit(int ModNum); - -private: - std::vector originalColors; - }; - - } // namespace PartDesignGui From ee7f50a554acc7cda8d7b7c2a4426b9f7948dcb3 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 2 Oct 2013 21:35:40 +0200 Subject: [PATCH 215/664] Allow selecting and removing fillet and chamfer references in the dialog --- .../PartDesign/Gui/TaskChamferParameters.cpp | 115 +++++++++++------- .../PartDesign/Gui/TaskChamferParameters.h | 52 ++------ .../Gui/TaskChamferParameters.h.orig | 90 ++++++++++++++ .../PartDesign/Gui/TaskChamferParameters.ui | 35 +++++- .../PartDesign/Gui/TaskDressUpParameters.h | 7 +- .../PartDesign/Gui/TaskFilletParameters.cpp | 115 +++++++++++------- src/Mod/PartDesign/Gui/TaskFilletParameters.h | 54 ++------ .../Gui/TaskFilletParameters.h.orig | 90 ++++++++++++++ .../PartDesign/Gui/TaskFilletParameters.ui | 31 ++++- .../PartDesign/Gui/ViewProviderChamfer.cpp | 73 +++-------- src/Mod/PartDesign/Gui/ViewProviderChamfer.h | 15 +-- src/Mod/PartDesign/Gui/ViewProviderFillet.cpp | 72 +++-------- src/Mod/PartDesign/Gui/ViewProviderFillet.h | 18 +-- 13 files changed, 439 insertions(+), 328 deletions(-) create mode 100644 src/Mod/PartDesign/Gui/TaskChamferParameters.h.orig create mode 100644 src/Mod/PartDesign/Gui/TaskFilletParameters.h.orig diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp index 58bda2c58e6a..a0d53d1a75f5 100644 --- a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp @@ -50,8 +50,8 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskChamferParameters */ -TaskChamferParameters::TaskChamferParameters(ViewProviderChamfer *ChamferView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("Part_Chamfer"),tr("Chamfer parameters"),true, parent),ChamferView(ChamferView) +TaskChamferParameters::TaskChamferParameters(ViewProviderDressUp *DressUpView,QWidget *parent) + : TaskDressUpParameters(DressUpView, parent) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -61,10 +61,14 @@ TaskChamferParameters::TaskChamferParameters(ViewProviderChamfer *ChamferView,QW connect(ui->chamferDistance, SIGNAL(valueChanged(double)), this, SLOT(onLengthChanged(double))); + connect(ui->buttonRefAdd, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefAdd(bool))); + connect(ui->buttonRefRemove, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefRemove(bool))); this->groupLayout()->addWidget(proxy); - PartDesign::Chamfer* pcChamfer = static_cast(ChamferView->getObject()); + PartDesign::Chamfer* pcChamfer = static_cast(DressUpView->getObject()); double r = pcChamfer->Size.getValue(); ui->chamferDistance->setUnit(Base::Unit::Length); @@ -73,11 +77,55 @@ TaskChamferParameters::TaskChamferParameters(ViewProviderChamfer *ChamferView,QW ui->chamferDistance->selectNumber(); ui->chamferDistance->bind(pcChamfer->Size); QMetaObject::invokeMethod(ui->chamferDistance, "setFocus", Qt::QueuedConnection); + std::vector strings = pcChamfer->Base.getSubValues(); + for (std::vector::const_iterator i = strings.begin(); i != strings.end(); i++) + { + ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); + } + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetReferences->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onRefDeleted())); + ui->listWidgetReferences->setContextMenuPolicy(Qt::ActionsContextMenu); +} + +void TaskChamferParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == none) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (referenceSelected(msg)) { + if (selectionMode == refAdd) + ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + else + removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); + clearButtons(none); + exitSelectionMode(); + } + } +} + +void TaskChamferParameters::clearButtons(const selectionModes notThis) +{ + if (notThis != refAdd) ui->buttonRefAdd->setChecked(false); + if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); +} + +void TaskChamferParameters::onRefDeleted(void) +{ + PartDesign::Chamfer* pcChamfer = static_cast(DressUpView->getObject()); + App::DocumentObject* base = pcChamfer->Base.getValue(); + std::vector refs = pcChamfer->Base.getSubValues(); + refs.erase(refs.begin() + ui->listWidgetReferences->currentRow()); + pcChamfer->Base.setValue(base, refs); + ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); + pcChamfer->getDocument()->recomputeFeature(pcChamfer); } void TaskChamferParameters::onLengthChanged(double len) { - PartDesign::Chamfer* pcChamfer = static_cast(ChamferView->getObject()); + PartDesign::Chamfer* pcChamfer = static_cast(DressUpView->getObject()); pcChamfer->Size.setValue(len); pcChamfer->getDocument()->recomputeFeature(pcChamfer); } @@ -89,6 +137,7 @@ double TaskChamferParameters::getLength(void) const TaskChamferParameters::~TaskChamferParameters() { + Gui::Selection().rmvSelectionGate(); delete ui; } @@ -102,12 +151,13 @@ void TaskChamferParameters::changeEvent(QEvent *e) void TaskChamferParameters::apply() { - std::string name = ChamferView->getObject()->getNameInDocument(); + std::string name = DressUpView->getObject()->getNameInDocument(); //Gui::Command::openCommand("Chamfer changed"); ui->chamferDistance->apply(); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); } @@ -116,11 +166,10 @@ void TaskChamferParameters::apply() // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgChamferParameters::TaskDlgChamferParameters(ViewProviderChamfer *ChamferView) - : TaskDialog(),ChamferView(ChamferView) +TaskDlgChamferParameters::TaskDlgChamferParameters(ViewProviderChamfer *DressUpView) + : TaskDlgDressUpParameters(DressUpView) { - assert(ChamferView); - parameter = new TaskChamferParameters(ChamferView); + parameter = new TaskChamferParameters(DressUpView); Content.push_back(parameter); } @@ -133,48 +182,20 @@ TaskDlgChamferParameters::~TaskDlgChamferParameters() //==== calls from the TaskView =============================================================== -void TaskDlgChamferParameters::open() -{ - // a transaction is already open at creation time of the chamfer - if (!Gui::Command::hasPendingCommand()) { - QString msg = tr("Edit chamfer"); - Gui::Command::openCommand((const char*)msg.toUtf8()); - } -} - -void TaskDlgChamferParameters::clicked(int) -{ - -} - +//void TaskDlgChamferParameters::open() +//{ +// // a transaction is already open at creation time of the chamfer +// if (!Gui::Command::hasPendingCommand()) { +// QString msg = tr("Edit chamfer"); +// Gui::Command::openCommand((const char*)msg.toUtf8()); +// } +//} bool TaskDlgChamferParameters::accept() { + parameter->showObject(); parameter->apply(); - return true; -} - -bool TaskDlgChamferParameters::reject() -{ - // role back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // Body housekeeping - if (ActivePartObject != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - return true; + return TaskDlgDressUpParameters::accept(); } - - #include "moc_TaskChamferParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.h b/src/Mod/PartDesign/Gui/TaskChamferParameters.h index 20d16bd396f8..5826c8fdfcbe 100644 --- a/src/Mod/PartDesign/Gui/TaskChamferParameters.h +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.h @@ -24,83 +24,49 @@ #ifndef GUI_TASKVIEW_TaskChamferParameters_H #define GUI_TASKVIEW_TaskChamferParameters_H -#include -#include -#include - +#include "TaskDressUpParameters.h" #include "ViewProviderChamfer.h" class Ui_TaskChamferParameters; -namespace App { -class Property; -} - -namespace Gui { -class ViewProvider; -} - - namespace PartDesignGui { -class TaskChamferParameters : public Gui::TaskView::TaskBox +class TaskChamferParameters : public TaskDressUpParameters { Q_OBJECT public: - TaskChamferParameters(ViewProviderChamfer *ChamferView, QWidget *parent=0); + TaskChamferParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); ~TaskChamferParameters(); - void apply(); + virtual void apply(); private Q_SLOTS: void onLengthChanged(double); + void onRefDeleted(void); protected: + virtual void clearButtons(const selectionModes notThis); void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); double getLength(void) const; private: - -private: - QWidget* proxy; Ui_TaskChamferParameters* ui; - ViewProviderChamfer *ChamferView; }; /// simulation dialog for the TaskView -class TaskDlgChamferParameters : public Gui::TaskView::TaskDialog +class TaskDlgChamferParameters : public TaskDlgDressUpParameters { Q_OBJECT public: - TaskDlgChamferParameters(ViewProviderChamfer *ChamferView); + TaskDlgChamferParameters(ViewProviderChamfer *DressUpView); ~TaskDlgChamferParameters(); - ViewProviderChamfer* getChamferView() const - { return ChamferView; } - - public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); - /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } - -protected: - ViewProviderChamfer *ChamferView; - - TaskChamferParameters *parameter; }; } //namespace PartDesignGui diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.h.orig b/src/Mod/PartDesign/Gui/TaskChamferParameters.h.orig new file mode 100644 index 000000000000..517790999f56 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.h.orig @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 GUI_TASKVIEW_TaskChamferParameters_H +#define GUI_TASKVIEW_TaskChamferParameters_H + +#include "TaskDressUpParameters.h" +#include "ViewProviderChamfer.h" + +class Ui_TaskChamferParameters; + +namespace PartDesignGui { + +class TaskChamferParameters : public TaskDressUpParameters +{ + Q_OBJECT + +public: + TaskChamferParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); + ~TaskChamferParameters(); + + virtual void apply(); + +private Q_SLOTS: + void onLengthChanged(double); + void onRefDeleted(void); + +protected: + virtual void clearButtons(const selectionModes notThis); + void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + double getLength(void) const; + +private: + Ui_TaskChamferParameters* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgChamferParameters : public TaskDlgDressUpParameters +{ + Q_OBJECT + +public: + TaskDlgChamferParameters(ViewProviderChamfer *DressUpView); + ~TaskDlgChamferParameters(); + +public: + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); +<<<<<<< 61d7568d0ff2d3e87f1abb738517f4294c5a6d2e + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderChamfer *ChamferView; + + TaskChamferParameters *parameter; +======= +>>>>>>> Allow selecting and removing fillet and chamfer references in the dialog +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TaskChamferParameters_H diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.ui b/src/Mod/PartDesign/Gui/TaskChamferParameters.ui index bcb4314ca8c2..9c958181facf 100644 --- a/src/Mod/PartDesign/Gui/TaskChamferParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.ui @@ -6,8 +6,8 @@ 0 0 - 135 - 40 + 182 + 185 @@ -15,19 +15,42 @@ - + - + - Size: + Add ref + + + true - + + + Remove ref + + + true + + + + + + + + + + + + Size: + + + diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.h b/src/Mod/PartDesign/Gui/TaskDressUpParameters.h index ce69f94a404c..ccdaefefe78f 100644 --- a/src/Mod/PartDesign/Gui/TaskDressUpParameters.h +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.h @@ -48,6 +48,9 @@ class TaskDressUpParameters : public Gui::TaskView::TaskBox, public Gui::Selecti void hideObject(); void showObject(); + /// Apply the changes made to the object to it + virtual void apply() {}; + protected Q_SLOTS: void onButtonRefAdd(const bool checked); void onButtonRefRemove(const bool checked); @@ -63,11 +66,13 @@ protected Q_SLOTS: virtual void changeEvent(QEvent *e) = 0; static void removeItemFromListWidget(QListWidget* widget, const char* itemstr); + ViewProviderDressUp* getDressUpView() const + { return DressUpView; } + protected: QWidget* proxy; ViewProviderDressUp *DressUpView; - selectionModes selectionMode; }; diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp index 0e1045a7d172..19ecbc715ec4 100644 --- a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp @@ -50,8 +50,8 @@ using namespace Gui; /* TRANSLATOR PartDesignGui::TaskFilletParameters */ -TaskFilletParameters::TaskFilletParameters(ViewProviderFillet *FilletView,QWidget *parent) - : TaskBox(Gui::BitmapFactory().pixmap("Part_Fillet"),tr("Fillet parameters"),true, parent),FilletView(FilletView) +TaskFilletParameters::TaskFilletParameters(ViewProviderDressUp *DressUpView,QWidget *parent) + : TaskDressUpParameters(DressUpView, parent) { // we need a separate container widget to add all controls to proxy = new QWidget(this); @@ -61,10 +61,14 @@ TaskFilletParameters::TaskFilletParameters(ViewProviderFillet *FilletView,QWidge connect(ui->filletRadius, SIGNAL(valueChanged(double)), this, SLOT(onLengthChanged(double))); + connect(ui->buttonRefAdd, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefAdd(bool))); + connect(ui->buttonRefRemove, SIGNAL(toggled(bool)), + this, SLOT(onButtonRefRemove(bool))); this->groupLayout()->addWidget(proxy); - PartDesign::Fillet* pcFillet = static_cast(FilletView->getObject()); + PartDesign::Fillet* pcFillet = static_cast(DressUpView->getObject()); double r = pcFillet->Radius.getValue(); ui->filletRadius->setUnit(Base::Unit::Length); @@ -73,11 +77,56 @@ TaskFilletParameters::TaskFilletParameters(ViewProviderFillet *FilletView,QWidge ui->filletRadius->selectNumber(); ui->filletRadius->bind(pcFillet->Radius); QMetaObject::invokeMethod(ui->filletRadius, "setFocus", Qt::QueuedConnection); + std::vector strings = pcFillet->Base.getSubValues(); + for (std::vector::const_iterator i = strings.begin(); i != strings.end(); i++) + { + ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); + } + // Create context menu + QAction* action = new QAction(tr("Remove"), this); + ui->listWidgetReferences->addAction(action); + connect(action, SIGNAL(triggered()), this, SLOT(onRefDeleted())); + ui->listWidgetReferences->setContextMenuPolicy(Qt::ActionsContextMenu); +} + +void TaskFilletParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (selectionMode == none) + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (referenceSelected(msg)) { + if (selectionMode == refAdd) + ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + else + removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); + clearButtons(none); + exitSelectionMode(); + } + } +} + +void TaskFilletParameters::clearButtons(const selectionModes notThis) +{ + if (notThis != refAdd) ui->buttonRefAdd->setChecked(false); + if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); +} + +void TaskFilletParameters::onRefDeleted(void) +{ + PartDesign::Fillet* pcFillet = static_cast(DressUpView->getObject()); + App::DocumentObject* base = pcFillet->Base.getValue(); + std::vector refs = pcFillet->Base.getSubValues(); + refs.erase(refs.begin() + ui->listWidgetReferences->currentRow()); + pcFillet->Base.setValue(base, refs); + ui->listWidgetReferences->model()->removeRow(ui->listWidgetReferences->currentRow()); + pcFillet->getDocument()->recomputeFeature(pcFillet); } void TaskFilletParameters::onLengthChanged(double len) { - PartDesign::Fillet* pcFillet = static_cast(FilletView->getObject()); + clearButtons(none); + PartDesign::Fillet* pcFillet = static_cast(DressUpView->getObject()); pcFillet->Radius.setValue(len); pcFillet->getDocument()->recomputeFeature(pcFillet); } @@ -89,6 +138,7 @@ double TaskFilletParameters::getLength(void) const TaskFilletParameters::~TaskFilletParameters() { + Gui::Selection().rmvSelectionGate(); delete ui; } @@ -102,7 +152,7 @@ void TaskFilletParameters::changeEvent(QEvent *e) void TaskFilletParameters::apply() { - std::string name = FilletView->getObject()->getNameInDocument(); + std::string name = getDressUpView()->getObject()->getNameInDocument(); //Gui::Command::openCommand("Fillet changed"); ui->filletRadius->apply(); @@ -116,11 +166,10 @@ void TaskFilletParameters::apply() // TaskDialog //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TaskDlgFilletParameters::TaskDlgFilletParameters(ViewProviderFillet *FilletView) - : TaskDialog(),FilletView(FilletView) +TaskDlgFilletParameters::TaskDlgFilletParameters(ViewProviderFillet *DressUpView) + : TaskDlgDressUpParameters(DressUpView) { - assert(FilletView); - parameter = new TaskFilletParameters(FilletView); + parameter = new TaskFilletParameters(DressUpView); Content.push_back(parameter); } @@ -133,48 +182,20 @@ TaskDlgFilletParameters::~TaskDlgFilletParameters() //==== calls from the TaskView =============================================================== -void TaskDlgFilletParameters::open() -{ - // a transaction is already open at creation time of the fillet - if (!Gui::Command::hasPendingCommand()) { - QString msg = tr("Edit fillet"); - Gui::Command::openCommand((const char*)msg.toUtf8()); - } -} - -void TaskDlgFilletParameters::clicked(int) -{ - -} - +//void TaskDlgFilletParameters::open() +//{ +// // a transaction is already open at creation time of the fillet +// if (!Gui::Command::hasPendingCommand()) { +// QString msg = tr("Edit fillet"); +// Gui::Command::openCommand((const char*)msg.toUtf8()); +// } +//} bool TaskDlgFilletParameters::accept() { + parameter->showObject(); parameter->apply(); - return true; + return TaskDlgDressUpParameters::accept(); } -bool TaskDlgFilletParameters::reject() -{ - // role back the done things - Gui::Command::abortCommand(); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - - // Body housekeeping - if (ActivePartObject != NULL) { - // Make the new Tip and the previous solid feature visible again - App::DocumentObject* tip = ActivePartObject->Tip.getValue(); - App::DocumentObject* prev = ActivePartObject->getPrevSolidFeature(); - if (tip != NULL) { - Gui::Application::Instance->getViewProvider(tip)->show(); - if ((tip != prev) && (prev != NULL)) - Gui::Application::Instance->getViewProvider(prev)->show(); - } - } - - return true; -} - - - #include "moc_TaskFilletParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.h b/src/Mod/PartDesign/Gui/TaskFilletParameters.h index e05fd9fd2205..2b6966cf4711 100644 --- a/src/Mod/PartDesign/Gui/TaskFilletParameters.h +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.h @@ -24,85 +24,51 @@ #ifndef GUI_TASKVIEW_TaskFilletParameters_H #define GUI_TASKVIEW_TaskFilletParameters_H -#include -#include -#include - +#include "TaskDressUpParameters.h" #include "ViewProviderFillet.h" class Ui_TaskFilletParameters; -namespace App { -class Property; -} - -namespace Gui { -class ViewProvider; -} - - namespace PartDesignGui { -class TaskFilletParameters : public Gui::TaskView::TaskBox +class TaskFilletParameters : public TaskDressUpParameters { Q_OBJECT public: - TaskFilletParameters(ViewProviderFillet *FilletView, QWidget *parent=0); + TaskFilletParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); ~TaskFilletParameters(); - void apply(); + virtual void apply(); private Q_SLOTS: void onLengthChanged(double); + void onRefDeleted(void); protected: double getLength(void) const; + virtual void clearButtons(const selectionModes notThis); void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); private: - -private: - QWidget* proxy; Ui_TaskFilletParameters* ui; - ViewProviderFillet *FilletView; }; /// simulation dialog for the TaskView -class TaskDlgFilletParameters : public Gui::TaskView::TaskDialog +class TaskDlgFilletParameters : public TaskDlgDressUpParameters { Q_OBJECT public: - TaskDlgFilletParameters(ViewProviderFillet *FilletView); + TaskDlgFilletParameters(ViewProviderFillet *DressUpView); ~TaskDlgFilletParameters(); - ViewProviderFillet* getFilletView() const - { return FilletView; } - - public: - /// is called the TaskView when the dialog is opened - virtual void open(); - /// is called by the framework if an button is clicked which has no accept or reject role - virtual void clicked(int); /// is called by the framework if the dialog is accepted (Ok) virtual bool accept(); - /// is called by the framework if the dialog is rejected (Cancel) - virtual bool reject(); - virtual bool isAllowedAlterDocument(void) const - { return false; } - - /// returns for Close and Help button - virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const - { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } - -protected: - ViewProviderFillet *FilletView; - - TaskFilletParameters *parameter; }; } //namespace PartDesignGui -#endif // GUI_TASKVIEW_TASKAPPERANCE_H +#endif // GUI_TASKVIEW_TaskFilletParameters_H diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.h.orig b/src/Mod/PartDesign/Gui/TaskFilletParameters.h.orig new file mode 100644 index 000000000000..17f2a4e7c62b --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.h.orig @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (c) 2011 Juergen Riegel * + * * + * 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 GUI_TASKVIEW_TaskFilletParameters_H +#define GUI_TASKVIEW_TaskFilletParameters_H + +#include "TaskDressUpParameters.h" +#include "ViewProviderFillet.h" + +class Ui_TaskFilletParameters; + +namespace PartDesignGui { + +class TaskFilletParameters : public TaskDressUpParameters +{ + Q_OBJECT + +public: + TaskFilletParameters(ViewProviderDressUp *DressUpView, QWidget *parent=0); + ~TaskFilletParameters(); + + virtual void apply(); + +private Q_SLOTS: + void onLengthChanged(double); + void onRefDeleted(void); + +protected: + double getLength(void) const; + virtual void clearButtons(const selectionModes notThis); + void changeEvent(QEvent *e); + virtual void onSelectionChanged(const Gui::SelectionChanges& msg); + +private: + Ui_TaskFilletParameters* ui; +}; + +/// simulation dialog for the TaskView +class TaskDlgFilletParameters : public TaskDlgDressUpParameters +{ + Q_OBJECT + +public: + TaskDlgFilletParameters(ViewProviderFillet *DressUpView); + ~TaskDlgFilletParameters(); + +public: + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); +<<<<<<< 61d7568d0ff2d3e87f1abb738517f4294c5a6d2e + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +protected: + ViewProviderFillet *FilletView; + + TaskFilletParameters *parameter; +======= +>>>>>>> Allow selecting and removing fillet and chamfer references in the dialog +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TaskFilletParameters_H diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.ui b/src/Mod/PartDesign/Gui/TaskFilletParameters.ui index 9d159721968a..b6803af459b8 100644 --- a/src/Mod/PartDesign/Gui/TaskFilletParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.ui @@ -6,14 +6,41 @@ 0 0 - 135 - 40 + 208 + 164 Form + + + + + + Add ref + + + true + + + + + + + Remove ref + + + true + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp index 7be0f498f216..c375a8d1eb6b 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderChamfer.cpp @@ -31,8 +31,6 @@ #include "ViewProviderChamfer.h" #include "TaskChamferParameters.h" -#include -#include #include #include #include @@ -40,73 +38,32 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderChamfer,PartDesignGui::ViewProvider) - -ViewProviderChamfer::ViewProviderChamfer() -{ - sPixmap = "PartDesign_Chamfer.svg"; -} - -ViewProviderChamfer::~ViewProviderChamfer() -{ -} - - -void ViewProviderChamfer::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) -{ - QAction* act; - act = menu->addAction(QObject::tr("Edit chamfer"), receiver, member); - act->setData(QVariant((int)ViewProvider::Default)); - PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); -} +PROPERTY_SOURCE(PartDesignGui::ViewProviderChamfer,PartDesignGui::ViewProviderDressUp) bool ViewProviderChamfer::setEdit(int ModNum) { if (ModNum == ViewProvider::Default ) { - // When double-clicking on the item for this chamfer the - // object unsets and sets its edit mode without closing - // the task panel - Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); - TaskDlgChamferParameters *padDlg = qobject_cast(dlg); - if (padDlg && padDlg->getChamferView() != this) - padDlg = 0; // another pad left open its task panel - if (dlg && !padDlg) { - QMessageBox msgBox; - msgBox.setText(QObject::tr("A dialog is already open in the task panel")); - msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::Yes); - int ret = msgBox.exec(); - if (ret == QMessageBox::Yes) - Gui::Control().reject(); - else - return false; - } - - // clear the selection (convenience) - Gui::Selection().clearSelection(); + TaskDlgDressUpParameters *dressUpDlg = NULL; - // always change to PartDesign WB, remember where we come from - oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); + if (checkDlgOpen(dressUpDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); - // start the edit dialog - if (padDlg) - Gui::Control().showDialog(padDlg); - else - Gui::Control().showDialog(new TaskDlgChamferParameters(this)); + // start the edit dialog + if (dressUpDlg) + Gui::Control().showDialog(dressUpDlg); + else + Gui::Control().showDialog(new TaskDlgChamferParameters(this)); - return true; + return true; + } else { + return false; + } } else { - return PartGui::ViewProviderPart::setEdit(ModNum); + return ViewProviderDressUp::setEdit(ModNum); } } -bool ViewProviderChamfer::onDelete(const std::vector &s) -{ - return ViewProvider::onDelete(s); -} - - diff --git a/src/Mod/PartDesign/Gui/ViewProviderChamfer.h b/src/Mod/PartDesign/Gui/ViewProviderChamfer.h index 507a7bb0eb6b..2a9bab302d85 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderChamfer.h +++ b/src/Mod/PartDesign/Gui/ViewProviderChamfer.h @@ -24,25 +24,20 @@ #ifndef PARTGUI_ViewProviderChamfer_H #define PARTGUI_ViewProviderChamfer_H -#include "ViewProvider.h" +#include "ViewProviderDressUp.h" namespace PartDesignGui { -class PartDesignGuiExport ViewProviderChamfer : public ViewProvider +class PartDesignGuiExport ViewProviderChamfer : public ViewProviderDressUp { PROPERTY_HEADER(PartDesignGui::ViewProviderChamfer); public: /// constructor - ViewProviderChamfer(); - /// destructor - virtual ~ViewProviderChamfer(); - - /// grouping handling - void setupContextMenu(QMenu*, QObject*, const char*); - - virtual bool onDelete(const std::vector &); + ViewProviderChamfer() + { featureName = std::string("Chamfer"); + sPixmap = "PartDesign_Chamfer.svg"; } protected: virtual bool setEdit(int ModNum); diff --git a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp index db604d595f65..24ad5d90842a 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderFillet.cpp @@ -31,8 +31,6 @@ #include "ViewProviderFillet.h" #include "TaskFilletParameters.h" -#include -#include #include #include #include @@ -40,71 +38,31 @@ using namespace PartDesignGui; -PROPERTY_SOURCE(PartDesignGui::ViewProviderFillet,PartDesignGui::ViewProvider) - -ViewProviderFillet::ViewProviderFillet() -{ - sPixmap = "PartDesign_Fillet.svg"; -} - -ViewProviderFillet::~ViewProviderFillet() -{ -} - - -void ViewProviderFillet::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) -{ - QAction* act; - act = menu->addAction(QObject::tr("Edit fillet"), receiver, member); - act->setData(QVariant((int)ViewProvider::Default)); - PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); -} +PROPERTY_SOURCE(PartDesignGui::ViewProviderFillet,PartDesignGui::ViewProviderDressUp) bool ViewProviderFillet::setEdit(int ModNum) { if (ModNum == ViewProvider::Default ) { - // When double-clicking on the item for this fillet the - // object unsets and sets its edit mode without closing - // the task panel - Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); - TaskDlgFilletParameters *padDlg = qobject_cast(dlg); - if (padDlg && padDlg->getFilletView() != this) - padDlg = 0; // another pad left open its task panel - if (dlg && !padDlg) { - QMessageBox msgBox; - msgBox.setText(QObject::tr("A dialog is already open in the task panel")); - msgBox.setInformativeText(QObject::tr("Do you want to close this dialog?")); - msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - msgBox.setDefaultButton(QMessageBox::Yes); - int ret = msgBox.exec(); - if (ret == QMessageBox::Yes) - Gui::Control().reject(); - else - return false; - } + TaskDlgDressUpParameters *dressUpDlg = NULL; - // clear the selection (convenience) - Gui::Selection().clearSelection(); + if (checkDlgOpen(dressUpDlg)) { + // always change to PartDesign WB, remember where we come from + oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); - // always change to PartDesign WB, remember where we come from - oldWb = Gui::Command::assureWorkbench("PartDesignWorkbench"); - - // start the edit dialog - if (padDlg) - Gui::Control().showDialog(padDlg); - else - Gui::Control().showDialog(new TaskDlgFilletParameters(this)); + // start the edit dialog + if (dressUpDlg) + Gui::Control().showDialog(dressUpDlg); + else + Gui::Control().showDialog(new TaskDlgFilletParameters(this)); - return true; + return true; + } else { + return false; + } } else { - return PartGui::ViewProviderPart::setEdit(ModNum); + return ViewProviderDressUp::setEdit(ModNum); } } -bool ViewProviderFillet::onDelete(const std::vector &s) -{ - return ViewProvider::onDelete(s); -} - diff --git a/src/Mod/PartDesign/Gui/ViewProviderFillet.h b/src/Mod/PartDesign/Gui/ViewProviderFillet.h index f2f80df7c2d7..240fffa36c0f 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderFillet.h +++ b/src/Mod/PartDesign/Gui/ViewProviderFillet.h @@ -24,33 +24,25 @@ #ifndef PARTGUI_ViewProviderFillet_H #define PARTGUI_ViewProviderFillet_H -#include "ViewProvider.h" +#include "ViewProviderDressUp.h" namespace PartDesignGui { -class PartDesignGuiExport ViewProviderFillet : public ViewProvider +class PartDesignGuiExport ViewProviderFillet : public ViewProviderDressUp { PROPERTY_HEADER(PartDesignGui::ViewProviderFillet); public: /// constructor - ViewProviderFillet(); - /// destructor - virtual ~ViewProviderFillet(); - - /// grouping handling - void setupContextMenu(QMenu*, QObject*, const char*); - - virtual bool onDelete(const std::vector &); + ViewProviderFillet() + { featureName = std::string("Fillet"); + sPixmap = "PartDesign_Fillet.svg"; } protected: virtual bool setEdit(int ModNum); - }; - - } // namespace PartDesignGui From 7981edd6392fc0598c68b8cdc7625026c6aecde6 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Wed, 2 Oct 2013 21:36:30 +0200 Subject: [PATCH 216/664] Allow selecting and removing fillet and chamfer references in the dialog (part 2) --- src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp index 7420b3a83c0e..31e1ca1f1c33 100644 --- a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp @@ -112,8 +112,10 @@ void TaskDressUpParameters::onButtonRefAdd(bool checked) clearButtons(refAdd); hideObject(); selectionMode = refAdd; - Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); + Gui::Selection().clearSelection(); + bool edge = (DressUpView->featureName != "Draft"); + bool face = (DressUpView->featureName == "Draft"); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), edge, face, false)); DressUpView->highlightReferences(true); } } @@ -125,7 +127,9 @@ void TaskDressUpParameters::onButtonRefRemove(const bool checked) hideObject(); selectionMode = refRemove; Gui::Selection().clearSelection(); - Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), false, true, false)); + bool edge = (DressUpView->featureName != "Draft"); + bool face = (DressUpView->featureName == "Draft"); + Gui::Selection().addSelectionGate(new ReferenceSelection(this->getBase(), edge, face, false)); DressUpView->highlightReferences(true); } } From b3058a4f5a772603081a885d73df90076c13286c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 3 Oct 2013 10:14:47 +0000 Subject: [PATCH 217/664] windows adoptions --- src/Mod/Assembly/App/opendcm/core.hpp | 2 + .../Assembly/App/opendcm/core/constraint.hpp | 34 +-- .../Assembly/App/opendcm/core/equations.hpp | 80 ++++-- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 66 +++-- .../Assembly/App/opendcm/core/property.hpp | 13 +- src/Mod/Assembly/App/opendcm/core/system.hpp | 33 ++- .../Assembly/App/opendcm/module3d/angle.hpp | 87 ++++-- .../App/opendcm/module3d/clustermath.hpp | 18 +- .../App/opendcm/module3d/coincident.hpp | 69 ++++- .../App/opendcm/module3d/distance.hpp | 178 +++++++++--- src/Mod/Assembly/App/opendcm/module3d/dof.hpp | 4 +- .../Assembly/App/opendcm/module3d/module.hpp | 4 +- .../App/opendcm/module3d/parallel.hpp | 271 +++++++++++------- .../Assembly/App/opendcm/module3d/solver.hpp | 12 +- .../App/opendcm/modulePart/module.hpp | 6 +- 15 files changed, 604 insertions(+), 273 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index 6a4612f76d99..b30cd8aec73b 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -23,6 +23,8 @@ #ifdef _WIN32 //warning about to long decoraded names, won't affect the code correctness #pragma warning( disable : 4503 ) + //warning about changed pod initalising behaviour (boost blank in variant) + #pragma warning( disable : 4345 ) //disable boost concept checks, as some of them have alignment problems which bring msvc to an error //(for example DFSvisitor check in boost::graph::depht_first_search) diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index 7d162823bf55..5d5cf88b76cc 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -51,7 +51,6 @@ #include "equations.hpp" #include "geometry.hpp" -class T; namespace mpl = boost::mpl; namespace fusion = boost::fusion; @@ -59,6 +58,13 @@ namespace dcm { namespace detail { +//metafunction to avoid ot-of-range access of mpl sequences +template +struct in_range_value { + typedef typename mpl::prior >::type last_id; + typedef typename mpl::min< mpl::int_, last_id>::type type; +}; + //type erasure container for constraints template class Constraint { @@ -152,7 +158,7 @@ class Constraint { virtual ~placeholder() {} virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const = 0; virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false) = 0; - virtual void treatLGZ(geom_ptr first, geom_ptr second) = 0; + virtual void treatLGZ(geom_ptr first, geom_ptr second) = 0; virtual int equationCount() = 0; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second) = 0; virtual void collectPseudoPoints(geom_ptr first, geom_ptr second, Vec& vec1, Vec& vec2) = 0; @@ -297,7 +303,7 @@ class Constraint { holder(Objects& obj); virtual void calculate(geom_ptr first, geom_ptr second, Scalar scale, bool rotation_only = false); - virtual void treatLGZ(geom_ptr first, geom_ptr second); + virtual void treatLGZ(geom_ptr first, geom_ptr second); virtual placeholder* resetConstraint(geom_ptr first, geom_ptr second) const; virtual void setMaps(MES& mes, geom_ptr first, geom_ptr second); virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); @@ -370,7 +376,7 @@ template void Constraint::initialize(ConstraintVector& cv) { //use the compile time unrolling to retrieve the geometry tags - initializeFirstGeometry, ConstraintVector>(cv, mpl::true_()); + initializeFirstGeometry >(cv, mpl::true_()); }; template @@ -507,15 +513,13 @@ void Constraint::holder::Calculater: //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors for(int i=0; i<3; i++) { - typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); val.m_diff_first_rot(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); + second->m_parameter, first->m_diffparam.col(i)); } //and now with the translations for(int i=0; i<3; i++) { - typename Kernel::VectorMap block(&first->m_diffparam(0,i+3),first->m_parameterCount,1, DS(1,1)); val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); + second->m_parameter, first->m_diffparam.col(i+3)); } } } @@ -530,15 +534,13 @@ void Constraint::holder::Calculater: //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors for(int i=0; i<3; i++) { - typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); val.m_diff_second_rot(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, block); + second->m_parameter, second->m_diffparam.col(i)); } //and the translation seperated for(int i=0; i<3; i++) { - typename Kernel::VectorMap block(&second->m_diffparam(0,i+3),second->m_parameterCount,1, DS(1,1)); val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, block); + second->m_parameter, second->m_diffparam.col(i+3)); } } } @@ -632,7 +634,7 @@ void Constraint::holder::LGZ::operat if(!val.enabled) return; - + //to treat local gradient zeros we calculate a approximate second derivative of the equations //only do that if neseccary: residual is not zero if(val.m_residual(0) > 1e-7) { //TODO: use exact precission and scale value @@ -845,14 +847,14 @@ template void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { typedef typename Sys::geometries geometries; - + switch(first->getExactType()) { #ifdef BOOST_PP_LOCAL_ITERATE #define BOOST_PP_LOCAL_MACRO(n) \ case (WhichType::value + n): \ return initializeSecondGeometry,\ - typename mpl::at_c::type,\ + typename mpl::at::type >::type,\ ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ break; #define BOOST_PP_LOCAL_LIMITS (0, 10) @@ -883,7 +885,7 @@ void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost: #define BOOST_PP_LOCAL_MACRO(n) \ case (WhichType::value + n): \ return intitalizeFinalize::type,\ + typename mpl::at::type >::type,\ ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ break; #define BOOST_PP_LOCAL_LIMITS (0, 10) diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 6484b67b309c..7f28fc33b860 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -49,7 +49,9 @@ struct no_option {}; template struct Pseudo { typedef std::vector > Vec; - void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; + + template + void calculatePseudo(const E::MatrixBase& param1, Vec& v1, const E::MatrixBase& param2, Vec& v2) {}; }; template @@ -60,7 +62,9 @@ struct Scale { template struct PseudoScale { typedef std::vector > Vec; - void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) {}; + + template + void calculatePseudo(const E::MatrixBase& param1, Vec& v1, const E::MatrixBase& param2, Vec& v2) {}; void setScale(typename Kernel::number_type scale) {}; }; @@ -218,28 +222,42 @@ struct Distance : public Equation { Scalar value; //template definition - void calculatePseudo(typename Kernel::Vector& param1, Vec& v1, typename Kernel::Vector& param2, Vec& v2) { + template + void calculatePseudo(const E::MatrixBase& param1, Vec& v1, const E::MatrixBase& param2, Vec& v2) { assert(false); }; void setScale(Scalar scale) { assert(false); }; - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { assert(false); return 0; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { assert(false); return 0; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { assert(false); return 0; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; }; @@ -267,22 +285,35 @@ struct Orientation : public Equation { option_type value; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { assert(false); return 0; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { assert(false); return 0; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { assert(false); return 0; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; }; @@ -307,22 +338,35 @@ struct Angle : public Equation { option_type value; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { assert(false); return 0; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { assert(false); return 0; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { assert(false); return 0; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; }; diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 2e788f8de55b..97b6a8021bab 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -37,12 +38,13 @@ #include "logging.hpp" #include "defines.hpp" #include "multimap.hpp" +#include "property.hpp" +namespace E = Eigen; +namespace mpl= boost::mpl; namespace dcm { -namespace E = Eigen; - struct nothing { void operator()() {}; }; @@ -54,6 +56,18 @@ enum ParameterType { complete //all parameter }; +//solver settings +struct precision { + + typedef double type; + typedef setting_property kind; + struct default_value { + double operator()() { + return 1e-6; + }; + }; +}; + template struct Dogleg { @@ -62,9 +76,10 @@ struct Dogleg { #endif typedef typename Kernel::number_type number_type; - number_type tolg, tolx, tolf; + number_type tolg, tolx; + Kernel* m_kernel; - Dogleg() : tolg(1e-40), tolx(1e-20), tolf(1e-6) { + Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20){ #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); @@ -190,7 +205,7 @@ struct Dogleg { while(!stop) { // check if finished - if(fx_inf <= tolf*sys.Scaling) // Success + if(fx_inf <= m_kernel->template getProperty()*sys.Scaling) // Success stop = 1; else if(g_inf <= tolg) @@ -318,7 +333,7 @@ struct Dogleg { }; template class Nonlinear = Dogleg> -struct Kernel { +struct Kernel : public PropertyOwner< mpl::vector > { //basics typedef Scalar number_type; @@ -489,34 +504,49 @@ struct Kernel { }; virtual void recalculate() = 0; - virtual void removeLocalGradientZeros() = 0; + virtual void removeLocalGradientZeros() = 0; }; Kernel() {}; + //static comparison versions template - static bool isSame(const E::MatrixBase& p1,const E::MatrixBase& p2) { - return ((p1-p2).squaredNorm() < 0.00001); + static bool isSame(const E::MatrixBase& p1,const E::MatrixBase& p2, number_type precission) { + return ((p1-p2).squaredNorm() < precission); } - static bool isSame(number_type t1, number_type t2) { - return (std::abs(t1-t2) < 0.00001); + static bool isSame(number_type t1, number_type t2, number_type precission) { + return (std::abs(t1-t2) < precission); } template - static bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { - return ((p1+p2).squaredNorm() < 0.00001); + static bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2, number_type precission) { + return ((p1+p2).squaredNorm() < precission); } - static int solve(MappedEquationSystem& mes) { + //runtime comparison versions (which use user settings for precission) + template + bool isSame(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1-p2).squaredNorm() < getProperty()); + } + bool isSame(number_type t1, number_type t2) { + return (std::abs(t1-t2) < getProperty()); + } + template + bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1+p2).squaredNorm() < getProperty()); + } + + int solve(MappedEquationSystem& mes) { nothing n; - return Nonlinear< Kernel >().solve(mes, n); + return NonlinearSolver(this).solve(mes, n); }; template - static int solve(MappedEquationSystem& mes, Functor& f) { - return Nonlinear< Kernel >().solve(mes, f); + int solve(MappedEquationSystem& mes, Functor& f) { + return NonlinearSolver(this).solve(mes, f); }; - + + typedef mpl::vector1 properties; }; } diff --git a/src/Mod/Assembly/App/opendcm/core/property.hpp b/src/Mod/Assembly/App/opendcm/core/property.hpp index 1c3e63d363b2..fe8b4ba081c5 100644 --- a/src/Mod/Assembly/App/opendcm/core/property.hpp +++ b/src/Mod/Assembly/App/opendcm/core/property.hpp @@ -23,17 +23,24 @@ #include #include #include -#include -#include #include #include #include #include +#include + +#include +#include +#include +#include +#include #include #include -#include "kernel.hpp" +#include + +#include "defines.hpp" namespace mpl = boost::mpl; namespace fusion = boost::fusion; diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp index 371ddbcc4de5..f3398a85cae5 100644 --- a/src/Mod/Assembly/App/opendcm/core/system.hpp +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -161,7 +161,7 @@ class System : public T1::template type< System >::inherit typedef typename details::vertex_fold< properties, mpl::vector1 >::type vertex_properties; typedef typename details::cluster_fold< properties, - mpl::vector2 >::type cluster_properties; + mpl::vector2 >::type cluster_properties; protected: //object storage @@ -277,15 +277,41 @@ class System : public T1::template type< System >::inherit return s; }; + //a kernel has it's own settings, therefore we need to decide which is accessed template - typename Setting::type& getSetting() { + typename boost::enable_if< boost::is_same< typename mpl::find::type, + typename mpl::end::type >, typename Setting::type& >::type getSetting() { return m_settings.template getProperty(); }; template - void setSetting(typename Setting::type value){ + typename boost::disable_if< boost::is_same< typename mpl::find::type, + typename mpl::end::type >, typename Setting::type& >::type getSetting() { + return m_kernel.template getProperty(); + }; + + template + typename boost::enable_if< boost::is_same< typename mpl::find::type, + typename mpl::end::type >, void >::type setSetting(typename Setting::type value){ m_settings.template setProperty(value); }; + + template + typename boost::disable_if< boost::is_same< typename mpl::find::type, + typename mpl::end::type >, void >::type setSetting(typename Setting::type value){ + m_kernel.template setProperty(value); + }; + + //convinience function + template + typename Setting::type& setting() { + return getSetting(); + }; + + //let evryone access and use our math kernel + Kernel& kernel() { + return m_kernel; + }; private: struct cloner { @@ -344,3 +370,4 @@ class System : public T1::template type< System >::inherit + diff --git a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp index 46067fadba10..f72b56adaeef 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/angle.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/angle.hpp @@ -28,49 +28,49 @@ namespace dcm { //the calculations( same as we always calculate directions we can outsource the work to this functions) namespace angle_detail { -template -inline typename Kernel::number_type calc(const T& d1, - const T& d2, +template +inline typename Kernel::number_type calc(const E::MatrixBase& d1, + const E::MatrixBase& d2, const typename Kernel::number_type& angle) { return d1.dot(d2) / (d1.norm()*d2.norm()) - std::cos(angle); }; -template -inline typename Kernel::number_type calcGradFirst(const T& d1, - const T& d2, - const T& dd1) { +template +inline typename Kernel::number_type calcGradFirst(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& dd1) { typename Kernel::number_type norm = d1.norm()*d2.norm(); return dd1.dot(d2)/norm - (d1.dot(d2) * (d1.dot(dd1)/d1.norm())*d2.norm()) / std::pow(norm,2); }; -template -inline typename Kernel::number_type calcGradSecond(const T& d1, - const T& d2, - const T& dd2) { +template +inline typename Kernel::number_type calcGradSecond(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& dd2) { typename Kernel::number_type norm = d1.norm()*d2.norm(); return d1.dot(dd2)/norm - (d1.dot(d2) * (d2.dot(dd2)/d2.norm())*d1.norm()) / std::pow(norm,2); }; -template -inline void calcGradFirstComp(const T& d1, - const T& d2, - const T& grad) { +template +inline void calcGradFirstComp(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& grad) { typename Kernel::number_type norm = d1.norm()*d2.norm(); - const_cast< T& >(grad) = d2/norm - d1.dot(d2)*d1/(std::pow(d1.norm(),3)*d2.norm()); + const_cast< E::MatrixBase& >(grad) = d2/norm - d1.dot(d2)*d1/(std::pow(d1.norm(),3)*d2.norm()); }; -template -inline void calcGradSecondComp(const T& d1, - const T& d2, - const T& grad) { +template +inline void calcGradSecondComp(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& grad) { typename Kernel::number_type norm = d1.norm()*d2.norm(); - const_cast< T& >(grad) = d1/norm - d1.dot(d2)*d2/(std::pow(d2.norm(),3)*d1.norm()); + const_cast< E::MatrixBase& >(grad) = d1/norm - d1.dot(d2)*d2/(std::pow(d2.norm(),3)*d1.norm()); }; } @@ -85,20 +85,33 @@ struct Angle::type< Kernel, tag::line3D, tag::line3D > : public dcm::PseudoScale option_type value; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return angle_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), value); }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return angle_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), dparam1.template segment<3>(3)); }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return angle_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), dparam2.template segment<3>(3)); }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); angle_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), gradient.template segment<3>(3)); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); angle_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), gradient.template segment<3>(3)); }; @@ -112,7 +125,10 @@ struct Angle::type< Kernel, tag::line3D, tag::cylinder3D > : public Angle::type< typedef typename Kernel::VectorMap Vector; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Angle::type::calculateGradientSecondComplete(param1, param2, gradient); gradient(6)=0; }; @@ -126,7 +142,10 @@ struct Angle::type< Kernel, tag::plane3D, tag::cylinder3D > : public Angle::type typedef typename Kernel::VectorMap Vector; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Angle::type::calculateGradientSecondComplete(param1, param2, gradient); gradient(6)=0; }; @@ -137,12 +156,18 @@ struct Angle::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Angle::t typedef typename Kernel::VectorMap Vector; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Angle::type::calculateGradientFirstComplete(param1, param2, gradient); gradient(6)=0; }; - - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Angle::type::calculateGradientSecondComplete(param1, param2, gradient); gradient(6)=0; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp index 1d3be6e6df86..db466e8f90a8 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/clustermath.hpp @@ -492,7 +492,7 @@ typename ClusterMath::Scalar ClusterMath::calculateClusterScale() { const typename Kernel::Vector3 p1 = m_points[0]; const typename Kernel::Vector3 p2 = m_points[1]; - if(Kernel::isSame((p1-p2).norm(), 0.)) + if(Kernel::isSame((p1-p2).norm(), 0., 1e-10)) return calcOnePoint(p1); return calcTwoPoints(p1, p2); @@ -505,16 +505,16 @@ typename ClusterMath::Scalar ClusterMath::calculateClusterScale() { const typename Kernel::Vector3 d = p2-p1; const typename Kernel::Vector3 e = p3-p1; - if(Kernel::isSame(d.norm(), 0.)) { + if(Kernel::isSame(d.norm(), 0., 1e-10)) { - if(Kernel::isSame(e.norm(), 0.)) + if(Kernel::isSame(e.norm(), 0., 1e-10)) return calcOnePoint(p1); return calcTwoPoints(p1, p3); - } else if(Kernel::isSame(e.norm(), 0.)) { + } else if(Kernel::isSame(e.norm(), 0., 1e-10)) { return calcTwoPoints(p1, p2); - } else if(!Kernel::isSame((d/d.norm() - e/e.norm()).norm(), 0.) && - !Kernel::isSame((d/d.norm() + e/e.norm()).norm(), 0.)) { + } else if(!Kernel::isSame((d/d.norm() - e/e.norm()).norm(), 0., 1e-10) && + !Kernel::isSame((d/d.norm() + e/e.norm()).norm(), 0., 1e-10)) { return calcThreePoints(p1, p2, p3); } //three points on a line need to be treaded as multiple points @@ -633,12 +633,12 @@ void ClusterMath::applyClusterScale(Scalar scale, bool isFixed) { } //if this is our scale then just applie the midpoint as shift - if(Kernel::isSame(scale, m_scale)) { + if(Kernel::isSame(scale, m_scale, 1e-10)) { } //if only one point exists we extend the origin-point-line to match the scale else if(mode==details::one) { - if(Kernel::isSame(midpoint.norm(),0)) + if(Kernel::isSame(midpoint.norm(),0, 1e-10)) midpoint << scale, 0, 0; else midpoint += scale*scale_dir; } @@ -735,7 +735,7 @@ typename ClusterMath::Scalar ClusterMath::calcTwoPoints(const typename midpoint = p1+(p2-p1)/2.; scale_dir = (p2-p1).cross(midpoint); scale_dir = scale_dir.cross(p2-p1); - if(!Kernel::isSame(scale_dir.norm(),0)) scale_dir.normalize(); + if(!Kernel::isSame(scale_dir.norm(),0, 1e-10)) scale_dir.normalize(); else scale_dir(0) = 1; mode = details::two; m_scale = (p2-p1).norm()/2.; diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index 7bc899094a28..d0adbf52da7f 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -47,22 +47,35 @@ struct ci_orientation : public Equation { typedef std::vector > Vec; option_type value; - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { assert(false); return 0; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { assert(false); return 0; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { assert(false); return 0; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; }; @@ -75,19 +88,32 @@ struct ci_orientation::type< Kernel, tag::point3D, tag::point3D > : public dcm:: typedef typename Kernel::VectorMap Vector; option_type value; - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return 0; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return 0; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return 0; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.setZero(); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.setZero(); }; }; @@ -138,22 +164,35 @@ struct ci_distance : public Equation { typedef std::vector > Vec; option_type value; - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { assert(false); return 0; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { assert(false); return 0; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { assert(false); return 0; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { assert(false); }; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp index 08d4bc67aae8..5396621586b9 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -39,19 +39,32 @@ struct Distance::type< Kernel, tag::point3D, tag::point3D > { void setScale(Scalar scale) { sc_value = value*scale; }; - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return (param1-param2).norm() - sc_value; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return (param1-param2).dot(dparam1) / (param1-param2).norm(); }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return (param1-param2).dot(-dparam2) / (param1-param2).norm(); }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient = (param1-param2) / (param1-param2).norm(); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient = (param2-param1) / (param1-param2).norm(); }; }; @@ -88,7 +101,8 @@ struct Distance::type< Kernel, tag::point3D, tag::line3D > { void setScale(Scalar scale) { sc_value = value*scale; }; - Scalar calculate(Vector& point, Vector& line) { + template + Scalar calculate(const E::MatrixBase& point, const E::MatrixBase& line) { //diff = point1 - point2 n = line.template segment<3>(3); diff = line.template head<3>() - point.template head<3>(); @@ -101,7 +115,10 @@ struct Distance::type< Kernel, tag::point3D, tag::line3D > { return res; }; - Scalar calculateGradientFirst(Vector& point, Vector& line, Vector& dpoint) { + template + Scalar calculateGradientFirst(const E::MatrixBase& point, + const E::MatrixBase& line, + const E::MatrixBase& dpoint) { if(dist.norm() == 0) return 1.; @@ -117,7 +134,10 @@ struct Distance::type< Kernel, tag::point3D, tag::line3D > { return res; }; - Scalar calculateGradientSecond(Vector& point, Vector& line, Vector& dline) { + template + Scalar calculateGradientSecond(const E::MatrixBase& point, + const E::MatrixBase& line, + const E::MatrixBase& dline) { if(dist.norm() == 0) return 1.; @@ -134,7 +154,10 @@ struct Distance::type< Kernel, tag::point3D, tag::line3D > { return res; }; - void calculateGradientFirstComplete(Vector& point, Vector& line, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& point, + const E::MatrixBase& line, + E::MatrixBase& gradient) { if(dist.norm() == 0) { gradient.head(3).setOnes(); return; @@ -144,7 +167,10 @@ struct Distance::type< Kernel, tag::point3D, tag::line3D > { gradient.head(3) = res/dist.norm(); }; - void calculateGradientSecondComplete(Vector& point, Vector& line, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& point, + const E::MatrixBase& line, + E::MatrixBase& gradient) { if(dist.norm() == 0) { gradient.head(6).setOnes(); return; @@ -191,7 +217,8 @@ struct Distance::type< Kernel, tag::point3D, tag::plane3D > { void setScale(Scalar scale) { sc_value = value*scale; }; - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance const Scalar res = (param1.head(3)-param2.head(3)).dot(param2.tail(3)) / param2.tail(3).norm() - sc_value; #ifdef USE_LOGGING @@ -201,7 +228,10 @@ struct Distance::type< Kernel, tag::point3D, tag::plane3D > { return res; }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { //dp1°n / |n| //if(dparam1.norm()!=1) return 0; const Scalar res = (dparam1.head(3)).dot(param2.tail(3)) / param2.tail(3).norm(); @@ -212,7 +242,10 @@ struct Distance::type< Kernel, tag::point3D, tag::plane3D > { return res; }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { const typename Kernel::Vector3 p1 = param1.head(3); const typename Kernel::Vector3 p2 = param2.head(3); @@ -228,11 +261,17 @@ struct Distance::type< Kernel, tag::point3D, tag::plane3D > { return res; }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient = param2.tail(3) / param2.tail(3).norm(); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { const typename Kernel::Vector3 p1m2 = param1.head(3) - param2.head(3); const typename Kernel::Vector3 n = param2.tail(3); @@ -252,13 +291,17 @@ struct Distance::type< Kernel, tag::point3D, tag::cylinder3D > : public Distance Distance::type< Kernel, tag::point3D, tag::line3D >::tag.set("Distance point3D cylinder3D"); }; #endif - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance const Scalar res = Distance::type< Kernel, tag::point3D, tag::line3D >::calculate(param1, param2); return res - param2(6); }; - void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + template + void calculateGradientSecondComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { Distance::type< Kernel, tag::point3D, tag::line3D >::calculateGradientSecondComplete(p1,p2,g); g(6) = -1; }; @@ -309,12 +352,13 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { void setScale(Scalar scale) { sc_value = value*scale; }; - Scalar calculate(Vector& line1, Vector& line2) { + template + Scalar calculate(const E::MatrixBase& line1, const E::MatrixBase& line2) { //diff = point1 - point2 n1 = line1.template segment<3>(3); n2 = line2.template segment<3>(3); nxn = n1.cross(n2); - nxn_n = nxn.norm(); + nxn_n = nxn.norm(); c = line2.template head<3>() - line1.template head<3>(); cdn = c.dot(nxn); const Scalar res = std::abs(cdn) / nxn.norm(); @@ -325,7 +369,10 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { return res; }; - Scalar calculateGradientFirst(Vector& line1, Vector& line2, Vector& dline1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& line1, + const E::MatrixBase& line2, + const E::MatrixBase& dline1) { if(nxn_n == 0) return 1.; @@ -334,7 +381,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn_n; //absoulute value requires diffrent differentation for diffrent results - if(cdn <= 0) diff *= -1; + if(cdn <= 0) + diff *= -1; diff /= std::pow(nxn_n,2); @@ -347,7 +395,10 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { return diff; }; - Scalar calculateGradientSecond(Vector& line1, Vector& line2, Vector& dline2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& line1, + const E::MatrixBase& line2, + const E::MatrixBase& dline2) { if(nxn_n == 0) return 1.; @@ -356,7 +407,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { diff -= c.dot(nxn)*nxn.dot(nxn_diff)/nxn_n; //absoulute value requires diffrent differentation for diffrent results - if(cdn <= 0) diff *= -1; + if(cdn <= 0) + diff *= -1; diff /= std::pow(nxn_n,2); @@ -369,7 +421,10 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { return diff; }; - void calculateGradientFirstComplete(Vector& line1, Vector& line2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& line1, + const E::MatrixBase& line2, + E::MatrixBase& gradient) { if(nxn_n == 0) { gradient.head(3).setOnes(); return; @@ -378,13 +433,17 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { if(cdn >= 0) { gradient.template head<3>() = -nxn/nxn_n; gradient.template segment<3>(3) = (c.cross(-n2)*nxn_n-c.dot(nxn)*n2.cross(nxn)/nxn_n)/std::pow(nxn_n,2); - } else { + } + else { gradient.template head<3>() = nxn/nxn_n; gradient.template segment<3>(3) = (-c.cross(-n2)*nxn_n+c.dot(nxn)*n2.cross(nxn)/nxn_n)/std::pow(nxn_n,2); } }; - void calculateGradientSecondComplete(Vector& line1, Vector& line2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& line1, + const E::MatrixBase& line2, + E::MatrixBase& gradient) { if(nxn_n == 0) { gradient.head(3).setOnes(); return; @@ -393,7 +452,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { if(cdn >= 0) { gradient.template head<3>() = nxn/nxn_n; gradient.template segment<3>(3) = (c.cross(n1)*nxn_n-c.dot(nxn)*((-n1).cross(nxn))/nxn_n)/std::pow(nxn_n,2); - } else { + } + else { gradient.template head<3>() = -nxn/nxn_n; gradient.template segment<3>(3) = (-c.cross(n1)*nxn_n+c.dot(nxn)*((-n1).cross(nxn))/nxn_n)/std::pow(nxn_n,2); } @@ -410,10 +470,14 @@ struct Distance::type< Kernel, tag::line3D, tag::plane3D > : public Distance::ty }; #endif typedef typename Kernel::VectorMap Vector; - void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { - typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); + + template + void calculateGradientFirstComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { + typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,grad); - g.segment(3,3).setZero(); + g.segment(3,3).setZero(); }; }; @@ -429,13 +493,17 @@ struct Distance::type< Kernel, tag::line3D, tag::cylinder3D > : public Distance: }; #endif - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance const Scalar res = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2); return res - param2(6); }; - void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + template + void calculateGradientSecondComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientSecondComplete(p1,p2,g); g(6) = -1; }; @@ -451,8 +519,12 @@ struct Distance::type< Kernel, tag::plane3D, tag::plane3D > : public Distance::t }; #endif typedef typename Kernel::VectorMap Vector; - void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { - typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); + + template + void calculateGradientFirstComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { + typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p1,p2,grad); g.segment(3,3).setZero(); }; @@ -471,26 +543,39 @@ struct Distance::type< Kernel, tag::plane3D, tag::cylinder3D > : public Distance }; #endif - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance const Scalar res = Distance::type< Kernel, tag::point3D, tag::plane3D >::calculate(param2, param1); return res - param2(6); }; - Scalar calculateGradientFirst(Vector& p1, Vector& p2, Vector& dp1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& p1, + const E::MatrixBase& p2, + const E::MatrixBase& dp1) { return Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientSecond(p2,p1,dp1); }; - Scalar calculateGradientSecond(Vector& p1, Vector& p2, Vector& dp2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& p1, + const E::MatrixBase& p2, + const E::MatrixBase& dp2) { return Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirst(p2,p1,dp2); }; - void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + template + void calculateGradientFirstComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientSecondComplete(p2,p1,g); }; - void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { - typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); + template + void calculateGradientSecondComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { + typename Kernel::VectorMap grad(&g(0), 3, typename Kernel::DynStride(1,1)); Distance::type< Kernel, tag::point3D, tag::plane3D >::calculateGradientFirstComplete(p2,p1,grad); g.segment(3,3).setZero(); g(6) = -1; @@ -509,18 +594,25 @@ struct Distance::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public Dista }; #endif - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance const Scalar res = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2); return res - param1(6) - param2(6); }; - void calculateGradientFirstComplete(Vector& p1, Vector& p2, Vector& g) { + template + void calculateGradientFirstComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientFirstComplete(p1,p2,g); g(6) = -1; }; - void calculateGradientSecondComplete(Vector& p1, Vector& p2, Vector& g) { + template + void calculateGradientSecondComplete(const E::MatrixBase& p1, + const E::MatrixBase& p2, + E::MatrixBase& g) { Distance::type< Kernel, tag::line3D, tag::line3D >::calculateGradientSecondComplete(p1,p2,g); g(6) = -1; }; diff --git a/src/Mod/Assembly/App/opendcm/module3d/dof.hpp b/src/Mod/Assembly/App/opendcm/module3d/dof.hpp index dbfc79eb11ec..f2356e35b472 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/dof.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/dof.hpp @@ -69,7 +69,7 @@ class Dof { tp1 = std::make_pair(v, constraint); } else if(m_translation == plane) { - if(K::isSame(tp1.first, v) || K::isOpposite(tp1.first, v)) { + if(K::isSame(tp1.first, v, 1e-6) || K::isOpposite(tp1.first, v, 1e-6)) { ConstraintVector cv; cv.push_back(tp1.second); return std::make_pair(false,cv); @@ -107,7 +107,7 @@ class Dof { return std::make_pair(false, ConstraintVector()); //error as every function call removes 2 dof's } else if(m_rotation == line) { - if(K::isSame(rp1.first, v) || K::isOpposite(rp1.first, v)) { + if(K::isSame(rp1.first, v, 1e-6) || K::isOpposite(rp1.first, v, 1e-6)) { ConstraintVector cv; cv.push_back(rp1.second); return std::make_pair(false, cv); diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index b30fedb5c93f..650fe083331e 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -171,7 +171,7 @@ struct Module3D { void recalculated(); void removed(); - friend class Constraint3D; + friend struct Constraint3D; }; template @@ -213,7 +213,7 @@ struct Module3D { friend struct details::ClusterMath::map_downstream; friend struct details::SystemSolver; friend struct details::SystemSolver::Rescaler; - friend class inheriter_base; + friend struct inheriter_base; public: //the geometry class itself does not hold an aligned eigen object, but maybe the variant diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp index 2dafc2043d57..0acba8bb0495 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -32,128 +32,130 @@ namespace dcm { //the calculations( same as we always calculate directions we can outsource the work to this functions) namespace orientation_detail { -template -inline typename Kernel::number_type calc(const T& d1, - const T& d2, +template +inline typename Kernel::number_type calc(const E::MatrixBase& d1, + const E::MatrixBase& d2, const Direction& dir) { switch(dir) { - case parallel: - if(d1.dot(d2) < 0) - return (d1+d2).norm(); - case equal: - return (d1-d2).norm(); - case opposite: + case parallel: + if(d1.dot(d2) < 0) return (d1+d2).norm(); - case perpendicular: - return d1.dot(d2); - default: - assert(false); + case equal: + return (d1-d2).norm(); + case opposite: + return (d1+d2).norm(); + case perpendicular: + return d1.dot(d2); + default: + assert(false); } return 0; }; -template -inline typename Kernel::number_type calcGradFirst(const T& d1, - const T& d2, - const T& dd1, +template +inline typename Kernel::number_type calcGradFirst(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& dd1, const Direction& dir) { typename Kernel::number_type res; switch(dir) { - case parallel: - if(d1.dot(d2) < 0) { - res= ((d1+d2).dot(dd1) / (d1+d2).norm()); - break; - } - case equal: - res = ((d1-d2).dot(dd1) / (d1-d2).norm()); - break; - case opposite: + case parallel: + if(d1.dot(d2) < 0) { res= ((d1+d2).dot(dd1) / (d1+d2).norm()); break; - case perpendicular: - res = dd1.dot(d2); - break; + } + case equal: + res = ((d1-d2).dot(dd1) / (d1-d2).norm()); + break; + case opposite: + res= ((d1+d2).dot(dd1) / (d1+d2).norm()); + break; + case perpendicular: + res = dd1.dot(d2); + break; } - if(isfinite(res)) return res; + if(isfinite(res)) + return res; return 0; }; -template -inline typename Kernel::number_type calcGradSecond(const T& d1, - const T& d2, - const T& dd2, +template +inline typename Kernel::number_type calcGradSecond(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& dd2, const Direction& dir) { typename Kernel::number_type res; switch(dir) { - case parallel: - if(d1.dot(d2) < 0) { - res = ((d1+d2).dot(dd2) / (d1+d2).norm()); - break; - } - case equal: - res = ((d1-d2).dot(-dd2) / (d1-d2).norm()); - break; - case opposite: + case parallel: + if(d1.dot(d2) < 0) { res = ((d1+d2).dot(dd2) / (d1+d2).norm()); break; - case perpendicular: - res = d1.dot(dd2); - break; + } + case equal: + res = ((d1-d2).dot(-dd2) / (d1-d2).norm()); + break; + case opposite: + res = ((d1+d2).dot(dd2) / (d1+d2).norm()); + break; + case perpendicular: + res = d1.dot(dd2); + break; } - if((isfinite)(res)) return res; + if((isfinite)(res)) + return res; return 0; }; -template -inline void calcGradFirstComp(const T& d1, - const T& d2, - const T& grad, +template +inline void calcGradFirstComp(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& grad, const Direction& dir) { switch(dir) { - case parallel: - if(d1.dot(d2) < 0) { - const_cast< T& >(grad) = (d1+d2) / (d1+d2).norm(); - return; - } - case equal: - const_cast< T& >(grad) = (d1-d2) / (d1-d2).norm(); - return; - case opposite: - const_cast< T& >(grad) = (d1+d2) / (d1+d2).norm(); - return; - case perpendicular: - const_cast< T& >(grad) = d2; + case parallel: + if(d1.dot(d2) < 0) { + const_cast< E::MatrixBase& >(grad) = (d1+d2) / (d1+d2).norm(); return; + } + case equal: + const_cast< E::MatrixBase& >(grad) = (d1-d2) / (d1-d2).norm(); + return; + case opposite: + const_cast< E::MatrixBase& >(grad) = (d1+d2) / (d1+d2).norm(); + return; + case perpendicular: + const_cast< E::MatrixBase& >(grad) = d2; + return; } }; -template -inline void calcGradSecondComp(const T& d1, - const T& d2, - const T& grad, +template +inline void calcGradSecondComp(const E::MatrixBase& d1, + const E::MatrixBase& d2, + const E::MatrixBase& grad, const Direction& dir) { switch(dir) { - case parallel: - if(d1.dot(d2) < 0) { - const_cast< T& >(grad) = (d2+d1) / (d1+d2).norm(); - return; - } - case equal: - const_cast< T& >(grad) = (d2-d1) / (d1-d2).norm(); - return; - case opposite: - const_cast< T& >(grad) = (d2+d1) / (d1+d2).norm(); - return; - case perpendicular: - const_cast< T& >(grad) = d1; + case parallel: + if(d1.dot(d2) < 0) { + const_cast< E::MatrixBase& >(grad) = (d2+d1) / (d1+d2).norm(); return; + } + case equal: + const_cast< E::MatrixBase& >(grad) = (d2-d1) / (d1-d2).norm(); + return; + case opposite: + const_cast< E::MatrixBase& >(grad) = (d2+d1) / (d1+d2).norm(); + return; + case perpendicular: + const_cast< E::MatrixBase& >(grad) = d1; + return; } }; @@ -168,20 +170,33 @@ struct Orientation::type< Kernel, tag::direction3D, tag::direction3D > : public option_type value; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return orientation_detail::calc(param1, param2, value); }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return orientation_detail::calcGradFirst(param1, param2, dparam1, value); }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return orientation_detail::calcGradSecond(param1, param2, dparam2, value); }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradFirstComp(param1, param2, gradient, value); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradSecondComp(param1, param2, gradient, value); }; @@ -196,31 +211,44 @@ struct Orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::Pseud option_type value; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return orientation_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), value); }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return orientation_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), dparam1.template segment<3>(3), value); }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return orientation_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), dparam2.template segment<3>(3), value); }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), gradient.template segment<3>(3), value); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), @@ -246,31 +274,44 @@ struct Orientation::type< Kernel, tag::line3D, tag::plane3D > : public Orientati }; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return orientation_detail::calc(param1.template segment<3>(3), param2.template segment<3>(3), getValue()); }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return orientation_detail::calcGradFirst(param1.template segment<3>(3), param2.template segment<3>(3), dparam1.template segment<3>(3), getValue()); }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return orientation_detail::calcGradSecond(param1.template segment<3>(3), param2.template segment<3>(3), dparam2.template segment<3>(3), getValue()); }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), gradient.template segment<3>(3), getValue()); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), @@ -285,7 +326,10 @@ struct Orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public Orient typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Orientation::type::calculateGradientSecondComplete(param1, param2, gradient); gradient(6)=0; }; @@ -303,19 +347,32 @@ struct Orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public Orien using Orientation::type::value; //template definition - Scalar calculate(Vector& param1, Vector& param2) { + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { return Orientation::type::calculate(param1, param2); }; - Scalar calculateGradientFirst(Vector& param1, Vector& param2, Vector& dparam1) { + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { return Orientation::type::calculateGradientFirst(param1, param2, dparam1); }; - Scalar calculateGradientSecond(Vector& param1, Vector& param2, Vector& dparam2) { + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { return Orientation::type::calculateGradientSecond(param1, param2, dparam2); }; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Orientation::type::calculateGradientFirstComplete(param1, param2, gradient); }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { Orientation::type::calculateGradientSecondComplete(param1, param2, gradient); gradient(6)=0; }; @@ -326,7 +383,10 @@ struct Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public O typedef typename Kernel::VectorMap Vector; - void calculateGradientFirstComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradFirstComp(param1.template segment<3>(3), param2.template segment<3>(3), @@ -334,7 +394,10 @@ struct Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public O Orientation::type< Kernel, tag::line3D, tag::line3D >::value); gradient(6) = 0; }; - void calculateGradientSecondComplete(Vector& param1, Vector& param2, Vector& gradient) { + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { gradient.template head<3>().setZero(); orientation_detail::calcGradSecondComp(param1.template segment<3>(3), param2.template segment<3>(3), diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index 6c347e5468e8..9a231abb84c0 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -209,7 +209,7 @@ typename SystemSolver::Scalar SystemSolver::Rescaler::scaleClusters() sc = (s>sc) ? s : sc; } //if no scaling-value returned we can use 1 - sc = (Kernel::isSame(sc,0)) ? 1. : sc; + sc = (Kernel::isSame(sc,0, 1e-10)) ? 1. : sc; typedef typename boost::graph_traits::vertex_iterator iter; std::pair it = boost::vertices(*cluster); @@ -241,7 +241,7 @@ void SystemSolver::Rescaler::collectPseudoPoints( std::pair it = boost::out_edges(cluster, *parent); for(; it.first != it.second; it.first++) { - std::pair< c_iter, c_iter > cit = parent->template getGlobalEdges(*it.first); + std::pair< c_iter, c_iter > cit = parent->getGlobalEdges(*it.first); for(; cit.first != cit.second; cit.first++) { Cons c = parent->template getObject(*cit.first); @@ -390,7 +390,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy BOOST_LOG(log)<< "No rotation parameters in system, solve without scaling"; #endif DummyScaler re; - Kernel::solve(mes, re); + sys.kernel().solve(mes, re); } else { @@ -422,7 +422,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //solve can be done without catching exceptions, because this only fails if the system in //unsolvable DummyScaler re; - Kernel::solve(mes, re); + sys.kernel().solve(mes, re); //now let's see if we have to go on with the translations mes.setAccess(general); @@ -434,7 +434,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //let's try translation only try { DummyScaler re; - Kernel::solve(mes, re); + sys.kernel().solve(mes, re); done=true; } catch(boost::exception&) { @@ -451,7 +451,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy #endif Rescaler re(cluster, mes); re(); - Kernel::solve(mes, re); + sys.kernel().solve(mes, re); #ifdef USE_LOGGING BOOST_LOG(log)<< "Numbers of rescale: "<::type::Part_base::addGeometry3D(const T& geom, Coo Geom g(new Geometry3D(geom, *m_system)); if(frame == Local) { //we need to collect all transforms up to this part! - Transform t;//(m_transform); + Transform t; transform_traverse(t, m_cluster); g->transform(t); @@ -325,8 +325,8 @@ ModulePart::type::Part_base::addGeometry3D(const T& geom, Coo template template -void ModulePart::type::Part_base::transform_traverse(ModulePart::type::Part_base::Transform& t, - boost::shared_ptr::type::Part_base::Cluster> c) { +void ModulePart::type::Part_base::transform_traverse(typename ModulePart::type::Part_base::Transform& t, + boost::shared_ptr::type::Part_base::Cluster> c) { t *= c->template getProperty().m_transform; From 710540c0b098c1aa922349c6c911d1b170348514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 3 Oct 2013 10:59:12 +0000 Subject: [PATCH 218/664] line line distance works with parallel lines too --- .../App/opendcm/module3d/distance.hpp | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp index 5396621586b9..921a361fbb77 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -307,7 +307,6 @@ struct Distance::type< Kernel, tag::point3D, tag::cylinder3D > : public Distance }; }; -//TODO: this won't work for parallel lines. switch to point-line distance when lines are parallel template struct Distance::type< Kernel, tag::line3D, tag::line3D > { @@ -319,6 +318,10 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { Scalar value, sc_value, cdn, nxn_n; Vector3 c, n1, n2, nxn; + //if the lines are parallel we need to fall back to point-line distance + //to do this efficently we just hold a point-line distance equation and use it instead + Distance::type pl_eqn; + #ifdef USE_LOGGING src::logger log; attrs::mutable_constant< std::string > tag; @@ -336,6 +339,13 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { const Vector3 n1 = line1.template segment<3>(3); const Vector3 n2 = line2.template segment<3>(3); const Vector3 nxn = n1.cross(n2); + + //parallel lines are treated as point line + if(Kernel::isSame(nxn.norm(), 0, 1e-6)) { + pl_eqn.calculatePseudo(line1, v1, line2, v2); + return; + }; + const Vector3 r = c.cross(nxn)/nxn.squaredNorm(); Vector3 pp1 = line1.template head<3>() + r.dot(n2)*n1; Vector3 pp2 = line2.template head<3>() + r.dot(n1)*n2; @@ -351,6 +361,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { }; void setScale(Scalar scale) { sc_value = value*scale; + pl_eqn.value = value; + pl_eqn.setScale(scale); }; template Scalar calculate(const E::MatrixBase& line1, const E::MatrixBase& line2) { @@ -359,6 +371,10 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { n2 = line2.template segment<3>(3); nxn = n1.cross(n2); nxn_n = nxn.norm(); + + if(Kernel::isSame(nxn_n, 0, 1e-6)) + return pl_eqn.calculate(line1, line2); + c = line2.template head<3>() - line1.template head<3>(); cdn = c.dot(nxn); const Scalar res = std::abs(cdn) / nxn.norm(); @@ -373,8 +389,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { Scalar calculateGradientFirst(const E::MatrixBase& line1, const E::MatrixBase& line2, const E::MatrixBase& dline1) { - if(nxn_n == 0) - return 1.; + if(Kernel::isSame(nxn_n, 0, 1e-6)) + return pl_eqn.calculateGradientFirst(line1, line2, dline1); const Vector3 nxn_diff = dline1.template segment<3>(3).cross(n2); Scalar diff = (-dline1.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn_n; @@ -399,8 +415,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { Scalar calculateGradientSecond(const E::MatrixBase& line1, const E::MatrixBase& line2, const E::MatrixBase& dline2) { - if(nxn_n == 0) - return 1.; + if(Kernel::isSame(nxn_n, 0, 1e-6)) + return pl_eqn.calculateGradientSecond(line1, line2, dline2); const Vector3 nxn_diff = n1.cross(dline2.template segment<3>(3)); Scalar diff = (dline2.template head<3>().dot(nxn)+c.dot(nxn_diff))*nxn_n; @@ -425,8 +441,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { void calculateGradientFirstComplete(const E::MatrixBase& line1, const E::MatrixBase& line2, E::MatrixBase& gradient) { - if(nxn_n == 0) { - gradient.head(3).setOnes(); + if(Kernel::isSame(nxn_n, 0, 1e-6)) { + pl_eqn.calculateGradientFirstComplete(line1, line2, gradient); return; } @@ -444,8 +460,8 @@ struct Distance::type< Kernel, tag::line3D, tag::line3D > { void calculateGradientSecondComplete(const E::MatrixBase& line1, const E::MatrixBase& line2, E::MatrixBase& gradient) { - if(nxn_n == 0) { - gradient.head(3).setOnes(); + if(Kernel::isSame(nxn_n, 0, 1e-6)) { + pl_eqn.calculateGradientFirstComplete(line1, line2, gradient); return; } From 8ec3907a033fd209636cc4bc963dcf053666cd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 3 Oct 2013 11:24:33 +0000 Subject: [PATCH 219/664] test commit --- src/Mod/Assembly/App/opendcm/core.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index b30cd8aec73b..6f6d171df6e6 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -21,18 +21,18 @@ #define DCM_CORE_H #ifdef _WIN32 - //warning about to long decoraded names, won't affect the code correctness - #pragma warning( disable : 4503 ) - //warning about changed pod initalising behaviour (boost blank in variant) - #pragma warning( disable : 4345 ) - - //disable boost concept checks, as some of them have alignment problems which bring msvc to an error - //(for example DFSvisitor check in boost::graph::depht_first_search) - //this has no runtime effect as these are only compile time checks - #include - #undef BOOST_CONCEPT_ASSERT - #define BOOST_CONCEPT_ASSERT(Model) - #include + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) + //warning about changed pod initalising behaviour (boost blank in variant) + #pragma warning( disable : 4345 ) + + //disable boost concept checks, as some of them have alignment problems which bring msvc to an error + //(for example DFSvisitor check in boost::graph::depht_first_search) + //this has no runtime effect as these are only compile time checks + #include + #undef BOOST_CONCEPT_ASSERT + #define BOOST_CONCEPT_ASSERT(Model) + #include #endif From e8dda0b25ab30a67cab01c4034e4df0a233ac13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 3 Oct 2013 12:25:08 +0000 Subject: [PATCH 220/664] add core defines file --- src/Mod/Assembly/App/opendcm/core/defines.hpp | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Mod/Assembly/App/opendcm/core/defines.hpp diff --git a/src/Mod/Assembly/App/opendcm/core/defines.hpp b/src/Mod/Assembly/App/opendcm/core/defines.hpp new file mode 100644 index 000000000000..b6547533bb8e --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/defines.hpp @@ -0,0 +1,41 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_DEFINES_CORE_H +#define GCM_DEFINES_CORE_H + + +#include +#include + +namespace dcm { + +//all solving related errors +typedef boost::error_info error_message; +typedef boost::error_info error_type_first_geometry; +typedef boost::error_info error_type_second_geometry; + +//exception codes are needed by the user +struct creation_error : virtual boost::exception {}; +struct solving_error : virtual boost::exception {}; +struct constraint_error : virtual boost::exception {}; + +} //dcm + +#endif //GCM_DEFINES_CORE_H \ No newline at end of file From 5dea42c9951739ac763eaa87e81aabc237e157bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 3 Oct 2013 12:27:15 +0000 Subject: [PATCH 221/664] multiple files added --- .../Assembly/App/opendcm/core/multimap.hpp | 404 ++++++++++++ .../App/opendcm/module3d/alignment.hpp | 63 ++ .../App/opendcm/moduleShape3d/defines.hpp | 40 ++ .../App/opendcm/moduleShape3d/distance.hpp | 137 ++++ .../App/opendcm/moduleShape3d/fixed.hpp | 87 +++ .../App/opendcm/moduleShape3d/generator.hpp | 223 +++++++ .../App/opendcm/moduleShape3d/geometry.hpp | 45 ++ .../App/opendcm/moduleShape3d/module.hpp | 591 ++++++++++++++++++ .../Assembly/App/opendcm/moduleshape3d.hpp | 35 ++ 9 files changed, 1625 insertions(+) create mode 100644 src/Mod/Assembly/App/opendcm/core/multimap.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/alignment.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleShape3d/defines.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleShape3d/distance.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleshape3d.hpp diff --git a/src/Mod/Assembly/App/opendcm/core/multimap.hpp b/src/Mod/Assembly/App/opendcm/core/multimap.hpp new file mode 100644 index 000000000000..9aa7e34020e1 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/multimap.hpp @@ -0,0 +1,404 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_CORE_MULTIMAP_H +#define DCM_CORE_MULTIMAP_H + +#include +#include +#include +#include +#include + +namespace dcm { +namespace details { +template +class MultiMap; +} +} + +namespace Eigen { +namespace internal { + +template +struct traits > + : public traits { + typedef traits TraitsBase; + typedef typename PlainObjectType::Index Index; + typedef typename PlainObjectType::Scalar Scalar; + enum { + InnerStrideAtCompileTime = int(PlainObjectType::InnerStrideAtCompileTime), + OuterStrideAtCompileTime = int(PlainObjectType::OuterStrideAtCompileTime), + HasNoInnerStride = InnerStrideAtCompileTime == 1, + HasNoOuterStride = OuterStrideAtCompileTime == 1, + HasNoStride = HasNoInnerStride && HasNoOuterStride, + IsAligned = false,//bool(EIGEN_ALIGN), + IsDynamicSize = PlainObjectType::SizeAtCompileTime == Dynamic, + KeepsPacketAccess = bool(HasNoInnerStride) + && (bool(IsDynamicSize) + || HasNoOuterStride + || (OuterStrideAtCompileTime != Dynamic + && ((static_cast(sizeof(Scalar)) * OuterStrideAtCompileTime) % 16) == 0)), + Flags0 = TraitsBase::Flags & (~NestByRefBit), + Flags1 = IsAligned ? (int(Flags0) | AlignedBit) : (int(Flags0) & ~AlignedBit), + Flags2 = (bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime)) + ? int(Flags1) : int(Flags1 & ~LinearAccessBit), + Flags3 = is_lvalue::value ? int(Flags2) : (int(Flags2) & ~LvalueBit), + Flags = KeepsPacketAccess ? int(Flags3) : (int(Flags3) & ~PacketAccessBit) + }; +private: + enum { Options }; // Expressions don't have Options +}; +} //internal +} //Eigen + +namespace dcm { +namespace details { + +using namespace Eigen; //needed for macros +namespace fusion = boost::fusion; + +template +class MultiMapBase : public internal::dense_xpr_base::type { + +public: + + typedef typename internal::dense_xpr_base::type Base; + + enum { + RowsAtCompileTime = internal::traits::RowsAtCompileTime, + ColsAtCompileTime = internal::traits::ColsAtCompileTime, + SizeAtCompileTime = Base::SizeAtCompileTime + }; + + typedef typename internal::traits::StorageKind StorageKind; + typedef typename internal::traits::Index Index; + typedef typename internal::traits::Scalar Scalar; + typedef typename internal::packet_traits::type PacketScalar; + typedef typename NumTraits::Real RealScalar; + typedef typename internal::conditional < + bool(internal::is_lvalue::value), + Scalar*, + const Scalar* >::type + PointerType; + + using Base::derived; + using Base::MaxRowsAtCompileTime; + using Base::MaxColsAtCompileTime; + using Base::MaxSizeAtCompileTime; + using Base::IsVectorAtCompileTime; + using Base::Flags; + using Base::IsRowMajor; + + using Base::size; + using Base::coeff; + using Base::coeffRef; + using Base::lazyAssign; + using Base::eval; + + // bug 217 - compile error on ICC 11.1 + using Base::operator=; + + typedef typename Base::CoeffReturnType CoeffReturnType; + + typedef Stride DynStride; + typedef fusion::vector6 MapData; + + + inline Index rows() const { + return m_rows.value(); + } + inline Index cols() const { + return m_cols.value(); + } + + inline const Scalar* data() const { + assert(false); + return m_data; + } + + inline const Scalar& coeff(Index row, Index col) const { + + typedef typename std::vector::const_iterator iter; + + for(iter i = m_data.begin(); i != m_data.end(); i++) { + const MapData& data = *i; + + if((fusion::at_c<1>(data) + fusion::at_c<3>(data)) > row && fusion::at_c<1>(data) <= row + && (fusion::at_c<2>(data) + fusion::at_c<4>(data)) > col && fusion::at_c<2>(data) <= col) + return fusion::at_c<0>(data)[(col - fusion::at_c<2>(data)) * fusion::at_c<5>(data).outer() + (row - fusion::at_c<1>(data)) * fusion::at_c<5>(data).inner()]; + }; + + return default_value; + } + + inline const Scalar& coeff(Index index) const { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + + typedef typename std::vector::const_iterator iter; + + for(iter i = m_data.begin(); i != m_data.end(); i++) { + const MapData& data = *i; + + if((fusion::at_c<1>(data) + fusion::at_c<3>(data)) > index) + return fusion::at_c<0>(data)[(index - fusion::at_c<1>(data)) * fusion::at_c<5>(data).inner()]; + }; + + return default_value; + } + + inline const Scalar& coeffRef(Index row, Index col) const { + return coeff(row, col); + } + + inline const Scalar& coeffRef(Index index) const { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + return coeff(index); + } + + template + inline PacketScalar packet(Index row, Index col) const { + + typedef typename std::vector::const_iterator iter; + + for(iter i = m_data.begin(); i != m_data.end(); i++) { + const MapData& data = *i; + + if((fusion::at_c<1>(data) + fusion::at_c<3>(data)) > row && fusion::at_c<1>(data) <= row + && (fusion::at_c<2>(data) + fusion::at_c<4>(data)) > col && fusion::at_c<2>(data) <= col) + return internal::ploadt + (fusion::at_c<0>(data) + (col - fusion::at_c<2>(data)) * fusion::at_c<5>(data).outer() + (row - fusion::at_c<1>(data)) * fusion::at_c<5>(data).inner()); + }; + return internal::ploadt(&default_value); + } + + template + inline PacketScalar packet(Index index) const { + EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) + typedef typename std::vector::const_iterator iter; + + for(iter i = m_data.begin(); i != m_data.end(); i++) { + const MapData& data = *i; + + if((fusion::at_c<1>(data) + fusion::at_c<3>(data)) > index) + return internal::ploadt(fusion::at_c<0>(data) + (index - fusion::at_c<1>(data)) * fusion::at_c<5>(data).inner()); + }; + return internal::ploadt(&default_value); + } + + + // constructor for datapointer which resembles the fixed size derived type + // this works only if this is the only maped data! + inline MultiMapBase(PointerType data) + : default_value(0), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { + + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + m_data.push_back(fusion::make_vector(data, 0, 0, m_rows.value(), m_cols.value(), DynStride(Base::outerStride(), Base::innerStride()))); + checkSanity(); + } + + // constructor for datapointer which resembles the derived dynamic size vector + inline MultiMapBase(PointerType data, Index size) + : default_value(0), + m_rows(RowsAtCompileTime == Dynamic ? size : Index(RowsAtCompileTime)), + m_cols(ColsAtCompileTime == Dynamic ? 1 : Index(ColsAtCompileTime)) { + + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(size >= 0); + eigen_assert(data == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == size); + + m_data.push_back(fusion::make_vector(data, 0, 0, size, 1, DynStride(Base::outerStride(), Base::innerStride()))); + checkSanity(); + } + + // constructor for datapointer which resembles the derived dynamic size matrix + // this works only if this matrix is the only mapped data! + inline MultiMapBase(PointerType data, Index rows, Index cols) + : default_value(0), m_rows(rows), m_cols(cols) { + + eigen_assert((data == 0) + || (rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); + + m_data.push_back(fusion::make_vector(data, 0, 0, m_rows.value(), m_cols.value(), DynStride(Base::outerStride(), Base::innerStride()))); + checkSanity(); + } + + //constructor for a data pointer with stride. Data in combination with stride needs to resemble + //the fixed size derived type. This only works if this is the only data + template + inline MultiMapBase(PointerType data, const Stride& stride) + : default_value(0), m_rows(RowsAtCompileTime), m_cols(ColsAtCompileTime) { + + EIGEN_STATIC_ASSERT_FIXED_SIZE(Derived) + m_data.push_back(fusion::make_vector(data, 0, 0, m_rows.value(), m_cols.value(), DynStride(stride.outer(), stride.inner()))); + checkSanity(); + } + + //constructor for a data pointer with stride. Data in combination with stride needs to resemble + //a part or all of the derived vector type. + template + inline MultiMapBase(PointerType data, Index size, const Stride& stride) + : default_value(0), + m_rows(RowsAtCompileTime == Dynamic ? size : Index(RowsAtCompileTime)), + m_cols(ColsAtCompileTime == Dynamic ? size : Index(ColsAtCompileTime)) { + + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(size >= 0); + eigen_assert(data == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == size); + m_data.push_back(fusion::make_vector(data, 0, 0, m_rows.value(), m_cols.value(), DynStride(stride.outer(), stride.inner()))); + checkSanity(); + } + + //constructor for a data pointer with stride. Data in combination with stride needs to resemble + //a part or all of the derived matrix type + template + inline MultiMapBase(PointerType data, Index rows, Index cols, const Stride& stride) + : default_value(0), m_rows(rows), m_cols(cols) { + + eigen_assert((data == 0) + || (rows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == rows) + && cols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == cols))); + m_data.push_back(fusion::make_vector(data, 0, 0, m_rows.value(), m_cols.value(), DynStride(Base::outerStride(), Base::innerStride()))); + checkSanity(); + } + + //constructor for arbitrary dense matrix types. The matrix must resemble a part or all of the + //derived type. + template + inline MultiMapBase(MatrixBase& matrix) + : default_value(0), + m_rows(RowsAtCompileTime == Dynamic ? matrix.rows() : Index(RowsAtCompileTime)), + m_cols(ColsAtCompileTime == Dynamic ? matrix.cols() : Index(ColsAtCompileTime)) { + + m_data.push_back(fusion::make_vector(&matrix(0, 0), 0, 0, matrix.rows(), matrix.cols(), DynStride(matrix.outerStride(), matrix.innerStride()))); + checkSanity(); + }; + + + //map extensions + //************** + + //extend with data vector in derived type form + inline void extend(PointerType data, Index size) { + + extend(data, size, DynStride(Base::outerStride(), Base::innerStride())); + }; + + //extend with data vector in arbitrary form + template + inline void extend(PointerType data, Index size, const Stride& stride) { + + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(size >= 0); + eigen_assert(data == 0 || SizeAtCompileTime == Dynamic || SizeAtCompileTime == size); + + m_data.push_back(fusion::make_vector(data, m_rows.value(), 0, size, 1, DynStride(stride.outer(), stride.inner()))); + m_rows.setValue(m_rows.value() + size); + checkSanity(); + }; + + //extend with eigen vector + template + inline void extend(MatrixBase& matrix) { + + //this only works for vectors, as we would not know where to add a matrix + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + eigen_assert(matrix.cols() == 1); + extend(matrix.derived().data(), matrix.rows(), DynStride(matrix.outerStride(), matrix.innerStride())); + }; + + //extend with general pointer data + template + inline void extend(PointerType matrix, Index row, Index col, Index rows, Index cols, const Stride& stride) { + + m_data.push_back(fusion::make_vector(matrix, row, col, rows, cols, DynStride(stride.outer(), stride.inner()))); + + if((row + rows) > m_rows.value()) + m_rows.setValue(row + rows); + + if((col + cols) > m_cols.value()) + m_cols.setValue(col + cols); + + checkSanity(); + }; + + //extend with pointer data in derived type form + inline void extend(PointerType matrix, Index row, Index col, Index rows, Index cols) { + + extend(matrix.derived().data(), row, col, rows, cols, DynStride(Base::outerStride(), Base::innerStride())); + }; + + //extend with eigen matrix + template + inline void extend(MatrixBase& matrix, Index row, Index col) { + + extend(matrix.derived().data(), row, col, matrix.rows(), matrix.cols(), DynStride(matrix.outerStride(), matrix.innerStride())); + }; + +protected: + + void checkSanity() const { + EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits::Flags & PacketAccessBit, + internal::inner_stride_at_compile_time::ret == 1), + PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1); + eigen_assert(EIGEN_IMPLIES(internal::traits::Flags & AlignedBit, (size_t(fusion::at_c<0>(m_data.back())) % 16) == 0) + && "data is not aligned"); + } + + std::vector m_data; + Scalar default_value; + internal::variable_if_dynamic m_rows; + internal::variable_if_dynamic m_cols; +}; + +//this indirection is needed so that the map base coeff functions are called +template +class MultiMap : public MultiMapBase< MultiMap > { + +public: + typedef MultiMapBase< MultiMap > Base; + EIGEN_DENSE_PUBLIC_INTERFACE(MultiMap) + + inline Index innerStride() const { + return 1; + } + + inline Index outerStride() const { + if(Flags & RowMajorBit) + return Base::m_cols.value(); + else // column-major + return Base::m_rows.value(); + } + + inline MultiMap(typename Base::PointerType matrix) : Base(matrix) {}; + inline MultiMap(typename Base::PointerType matrix, typename Base::Index size) : Base(matrix, size) {}; + inline MultiMap(typename Base::PointerType matrix, + typename Base::Index row, + typename Base::Index col) : Base(matrix, row, col) {}; + + + template + inline MultiMap(MatrixBase& matrix) : Base(matrix) {}; +}; + +} // details +} // dcm + +#endif // EIGEN_MAPBASE_H diff --git a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp new file mode 100644 index 000000000000..6671e4aa2939 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp @@ -0,0 +1,63 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_ALIGNMENT_HPP +#define DCM_ALIGNMENT_HPP + +#include +#include "distance.hpp" + +namespace dcm { + +struct Alignment : public dcm::constraint_sequence< fusion::vector2< Distance, Orientation > > { + //allow to set the distance + Alignment& operator()(Direction val) { + fusion::at_c<1>(*this) = val; + return *this; + }; + Alignment& operator()(double val) { + fusion::at_c<0>(*this) = val; + return *this; + }; + Alignment& operator()(double val1, Direction val2) { + fusion::at_c<0>(*this) = val1; + fusion::at_c<1>(*this) = val2; + return *this; + }; + Alignment& operator()(Direction val1, double val2) { + fusion::at_c<0>(*this) = val2; + fusion::at_c<1>(*this) = val1; + return *this; + }; + Alignment& operator=(Direction val) { + fusion::at_c<1>(*this) = val; + return *this; + }; + Alignment& operator=(double val) { + fusion::at_c<0>(*this) = val; + return *this; + }; +}; + +static Alignment alignment; + +}//dcm + + +#endif //DCM_ALIGNMENT_HPP diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/defines.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/defines.hpp new file mode 100644 index 000000000000..d8b3a0d4220d --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/defines.hpp @@ -0,0 +1,40 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_DEFINES_SHAPE3D_H +#define GCM_DEFINES_SHAPE3D_H + +namespace dcm { + +enum purpose { + startpoint = 1, + midpoint, + endpoint, + line, + circle +}; + +namespace details { + +struct mshape3d {}; //base of modulehlg3d::type to allow other modules check for it + +} //details +} //dcm + +#endif diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/distance.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/distance.hpp new file mode 100644 index 000000000000..8ea55a88b161 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/distance.hpp @@ -0,0 +1,137 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_DISTANCE_SHAPE3D_H +#define GCM_DISTANCE_SHAPE3D_H + +#include +#include +#include +#include +#include + +namespace dcm { + +template +struct Distance::type< Kernel, tag::point3D, tag::segment3D > { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef typename Kernel::Vector3 Vector3; + typedef std::vector > Vec; + + Scalar value, sc_value, cross_n, cross_v12_n, v12_n; + Vector3 v01, v02, v12, cross; + +#ifdef USE_LOGGING + src::logger log; + attrs::mutable_constant< std::string > tag; + + type() : tag("Distance point3D segment3D") { + log.add_attribute("Tag", tag); + }; +#endif + + //template definition + void calculatePseudo(typename Kernel::Vector& point, Vec& v1, typename Kernel::Vector& segment, Vec& v2) { + Vector3 dir = (segment.template head<3>() - segment.template tail<3>()).normalized(); + Vector3 pp = segment.head(3) + (segment.head(3)-point.head(3)).norm()*dir; +#ifdef USE_LOGGING + if(!boost::math::isnormal(pp.norm())) + BOOST_LOG(log) << "Unnormal pseudopoint detected"; +#endif + v2.push_back(pp); + }; + void setScale(Scalar scale) { + sc_value = value*scale; + }; + + template + Scalar calculate(const E::MatrixBase& point, const E::MatrixBase& segment) { + //diff = point1 - point2 + v01 = point-segment.template head<3>(); + v02 = point-segment.template tail<3>(); + v12 = segment.template head<3>() - segment.template tail<3>(); + cross = v01.cross(v02); + v12_n = v12.norm(); + cross_n = cross.norm(); + cross_v12_n = cross_n/std::pow(v12_n,3); + + const Scalar res = cross.norm()/v12_n - sc_value; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal residual detected: "< + Scalar calculateGradientFirst(const E::MatrixBase& point, + const E::MatrixBase& segment, + const E::MatrixBase& dpoint) { + + const Vector3 d_point = dpoint; //eigen only acceppts vector3 for cross product + const Vector3 d_cross = d_point.cross(v02) + v01.cross(d_point); + const Scalar res = cross.dot(d_cross)/(cross_n*v12_n); +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal first cluster gradient detected: "< + Scalar calculateGradientSecond(const E::MatrixBase& point, + const E::MatrixBase& segment, + const E::MatrixBase& dsegment) { + + const Vector3 d_cross = - (dsegment.template head<3>().cross(v02) + v01.cross(dsegment.template tail<3>())); + const Vector3 d_v12 = dsegment.template head<3>() - dsegment.template tail<3>(); + const Scalar res = cross.dot(d_cross)/(cross_n*v12_n) - v12.dot(d_v12)*cross_v12_n; +#ifdef USE_LOGGING + if(!boost::math::isfinite(res)) + BOOST_LOG(log) << "Unnormal second cluster gradient detected: "< + void calculateGradientFirstComplete(const E::MatrixBase& point, + const E::MatrixBase& segment, + E::MatrixBase& gradient) { + //gradient = (v02.cross(cross)+cross.cross(v01))/(cross.norm()*v12_n); + gradient = (v02-v01).cross(cross)/(cross_n*v12_n); + }; + + template + void calculateGradientSecondComplete(const E::MatrixBase& point, + const E::MatrixBase& segment, + E::MatrixBase& gradient) { + gradient.template head<3>() = cross.cross(v02)/(cross_n*v12_n) - v12*cross_v12_n; + gradient.template tail<3>() = v01.cross(cross)/(cross_n*v12_n) + v12*cross_v12_n; + }; +}; + +} + +#endif //GCM_DISTANCE_SHAPE3D_H diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp new file mode 100644 index 000000000000..09f1361feb7a --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp @@ -0,0 +1,87 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_FIXED_SHAPE3D_H +#define GCM_FIXED_SHAPE3D_H + +//we need constraints to identifie connections between geometries in our shapes, however, if the +//geometries are linked to each other a calculation is not necessary. Therfore a no-equation constraint +//is needed + +#include + +namespace dcm { +namespace details { + +//this equation is for internal use only. one needs to ensure the constraint is disabled after adding +//this fixed equation +struct Fixed : public Equation { + + using Equation::operator=; + Fixed() : Equation(parallel) {}; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + + option_type value; + + //we shall not use this equation, warn the user about wrong usage + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { + assert(false); + return 0; + }; + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { + assert(false); + return 0; + }; + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { + assert(false); + return 0; + }; + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { + assert(false); + }; + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { + assert(false); + }; + }; +}; + +static Fixed fixed; + +}//details +} //dcm + +#endif \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp new file mode 100644 index 000000000000..fcd810fa843c --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp @@ -0,0 +1,223 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_GENERATOR_SHAPE3D_H +#define GCM_GENERATOR_SHAPE3D_H + +#include +#include +#include +#include "geometry.hpp" +#include "fixed.hpp" +#include "defines.hpp" + +#include +#include + +namespace dcm { + +namespace details { + +template +struct ShapeGeneratorBase { + + BOOST_MPL_ASSERT((typename system_traits::template getModule::has_module)); + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef typename module3d::Constraint3D Constraint3D; + typedef typename system_traits::template getModule::type moduleShape3d; + typedef typename moduleShape3d::Shape3D Shape3D; + + typedef typename moduleShape3d::shape_purpose_prop shape_purpose_prop; + typedef typename moduleShape3d::shape_geometry_prop shape_geometry_prop; + typedef typename moduleShape3d::shape_constraint_prop shape_constraint_prop; + + Sys* m_system; + boost::shared_ptr m_shape; + std::vector >* m_geometries; + std::vector >* m_shapes; + std::vector >* m_constraints; + + ShapeGeneratorBase(Sys* system) : m_system(system) {}; + virtual ~ShapeGeneratorBase() {}; + + void set(boost::shared_ptr shape, + std::vector >* geometries, + std::vector >* shapes, + std::vector >* constraints) { + + m_shape = shape; + m_geometries = geometries; + m_shapes = shapes; + m_constraints = constraints; + }; + + //check if all needed parts are supplied + virtual bool check() = 0; + //initialise all relations between the geometries + virtual void init() = 0; + //get geometry3d for optional types (e.g. midpoints) + virtual boost::shared_ptr getOrCreateG3d(int type) = 0; + //get hlgeometry3d for optional types + virtual boost::shared_ptr getOrCreateHLG3d(int type) = 0; +}; + +} //details + + +struct dummy_generator { + + template + struct type : public details::ShapeGeneratorBase { + + type(Sys* system) : details::ShapeGeneratorBase(system) {}; + + //check if all needed parts are supplied + virtual bool check() { + throw creation_error() << boost::errinfo_errno(210) << error_message("not all needd types for high level geometry present"); + }; + //initialise all relations between the geometries, throw on error + virtual void init() { + throw creation_error() << boost::errinfo_errno(211) << error_message("dummy generator can't create high level geometry"); + }; + //get geometry3d for optional types (e.g. midpoints) + virtual boost::shared_ptr::Geometry3D> getOrCreateG3d(int type) { + throw creation_error() << boost::errinfo_errno(212) << error_message("dummy generator has no geometry to access"); + }; + //get hlgeometry3d for optional types + virtual boost::shared_ptr::Shape3D> getOrCreateHLG3d(int type) { + throw creation_error() << boost::errinfo_errno(213) << error_message("dummy generator has no high level geometry to access"); + }; + }; +}; + +//test generator +struct segment3D { + + template + struct type : public dcm::details::ShapeGeneratorBase { + + typedef dcm::details::ShapeGeneratorBase base; + typedef typename Sys::Kernel Kernel; + using typename base::Geometry3D; + using typename base::Constraint3D; + using typename base::Shape3D; + + type(Sys* system) : details::ShapeGeneratorBase(system) {}; + + //check if all needed parts are supplied, a segment needs 2 points + virtual bool check() { + + //even we have a real geometry segment + if(base::m_shape->getGeneralType() == tag::weight::segment::value) + return true; + + //or two point geometries + if(base::m_geometries->size() == 2) + return true; + + return false; + }; + //initialise all relations between the geometries + virtual void init() { + + if(base::m_shape->getGeneralType() == dcm::tag::weight::segment::value) { + + //link the line geometrie to our shape + boost::shared_ptr g1 = base::m_system->createGeometry3D(); + base::m_geometries->push_back(g1); + g1->template linkTo(base::m_shape,0); + g1->template setProperty(line); + g1->template connectSignal(boost::bind(&base::Shape3D::recalc, base::m_shape, _1)); + + //we have a segment, lets link the two points to it + boost::shared_ptr g2 = base::m_system->createGeometry3D(); + base::m_geometries->push_back(g2); + g2->template setProperty(startpoint); + boost::shared_ptr g3 = base::m_system->createGeometry3D(); + base::m_geometries->push_back(g3); + g3->template setProperty(endpoint); + + //link the points to our new segment + g2->template linkTo(base::m_shape, 0); + g3->template linkTo(base::m_shape, 3); + + //add the fix constraints + boost::shared_ptr c1 = base::m_system->createConstraint3D(g1,g2, details::fixed); + boost::shared_ptr c2 = base::m_system->createConstraint3D(g1,g3, details::fixed); + c1->disable(); //required by fixed constraint + c2->disable(); //requiered by fixed constraint + } + else + if(base::m_geometries->size() == 2) { + //we have two points, lets get them + boost::shared_ptr g1 = base::m_geometries->operator[](0); + boost::shared_ptr g2 = base::m_geometries->operator[](1); + + //possibility 1: two points. we add a segment line an link the point in + if(g1->getGeneralType() == tag::weight::point::value || g2->getGeneralType() == tag::weight::point::value) { + + g1->template setProperty(startpoint); + g2->template setProperty(endpoint); + + //construct our segment value + typename Kernel::Vector val(6); + val.head(3) = g1->getValue(); + val.tail(3) = g2->getValue(); + + //the shape is a segment + base::m_shape->template setValue(val); + + //and create a segment geometry we use as line + boost::shared_ptr g3 = base::m_system->createGeometry3D(); + base::m_geometries->push_back(g3); + g3->template linkTo(base::m_shape,0); + g3->template setProperty(line); + g3->template connectSignal(boost::bind(&base::Shape3D::recalc, base::m_shape, _1)); + + //link the points to our new segment + g1->template linkTo(base::m_shape, 0); + g2->template linkTo(base::m_shape, 3); + + //add the fix constraints to show our relation + boost::shared_ptr c1 = base::m_system->createConstraint3D(g1,g3, details::fixed); + boost::shared_ptr c2 = base::m_system->createConstraint3D(g1,g3, details::fixed); + c1->disable(); //required by fixed constraint + c2->disable(); //requiered by fixed constraint + + } + else + throw creation_error() << boost::errinfo_errno(501) << error_message("Wrong geometries for segment construction"); + }; + }; + //get geometry3d for optional types (e.g. midpoints) + virtual boost::shared_ptr::Geometry3D> getOrCreateG3d(int type) { + return boost::shared_ptr::Geometry3D>(); + }; + //get hlgeometry3d for optional types + virtual boost::shared_ptr::Shape3D> getOrCreateHLG3d(int type) { + return boost::shared_ptr::Shape3D>(); + }; + }; +}; + +} //dcm + + +#endif //GCM_GENERATOR_SHAPE3D_H diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp new file mode 100644 index 000000000000..e5ca7b3bb5f1 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp @@ -0,0 +1,45 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_GEOMETRY_HL3D_H +#define GCM_GEOMETRY_HL3D_H + +#include "opendcm/core/geometry.hpp" +#include "opendcm/module3d/geometry.hpp" + +namespace dcm { +namespace details { + +template +struct tag_traits { + typedef void return_type; + typedef void value_type; + BOOST_MPL_ASSERT_MSG(false, NO_TAG_TRAITS_SPECIFIED_FOR_TYPE, (T)); +}; + +} //details + +namespace tag { + +struct segment3D : details::stacked2_geometry {}; + +} //tag +} //dcm + +#endif \ No newline at end of file diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp new file mode 100644 index 000000000000..dec011eaab57 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp @@ -0,0 +1,591 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_MODULE_SHAPE3D_H +#define GCM_MODULE_SHAPE3D_H + +#include +#include +#include + +#include "defines.hpp" +#include "geometry.hpp" +#include "generator.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define APPEND_SINGLE(z, n, data) \ + typedef typename system_traits::template getModule::type::geometry_types gtypes; \ + g_ptr = details::converter_g::template apply(BOOST_PP_CAT(arg,n), m_this); \ + if(!g_ptr) { \ + hlg_ptr = details::converter_hlg::template apply(BOOST_PP_CAT(arg,n), data); \ + if(!hlg_ptr) \ + throw creation_error() << boost::errinfo_errno(216) << error_message("could not handle input"); \ + else \ + data->append(hlg_ptr);\ + } \ + else { \ + data->append(g_ptr); \ + } \ + + +#define CREATE_DEF(z, n, data) \ + template < \ + typename Generator \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + boost::shared_ptr createShape3D( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ); + +#define CREATE_DEC(z, n, data) \ + template \ + template \ + template <\ + typename Generator \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg)\ + > \ + boost::shared_ptr::template type::Shape3D> \ + ModuleShape3D::type::inheriter_base::createShape3D( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ) \ + { \ + typedef typename system_traits::template getModule::type module3d; \ + typedef typename module3d::Geometry3D Geometry3D; \ + boost::shared_ptr g_ptr; \ + boost::shared_ptr hlg_ptr; \ + boost::shared_ptr ptr = boost::shared_ptr(new Shape3D(*m_this)); \ + BOOST_PP_REPEAT(n, APPEND_SINGLE, ptr) \ + ptr->template initShape();\ + m_this->push_back(ptr);\ + return ptr;\ + }; + + +namespace mpl = boost::mpl; + +namespace dcm { + +namespace details { + +//return always a geometry3d pointer struct, no matter whats the supplied type +template +struct converter_g { + //check if the type T is usable from within module3d, as it could also be a shape type + template + static typename boost::enable_if< + mpl::not_< boost::is_same< + typename mpl::find::type,typename mpl::end::type> >, + boost::shared_ptr >::type apply(T const& t, Sys* sys) { + return sys->createGeometry3D(t); + }; + + //seems to be a shape type, return an empty geometry + template + static typename boost::enable_if< + boost::is_same< + typename mpl::find::type, typename mpl::end::type>, + boost::shared_ptr >::type apply(T const& t, Sys* sys) { + return boost::shared_ptr(); + }; +}; + +template +struct converter_g< boost::shared_ptr, R> { + template + static boost::shared_ptr apply(boost::shared_ptr t, Sys* sys) { + return t; + }; +}; + +template +struct converter_hlg { + template + static typename boost::enable_if< + boost::is_same< + typename mpl::find::template getModule::type::geometry_types, T>::type, + typename mpl::end::template getModule::type::geometry_types>::type>, + boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self) { + return boost::shared_ptr(); + }; + + template + static typename boost::enable_if< + mpl::not_< boost::is_same< + typename mpl::find::template getModule::type::geometry_types, T>::type, + typename mpl::end::template getModule::type::geometry_types>::type> >, + boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self) { + self->set(t); + return self; + }; +}; + +template +struct converter_hlg, R> { + template + static boost::shared_ptr apply(boost::shared_ptr t, boost::shared_ptr self) { + return t; + }; +}; + +}//details + + +template +struct ModuleShape3D { + + template + struct type : details::mshape3d { + + typedef TypeList geometry_types; + //forward declare + struct inheriter_base; + struct Shape3D; + + typedef mpl::map0<> ShapeSig; + + template + struct Shape3D_base : public details::Geometry, public Object { + + typedef typename Sys::Kernel Kernel; + typedef typename Kernel::number_type Scalar; + + //traits are only accessible in subclass scope + BOOST_MPL_ASSERT((typename system_traits::template getModule::has_module)); + typedef typename system_traits::template getModule::type module3d; + typedef typename module3d::Geometry3D Geometry3D; + typedef typename module3d::Constraint3D Constraint3D; + + Shape3D_base(Sys& system); + + template + Shape3D_base(const T& geometry, Sys& system); + + template + void set(const T& geometry); + + bool holdsType() { + return m_geometry.which()!=0; + }; + int whichType() { + return m_geometry.which()-1; + }; + + template + typename Visitor::result_type apply(Visitor& vis) { + return boost::apply_visitor(vis, m_geometry); + }; + + template + T convertTo() { + T t; + (typename geometry_traits::modell()).template inject::accessor >(t, Base::m_global); + return t; + }; + + virtual boost::shared_ptr clone(Sys& newSys); + + /*shape access functions*/ + typedef typename std::vector >::const_iterator geometry3d_iterator; + typedef typename std::vector >::const_iterator shape3d_iterator; + shape3d_iterator beginShape3D() { + return m_shapes.begin(); + }; + shape3d_iterator endShape3D() { + return m_shapes.end(); + }; + geometry3d_iterator beginGeometry3D() { + return m_geometries.begin(); + }; + geometry3d_iterator endGeometry3D() { + return m_geometries.end(); + }; + + boost::shared_ptr geometry(purpose f); + template + boost::shared_ptr subshape(); + + void recalc(boost::shared_ptr g); + protected: + + typedef details::Geometry Base; + typedef Object ObjBase; + typedef typename mpl::push_front::type ExtTypeList; + typedef typename boost::make_variant_over< ExtTypeList >::type Variant; + + struct cloner : boost::static_visitor { + typedef typename boost::make_variant_over< ExtTypeList >::type Variant; + + Variant variant; + cloner(Variant& v) : variant(v) {}; + + template + void operator()(T& t) { + variant = geometry_clone_traits()(t); + }; + }; + + //visitor to write the calculated value into the variant + struct apply_visitor : public boost::static_visitor { + + apply_visitor(typename Kernel::Vector& v) : value(v) {}; + template + void operator()(T& t) const { + (typename geometry_traits::modell()).template inject::accessor >(t, value); + } + typename Kernel::Vector& value; + }; + + Variant m_geometry; //Variant holding the real geometry type + boost::shared_ptr< details::ShapeGeneratorBase > m_generator; + + using Object >::m_system; + + std::vector > m_geometries; + std::vector > m_shapes; + std::vector > m_constraints; + + template + void initShape() { + m_generator = boost::shared_ptr >(new typename generator::template type(m_system)); + m_generator->set(ObjBase::shared_from_this(), &m_geometries, &m_shapes, &m_constraints); + + if(!m_generator->check()) + throw creation_error() << boost::errinfo_errno(210) << error_message("not all needd geometry for shape present"); + + m_generator->init(); + }; + + + boost::shared_ptr append(boost::shared_ptr g); + boost::shared_ptr append(boost::shared_ptr g); + + //override protected event functions to emit signals + void reset() {}; + void recalculated() {}; + void removed() {}; + + + friend struct inheriter_base; + friend struct Object >; + }; + + template + class Shape3D_id : public Shape3D_base { + + typedef Shape3D_base Base; + +#ifdef USE_LOGGING + attrs::mutable_constant< std::string > log_id; +#endif + public: + Shape3D_id(Sys& system); + + template + Shape3D_id(const T& geometry, Sys& system); + + template + void set(const T& geometry, ID id); + //somehow the base class set funtion is not found + template + void set(const T& geometry); + + ID& getIdentifier(); + void setIdentifier(ID id); + }; + + struct Shape3D : public mpl::if_, + Shape3D_base, Shape3D_id >::type { + + Shape3D(Sys& system); + + template + Shape3D(const T& geometry, Sys& system); + + //allow accessing the internals by module3d classes but not by users + friend struct details::ClusterMath; + friend struct details::ClusterMath::map_downstream; + friend struct details::SystemSolver; + friend struct details::SystemSolver::Rescaler; + friend struct inheriter_base; + + public: + //the geometry class itself does not hold an aligned eigen object, but maybe the variant + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + }; + + //inheriter for own functions + struct inheriter_base { + + inheriter_base(){ + m_this = (Sys*)this; + }; + + private: + Sys* m_this; + + public: + //with no vararg templates before c++11 we need preprocessor to create the overloads of create we need + BOOST_PP_REPEAT(5, CREATE_DEF, ~) + + }; + struct inheriter_id : public inheriter_base {}; + struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; + + //add properties to geometry and constraint to evaluate their shape partipance + struct shape_purpose_prop { + typedef purpose type; + typedef typename system_traits::template getModule::type::Geometry3D kind; + }; + struct shape_geometry_prop { + typedef bool type; + typedef typename system_traits::template getModule::type::Geometry3D kind; + }; + struct shape_constraint_prop { + typedef bool type; + typedef typename system_traits::template getModule::type::Constraint3D kind; + }; + + //needed typedefs + typedef ID Identifier; + typedef mpl::vector3 properties; + typedef mpl::vector1 objects; + typedef mpl::vector1 geometries; + + //needed static functions + static void system_init(Sys& sys) {}; + static void system_copy(const Sys& from, Sys& into) {}; + + }; +}; + +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ +/*****************************************************************************************************************/ + +BOOST_PP_REPEAT(5, CREATE_DEC, ~) + +template +template +template +ModuleShape3D::type::Shape3D_base::Shape3D_base(Sys& system) + : Object(system) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif +}; + +template +template +template +template +ModuleShape3D::type::Shape3D_base::Shape3D_base(const T& geometry, Sys& system) + : Object(system) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry3D")); +#endif + + m_geometry = geometry; + //first init, so that the geometry internal vector has the right size + Base::template init< typename geometry_traits::tag >(); + //now write the value; + (typename geometry_traits::modell()).template extract::accessor >(geometry, Base::getValue()); +}; + +template +template +template +template +void ModuleShape3D::type::Shape3D_base::set(const T& geometry) { + + m_geometry = geometry; + //first init, so that the geometry internal vector has the right size + this->template init< typename geometry_traits::tag >(); + //now write the value; + (typename geometry_traits::modell()).template extract::accessor >(geometry, this->getValue()); + + reset(); +}; + +template +template +template +boost::shared_ptr ModuleShape3D::type::Shape3D_base::clone(Sys& newSys) { + + //copy the standart stuff + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + //it's possible that the variant contains pointers, so we need to clone them + cloner clone_fnc(np->m_geometry); + boost::apply_visitor(clone_fnc, m_geometry); + return np; +}; + +template +template +template +boost::shared_ptr::template getModule::type::Geometry3D> +ModuleShape3D::type::Shape3D_base::geometry(purpose f) { + + for(geometry3d_iterator it = m_geometries.begin(); it != m_geometries.end(); it++) { + + if((*it)->template getProperty() == f) + return *it; + }; + return boost::shared_ptr(); +}; + +template +template +template +boost::shared_ptr +ModuleShape3D::type::Shape3D_base::append(boost::shared_ptr g) { + m_geometries.push_back(g); + g->template setProperty(true); + return ObjBase::shared_from_this(); +}; + + +template +template +template +boost::shared_ptr +ModuleShape3D::type::Shape3D_base::append(boost::shared_ptr g) { + m_shapes.push_back(g); + return ObjBase::shared_from_this(); +}; + +template +template +template +void ModuleShape3D::type::Shape3D_base::recalc(boost::shared_ptr g) { + + //we recalculated thebase line, that means we have our new value. use it. + Base::finishCalculation(); +}; + +template +template +template +ModuleShape3D::type::Shape3D_id::Shape3D_id(Sys& system) + : ModuleShape3D::template type::template Shape3D_base(system) +#ifdef USE_LOGGING +, log_id("No ID") +#endif +{ + +#ifdef USE_LOGGING + Base::log.add_attribute("ID", log_id); +#endif +}; + +template +template +template +template +ModuleShape3D::type::Shape3D_id::Shape3D_id(const T& geometry, Sys& system) + : ModuleShape3D::template type::template Shape3D_base(geometry, system) +#ifdef USE_LOGGING +, log_id("No ID") +#endif +{ + +#ifdef USE_LOGGING + Base::log.add_attribute("ID", log_id); +#endif +}; + +template +template +template +template +void ModuleShape3D::type::Shape3D_id::set(const T& geometry, Identifier id) { + this->template setProperty >(id); + Base::set(geometry); +}; + +template +template +template +template +void ModuleShape3D::type::Shape3D_id::set(const T& geometry) { + Base::set(geometry); +}; + +template +template +template +typename ModuleShape3D::template type::Identifier& +ModuleShape3D::type::Shape3D_id::getIdentifier() { + return this->template getProperty >(); +}; + +template +template +template +void ModuleShape3D::type::Shape3D_id::setIdentifier(Identifier id) { + this->template setProperty >(id); +#ifdef USE_LOGGING + std::stringstream str; + str<template getProperty >(); + log_id.set(str.str()); + BOOST_LOG(Base::log)<<"Identifyer set: "< +template +ModuleShape3D::type::Shape3D::Shape3D(Sys& system) + : mpl::if_, + Shape3D_base, + Shape3D_id >::type(system) { + +}; + +template +template +template +ModuleShape3D::type::Shape3D::Shape3D(const T& geometry, Sys& system) + : mpl::if_, + Shape3D_base, + Shape3D_id >::type(geometry, system) { + +}; + +}//dcm + +#endif //GCM_MODULE_SHAPE3D_H diff --git a/src/Mod/Assembly/App/opendcm/moduleshape3d.hpp b/src/Mod/Assembly/App/opendcm/moduleshape3d.hpp new file mode 100644 index 000000000000..963211554d76 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/moduleshape3d.hpp @@ -0,0 +1,35 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2013 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_MODULEHL3D_H +#define DCM_MODULEHL3D_H + +#define DCM_USE_MODULEHL3D + +#ifdef _WIN32 + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) +#endif + +#include "moduleShape3d/defines.hpp" +#include "moduleShape3d/module.hpp" +#include "moduleShape3d/geometry.hpp" +#include "moduleShape3d/distance.hpp" + +#endif //DCM_MODULEHL3D_H \ No newline at end of file From acd4109d5bcf5b669f313e22d50feee6ebb48821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 3 Oct 2013 13:06:23 +0000 Subject: [PATCH 222/664] add missing template specifier (gcc error) --- src/Mod/Assembly/App/opendcm/modulePart/module.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp index de3923e29b2f..f74d86ce2b43 100644 --- a/src/Mod/Assembly/App/opendcm/modulePart/module.hpp +++ b/src/Mod/Assembly/App/opendcm/modulePart/module.hpp @@ -325,8 +325,8 @@ ModulePart::type::Part_base::addGeometry3D(const T& geom, Coo template template -void ModulePart::type::Part_base::transform_traverse(typename ModulePart::type::Part_base::Transform& t, - boost::shared_ptr::type::Part_base::Cluster> c) { +void ModulePart::type::Part_base::transform_traverse(typename ModulePart::template type::Part_base::Transform& t, + boost::shared_ptr::template type::Part_base::Cluster> c) { t *= c->template getProperty().m_transform; From 9569dd3beb03f749ea9910bdc443268350879503 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 3 Oct 2013 20:43:01 +0200 Subject: [PATCH 223/664] Fix bug in PartDesignGui Workbench that may cause a crash --- src/Mod/PartDesign/Gui/Workbench.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 8d4e0439f6a8..4487571967a3 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -277,9 +277,11 @@ void switchToDocument(const App::Document* doc) sketch->getNameInDocument(), Datum.c_str(), side.c_str()); Gui::Selection().clearSelection(); - Gui::Selection().addSelection(doc->getName(), oldTip->getNameInDocument()); - Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); - Gui::Selection().clearSelection(); + if (oldTip != NULL) { + Gui::Selection().addSelection(doc->getName(), oldTip->getNameInDocument()); + Gui::Command::doCommand(Gui::Command::Gui,"FreeCADGui.runCommand('PartDesign_MoveTip')"); + Gui::Selection().clearSelection(); + } } } From f91d5013a34b6ac90c43a6deba64cad144418ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 14 Oct 2013 16:54:01 +0000 Subject: [PATCH 224/664] revidsed assembly constraint gui interaction --- src/Mod/Assembly/App/AppAssembly.cpp | 13 +- src/Mod/Assembly/App/CMakeLists.txt | 12 - src/Mod/Assembly/App/Constraint.cpp | 127 ++- src/Mod/Assembly/App/Constraint.h | 7 +- src/Mod/Assembly/App/ConstraintAlignment.cpp | 87 -- src/Mod/Assembly/App/ConstraintAlignment.h | 61 -- src/Mod/Assembly/App/ConstraintAngle.cpp | 69 -- src/Mod/Assembly/App/ConstraintAngle.h | 60 -- .../Assembly/App/ConstraintCoincidence.cpp | 87 -- src/Mod/Assembly/App/ConstraintCoincidence.h | 60 -- src/Mod/Assembly/App/ConstraintDistance.cpp | 83 -- src/Mod/Assembly/App/ConstraintDistance.h | 62 -- src/Mod/Assembly/App/ConstraintFix.h | 59 -- .../Assembly/App/ConstraintOrientation.cpp | 93 -- src/Mod/Assembly/App/ConstraintOrientation.h | 60 -- src/Mod/Assembly/App/ItemAssembly.cpp | 4 +- src/Mod/Assembly/App/opendcm/core.hpp | 24 +- .../Assembly/App/opendcm/core/equations.hpp | 2 +- .../Assembly/App/opendcm/core/geometry.hpp | 44 +- .../App/opendcm/module3d/distance.hpp | 2 +- .../Assembly/App/opendcm/module3d/module.hpp | 3 + .../App/opendcm/moduleShape3d/generator.hpp | 6 +- .../App/opendcm/moduleShape3d/geometry.hpp | 4 +- .../App/opendcm/moduleShape3d/module.hpp | 158 ++- src/Mod/Assembly/Gui/AlignmentDialog.ui | 111 -- src/Mod/Assembly/Gui/AppAssemblyGui.cpp | 14 +- src/Mod/Assembly/Gui/CMakeLists.txt | 25 +- src/Mod/Assembly/Gui/CommandConstraints.cpp | 208 ++-- src/Mod/Assembly/Gui/Resources/Assembly.qrc | 80 +- .../Assembly/Gui/Resources/Assembly.qrc.orig | 81 ++ .../Assembly_ConstraintBidirectional.svg | 410 ++++++++ .../icons/Assembly_ConstraintEqual.svg | 390 +++++++ .../icons/Assembly_ConstraintGeneral.svg | 305 ++++++ .../icons/Assembly_ConstraintOpposite.svg | 390 +++++++ .../icons/Assembly_ConstraintParallel.svg | 397 +++++++ .../Assembly_ConstraintPerpendicular.svg | 539 ++++++++++ .../Assembly_ConstraintUnidirectional1.svg | 397 +++++++ .../Assembly_ConstraintUnidirectional2.svg | 394 +++++++ .../Assembly/Gui/TaskAssemblyConstraints.cpp | 412 ++++++++ ...straintFix.h => TaskAssemblyConstraints.h} | 50 +- .../Assembly/Gui/TaskAssemblyConstraints.ui | 979 ++++++++++++++++++ .../TaskDlgAssemblyConstraints.cpp} | 76 +- ...ntAngle.h => TaskDlgAssemblyConstraints.h} | 112 +- .../Assembly/Gui/ViewProviderConstraint.cpp | 99 +- src/Mod/Assembly/Gui/ViewProviderConstraint.h | 10 +- .../Gui/ViewProviderConstraintAlignment.cpp | 34 - .../Gui/ViewProviderConstraintAlignment.h | 41 - .../Gui/ViewProviderConstraintAngle.cpp | 34 - .../Gui/ViewProviderConstraintCoincidence.cpp | 34 - .../Gui/ViewProviderConstraintCoincidence.h | 42 - .../Gui/ViewProviderConstraintDistance.cpp | 34 - .../Gui/ViewProviderConstraintDistance.h | 43 - .../Gui/ViewProviderConstraintFix.cpp | 56 - .../Gui/ViewProviderConstraintOrientation.cpp | 34 - .../Gui/ViewProviderConstraintOrientation.h | 42 - src/Mod/Assembly/Gui/Workbench.cpp | 1 + 56 files changed, 5409 insertions(+), 1652 deletions(-) delete mode 100644 src/Mod/Assembly/App/ConstraintAlignment.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintAlignment.h delete mode 100644 src/Mod/Assembly/App/ConstraintAngle.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintAngle.h delete mode 100644 src/Mod/Assembly/App/ConstraintCoincidence.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintCoincidence.h delete mode 100644 src/Mod/Assembly/App/ConstraintDistance.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintDistance.h delete mode 100644 src/Mod/Assembly/App/ConstraintFix.h delete mode 100644 src/Mod/Assembly/App/ConstraintOrientation.cpp delete mode 100644 src/Mod/Assembly/App/ConstraintOrientation.h delete mode 100644 src/Mod/Assembly/Gui/AlignmentDialog.ui create mode 100644 src/Mod/Assembly/Gui/Resources/Assembly.qrc.orig create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintBidirectional.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintEqual.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintGeneral.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOpposite.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintParallel.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintPerpendicular.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional1.svg create mode 100644 src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional2.svg create mode 100644 src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp rename src/Mod/Assembly/Gui/{ViewProviderConstraintFix.h => TaskAssemblyConstraints.h} (57%) create mode 100644 src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui rename src/Mod/Assembly/{App/ConstraintFix.cpp => Gui/TaskDlgAssemblyConstraints.cpp} (50%) rename src/Mod/Assembly/Gui/{ViewProviderConstraintAngle.h => TaskDlgAssemblyConstraints.h} (52%) delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp delete mode 100644 src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h diff --git a/src/Mod/Assembly/App/AppAssembly.cpp b/src/Mod/Assembly/App/AppAssembly.cpp index babebb0fe63d..aa41ce4ec4f3 100644 --- a/src/Mod/Assembly/App/AppAssembly.cpp +++ b/src/Mod/Assembly/App/AppAssembly.cpp @@ -34,13 +34,8 @@ #include "ItemAssembly.h" #include "ItemPart.h" -#include "ConstraintAngle.h" -#include "ConstraintCoincidence.h" -#include "ConstraintFix.h" +#include "Constraint.h" #include "ConstraintGroup.h" -#include "ConstraintAlignment.h" -#include "ConstraintDistance.h" -#include "ConstraintOrientation.h" extern struct PyMethodDef Assembly_methods[]; @@ -80,12 +75,6 @@ void AssemblyExport initAssembly() // constraint hirachy Assembly::Constraint ::init(); - Assembly::ConstraintAngle ::init(); - Assembly::ConstraintDistance::init(); - Assembly::ConstraintCoincidence::init(); - Assembly::ConstraintFix ::init(); - Assembly::ConstraintAlignment ::init(); - Assembly::ConstraintOrientation::init(); Assembly::ConstraintGroup ::init(); } diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index 549de815729a..c96dbc9fa611 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -45,18 +45,6 @@ SET(Features_SRCS Constraint.h ConstraintGroup.cpp ConstraintGroup.h - ConstraintAngle.cpp - ConstraintAngle.h - ConstraintDistance.cpp - ConstraintDistance.h - ConstraintCoincidence.cpp - ConstraintCoincidence.h - ConstraintFix.cpp - ConstraintFix.h - ConstraintAlignment.cpp - ConstraintAlignment.h - ConstraintOrientation.cpp - ConstraintOrientation.h ) SOURCE_GROUP("Features" FILES ${Features_SRCS}) diff --git a/src/Mod/Assembly/App/Constraint.cpp b/src/Mod/Assembly/App/Constraint.cpp index 516f6324627e..8483c42d33e8 100644 --- a/src/Mod/Assembly/App/Constraint.cpp +++ b/src/Mod/Assembly/App/Constraint.cpp @@ -26,6 +26,8 @@ #ifndef _PreComp_ #endif +#include + #include #include #include @@ -57,7 +59,14 @@ using namespace Assembly; namespace Assembly { struct ConstraintInitException : std::exception { - const char* what() const throw() { return "Constraint cout not be initialised: unsoported geometry";} + const char* what() const throw() { + return "Constraint cout not be initialised: unsoported geometry"; + } +}; +struct ConstraintLinkException : std::exception { + const char* what() const throw() { + return "Constraint cout not be initialised: unsoported link type"; + } }; PROPERTY_SOURCE(Assembly::Constraint, App::DocumentObject) @@ -66,6 +75,26 @@ Constraint::Constraint() { ADD_PROPERTY(First, (0)); ADD_PROPERTY(Second,(0)); + ADD_PROPERTY(Value,(0)); + ADD_PROPERTY(Orientation, (long(0))); + ADD_PROPERTY(Type, (long(6))); + + std::vector vec; + vec.push_back("Parallel"); + vec.push_back("Equal"); + vec.push_back("Opposite"); + vec.push_back("Perpendicular"); + Orientation.setEnumVector(vec); + + std::vector vec2; + vec2.push_back("Fix"); + vec2.push_back("Distance"); + vec2.push_back("Orientation"); + vec2.push_back("Angle"); + vec2.push_back("Align"); + vec2.push_back("Coincident"); + vec2.push_back("None"); + Type.setEnumVector(vec2); } short Constraint::mustExecute() const @@ -76,7 +105,7 @@ short Constraint::mustExecute() const return 0; } -App::DocumentObjectExecReturn *Constraint::execute(void) +App::DocumentObjectExecReturn* Constraint::execute(void) { touch(); return App::DocumentObject::StdReturn; @@ -84,39 +113,99 @@ App::DocumentObjectExecReturn *Constraint::execute(void) boost::shared_ptr Constraint::initLink(App::PropertyLinkSub& link) { + //empty links are allows + if(!link.getValue()) + return boost::shared_ptr(); + //check if we have Assembly::ItemPart - if( link.getValue()->getTypeId() != ItemPart::getClassTypeId() ) { - Base::Console().Message("Link is not ItemPart, the constraint is invalid\n"); - return boost::shared_ptr(); + if(link.getValue()->getTypeId() != ItemPart::getClassTypeId()) { + throw ConstraintLinkException(); + return boost::shared_ptr(); }; - + Assembly::ItemPart* part = static_cast(link.getValue()); - if(!part) - return boost::shared_ptr(); - + if(!part) + return boost::shared_ptr(); + //get the relevant solver in which the part needs to be added part->ensureInitialisation(); - + return part->getGeometry3D(link.getSubValues()[0].c_str()); } -void Constraint::init(Assembly::ItemAssembly* ass) +void Constraint::init(Assembly::ItemAssembly* ass) { - m_first_geom = initLink(First); - m_second_geom = initLink(Second); - - if(!m_first_geom || !m_second_geom) - throw ConstraintInitException(); + Assembly::ItemPart* part1, *part2; + + if(First.getValue()) { + m_first_geom = initLink(First); + part1 = static_cast(First.getValue()); + } + + if(Second.getValue()) { + m_second_geom = initLink(Second); + part2= static_cast(Second.getValue()); + } + + //fix constraint + if(Type.getValue() == 0) { + if(part1) + part1->m_part->fix(true); + else + if(part2) + part2->m_part->fix(true); + }; + + //all other constraints need poth parts + if(!part1 || !part2) + return; + + //we may need the orientation + dcm::Direction dir; + switch(Orientation.getValue()) { + case 0: + dir = dcm::parallel; + break; + case 1: + dir = dcm::equal; + break; + case 2: + dir = dcm::opposite; + break; + default: + dir = dcm::perpendicular; + + }; + + //distance constraint + if(Type.getValue() == 1) + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::distance = Value.getValue()); + + //orientation constraint + if(Type.getValue() == 2) + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::orientation = dir); + + //angle constraint + if(Type.getValue() == 3) + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::angle = Value.getValue()*M_PI/180.); + + //alignemnt constraint + if(Type.getValue() == 4) + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::alignment(dir, Value.getValue())); + + //coincident constraint + if(Type.getValue() == 5) + m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::coincidence = dir); } -PyObject *Constraint::getPyObject(void) +PyObject* Constraint::getPyObject(void) { - if (PythonObject.is(Py::_None())){ + if(PythonObject.is(Py::_None())) { // ref counter is set to 1 PythonObject = Py::Object(new ConstraintPy(this),true); } - return Py::new_reference_to(PythonObject); + return Py::new_reference_to(PythonObject); } diff --git a/src/Mod/Assembly/App/Constraint.h b/src/Mod/Assembly/App/Constraint.h index c6d00f23e4a9..00fb71edbd19 100644 --- a/src/Mod/Assembly/App/Constraint.h +++ b/src/Mod/Assembly/App/Constraint.h @@ -52,6 +52,9 @@ class AssemblyExport Constraint : public App::DocumentObject App::PropertyLinkSub First; App::PropertyLinkSub Second; + App::PropertyFloat Value; + App::PropertyEnumeration Orientation; + App::PropertyEnumeration Type; /** @name methods override feature */ //@{ @@ -60,13 +63,13 @@ class AssemblyExport Constraint : public App::DocumentObject short mustExecute() const; /// returns the type name of the view provider const char* getViewProviderName(void) const { - return "Gui::ViewProviderDocumentObject"; + return "AssemblyGui::ViewProviderConstraint"; } PyObject *getPyObject(void); /** @brief initialize the constraint in the assembly solver */ - virtual void init(Assembly::ItemAssembly* ass); + void init(Assembly::ItemAssembly* ass); }; } //namespace Assembly diff --git a/src/Mod/Assembly/App/ConstraintAlignment.cpp b/src/Mod/Assembly/App/ConstraintAlignment.cpp deleted file mode 100644 index dd08b205f12a..000000000000 --- a/src/Mod/Assembly/App/ConstraintAlignment.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 - -#include "ConstraintAlignment.h" - - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintAlignment, Assembly::Constraint) - -ConstraintAlignment::ConstraintAlignment() -{ - ADD_PROPERTY(Offset,(0)); - ADD_PROPERTY(Orientation, (long(0))); - - std::vector vec; - vec.push_back("Parallel"); - vec.push_back("Equal"); - vec.push_back("Opposite"); - Orientation.setEnumVector(vec); -} - -short ConstraintAlignment::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintAlignment::execute(void) -{ - - return App::DocumentObject::StdReturn; -} - -void ConstraintAlignment::init(Assembly::ItemAssembly* ass) { - - //cant use the base class init as we only need one part - Constraint::init(ass); - - //init the constraint - dcm::Direction dir; - switch(Orientation.getValue()) { - case 0: - dir = dcm::parallel; - break; - case 1: - dir = dcm::equal; - break; - default: - dir = dcm::opposite; - }; - - m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::alignment(dir, Offset.getValue())); -}; - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAlignment.h b/src/Mod/Assembly/App/ConstraintAlignment.h deleted file mode 100644 index b9ba6279bd34..000000000000 --- a/src/Mod/Assembly/App/ConstraintAlignment.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 Assembly_ConstraintAlignment_H -#define Assembly_ConstraintAlignment_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintAlignment : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintAlignment); - -public: - ConstraintAlignment(); - - App::PropertyFloat Offset; - App::PropertyEnumeration Orientation; - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "AssemblyGui::ViewProviderConstraintAlignment"; - } - //@} - - virtual void init(Assembly::ItemAssembly* ass); -}; - -} //namespace PartDesign - - -#endif // PART_ConstraintAlignment_H diff --git a/src/Mod/Assembly/App/ConstraintAngle.cpp b/src/Mod/Assembly/App/ConstraintAngle.cpp deleted file mode 100644 index f7c19bd3db1f..000000000000 --- a/src/Mod/Assembly/App/ConstraintAngle.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 - -#include -#include "ConstraintAngle.h" - - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintAngle, Assembly::Constraint) - -ConstraintAngle::ConstraintAngle() -{ - ADD_PROPERTY(Angle,(0)); -} - -short ConstraintAngle::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintAngle::execute(void) -{ - - return App::DocumentObject::StdReturn; -} - -void ConstraintAngle::init(Assembly::ItemAssembly* ass) -{ - //init the parts and geometries - Constraint::init(ass); - - //init the constraint - m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::angle = Angle.getValue()*M_PI/180.); -} - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintAngle.h b/src/Mod/Assembly/App/ConstraintAngle.h deleted file mode 100644 index 60ffd110fca4..000000000000 --- a/src/Mod/Assembly/App/ConstraintAngle.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 Assembly_ConstraintAngle_H -#define Assembly_ConstraintAngle_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintAngle : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintAngle); - -public: - ConstraintAngle(); - - App::PropertyFloat Angle; - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "AssemblyGui::ViewProviderConstraintAngle"; - } - //@} - - virtual void init(Assembly::ItemAssembly* ass); -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintAngle_H diff --git a/src/Mod/Assembly/App/ConstraintCoincidence.cpp b/src/Mod/Assembly/App/ConstraintCoincidence.cpp deleted file mode 100644 index 326787e62903..000000000000 --- a/src/Mod/Assembly/App/ConstraintCoincidence.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 - -#include "ConstraintCoincidence.h" - - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintCoincidence, Assembly::Constraint) - -ConstraintCoincidence::ConstraintCoincidence() -{ - - ADD_PROPERTY(Orientation, (long(0))); - - std::vector vec; - vec.push_back("Parallel"); - vec.push_back("Equal"); - vec.push_back("Opposite"); - Orientation.setEnumVector(vec); -} - -short ConstraintCoincidence::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintCoincidence::execute(void) -{ - - return App::DocumentObject::StdReturn; -} - -void ConstraintCoincidence::init(Assembly::ItemAssembly* ass) { - - //cant use the base class init as we only need one part - Constraint::init(ass); - - //init the constraint - dcm::Direction dir; - switch(Orientation.getValue()) { - case 0: - dir = dcm::parallel; - break; - case 1: - dir = dcm::equal; - break; - default: - dir = dcm::opposite; - }; - - m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::coincidence = dir); -}; - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintCoincidence.h b/src/Mod/Assembly/App/ConstraintCoincidence.h deleted file mode 100644 index c20e4a75dba3..000000000000 --- a/src/Mod/Assembly/App/ConstraintCoincidence.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 Assembly_ConstraintCoincidence_H -#define Assembly_ConstraintCoincidence_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintCoincidence : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintCoincidence); - -public: - ConstraintCoincidence(); - - App::PropertyEnumeration Orientation; - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "AssemblyGui::ViewProviderConstraintCoincidence"; - } - //@} - - virtual void init(Assembly::ItemAssembly* ass); -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintCoincidence_H diff --git a/src/Mod/Assembly/App/ConstraintDistance.cpp b/src/Mod/Assembly/App/ConstraintDistance.cpp deleted file mode 100644 index 7d79923b6c6d..000000000000 --- a/src/Mod/Assembly/App/ConstraintDistance.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel - * 2013 Stefan Tröger - * * - * 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 -#include - -#include "ConstraintDistance.h" -#include "ConstraintPy.h" - -#include "ItemPart.h" - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintDistance, Assembly::Constraint) - -ConstraintDistance::ConstraintDistance() -{ - ADD_PROPERTY(Distance,(0)); -} - -PyObject *ConstraintDistance::getPyObject(void) -{ - if (PythonObject.is(Py::_None())){ - // ref counter is set to 1 - PythonObject = Py::Object(new ConstraintPy(this),true); - } - return Py::new_reference_to(PythonObject); -} - -short ConstraintDistance::mustExecute() const -{ - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn *ConstraintDistance::execute(void) -{ - Base::Console().Message("Recalculate axis constraint\n"); - touch(); - return App::DocumentObject::StdReturn; -} - -void ConstraintDistance::init(Assembly::ItemAssembly* ass) -{ - //init the parts and geometries - Constraint::init(ass); - - //init the constraint - m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::distance = Distance.getValue()); -} - - -} \ No newline at end of file diff --git a/src/Mod/Assembly/App/ConstraintDistance.h b/src/Mod/Assembly/App/ConstraintDistance.h deleted file mode 100644 index 549e0e4341ff..000000000000 --- a/src/Mod/Assembly/App/ConstraintDistance.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 Assembly_ConstraintAxis_H -#define Assembly_ConstraintAxis_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintDistance : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintAxis); - -public: - ConstraintDistance(); - - App::PropertyFloat Distance; - - PyObject *getPyObject(void); - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "AssemblyGui::ViewProviderConstraintDistance"; - } - //@} - - virtual void init(Assembly::ItemAssembly* ass); -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintAxis_H diff --git a/src/Mod/Assembly/App/ConstraintFix.h b/src/Mod/Assembly/App/ConstraintFix.h deleted file mode 100644 index 6c0f92564cdd..000000000000 --- a/src/Mod/Assembly/App/ConstraintFix.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * - * * - * 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 Assembly_ConstraintFix_H -#define Assembly_ConstraintFix_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintFix : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintFix); - -public: - ConstraintFix(); - ~ConstraintFix(); - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "AssemblyGui::ViewProviderConstraintFix"; - } - //@} - - virtual void init(Assembly::ItemAssembly* ass); -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintFix_H diff --git a/src/Mod/Assembly/App/ConstraintOrientation.cpp b/src/Mod/Assembly/App/ConstraintOrientation.cpp deleted file mode 100644 index 0150a6d8f697..000000000000 --- a/src/Mod/Assembly/App/ConstraintOrientation.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel - * 2013 Stefan Tröger - * * - * 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 -#include - -#include "ConstraintOrientation.h" -#include "ConstraintPy.h" - -#include "ItemPart.h" - - -using namespace Assembly; - -namespace Assembly { - - -PROPERTY_SOURCE(Assembly::ConstraintOrientation, Assembly::Constraint) - -ConstraintOrientation::ConstraintOrientation() { - ADD_PROPERTY(Orientation, (long(0))); - - std::vector vec; - vec.push_back("Parallel"); - vec.push_back("Perpendicular"); - vec.push_back("Equal"); - vec.push_back("Opposite"); - Orientation.setEnumVector(vec); -} - -short ConstraintOrientation::mustExecute() const { - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; -} - -App::DocumentObjectExecReturn* ConstraintOrientation::execute(void) { - Base::Console().Message("Recalculate orientation constraint\n"); - touch(); - return App::DocumentObject::StdReturn; -} - -void ConstraintOrientation::init(Assembly::ItemAssembly* ass) { - //init the parts and geometries - Constraint::init(ass); - - //init the constraint - dcm::Direction dir; - switch(Orientation.getValue()) { - case 0: - dir = dcm::parallel; - break; - case 1: - dir = dcm::perpendicular; - break; - case 2: - dir = dcm::equal; - break; - default: - dir = dcm::opposite; - }; - - m_constraint = ass->m_solver->createConstraint3D(getNameInDocument(), m_first_geom, m_second_geom, dcm::orientation = dir); -} - - -} diff --git a/src/Mod/Assembly/App/ConstraintOrientation.h b/src/Mod/Assembly/App/ConstraintOrientation.h deleted file mode 100644 index 14be368974cf..000000000000 --- a/src/Mod/Assembly/App/ConstraintOrientation.h +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2012 Juergen Riegel * - * * - * 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 Assembly_ConstraintOrientation_H -#define Assembly_ConstraintOrientation_H - -#include -#include "Constraint.h" - - -namespace Assembly -{ - -class AssemblyExport ConstraintOrientation : public Assembly::Constraint -{ - PROPERTY_HEADER(Assembly::ConstraintOrientation); - -public: - ConstraintOrientation(); - - App::PropertyEnumeration Orientation; - - /** @name methods override feature */ - //@{ - /// recalculate the feature - App::DocumentObjectExecReturn *execute(void); - short mustExecute() const; - /// returns the type name of the view provider - const char* getViewProviderName(void) const { - return "AssemblyGui::ViewProviderConstraintOrientation"; - } - //@} - - virtual void init(Assembly::ItemAssembly* ass); -}; - -} //namespace Assembly - - -#endif // Assembly_ConstraintAxis_H diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index e7f54efffae9..431ec584e425 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -84,7 +84,9 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) { *boost::get_error_info(e), boost::get_error_info(e)->c_str()); } - + catch(std::exception& e) { + Base::Console().Error("Exception raised in assembly solver: %s", e.what()); + }; this->touch(); return App::DocumentObject::StdReturn; } diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index 6f6d171df6e6..b30cd8aec73b 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -21,18 +21,18 @@ #define DCM_CORE_H #ifdef _WIN32 - //warning about to long decoraded names, won't affect the code correctness - #pragma warning( disable : 4503 ) - //warning about changed pod initalising behaviour (boost blank in variant) - #pragma warning( disable : 4345 ) - - //disable boost concept checks, as some of them have alignment problems which bring msvc to an error - //(for example DFSvisitor check in boost::graph::depht_first_search) - //this has no runtime effect as these are only compile time checks - #include - #undef BOOST_CONCEPT_ASSERT - #define BOOST_CONCEPT_ASSERT(Model) - #include + //warning about to long decoraded names, won't affect the code correctness + #pragma warning( disable : 4503 ) + //warning about changed pod initalising behaviour (boost blank in variant) + #pragma warning( disable : 4345 ) + + //disable boost concept checks, as some of them have alignment problems which bring msvc to an error + //(for example DFSvisitor check in boost::graph::depht_first_search) + //this has no runtime effect as these are only compile time checks + #include + #undef BOOST_CONCEPT_ASSERT + #define BOOST_CONCEPT_ASSERT(Model) + #include #endif diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 7f28fc33b860..0bca861343dd 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -264,7 +264,7 @@ struct Distance : public Equation { }; //the possible directions -enum Direction { parallel, equal, opposite, perpendicular }; +enum Direction { parallel=0, equal, opposite, perpendicular }; struct Orientation : public Equation { diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index 4a145cfce494..d85852bcd018 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -56,6 +56,24 @@ namespace dcm { //signal we use for recalculation struct recalculated {}; + +//all supported geometry types for easy access and comparison +namespace geometry { +enum types { + parameter = 0, + direction, + point, + line, + segment, + circle, + arc, + geometry, + ellipse, + elliptical_arc, + plane, + cylinder +}; +}//namespace geometry namespace tag { @@ -66,17 +84,17 @@ struct undefined { //we need to order tags, this values make it easy for module tags namespace weight { -struct parameter : mpl::int_<0> {}; -struct direction : mpl::int_<1> {}; -struct point : mpl::int_<2> {}; -struct line : mpl::int_<3> {}; -struct segment : mpl::int_<4> {}; -struct circle : mpl::int_<5> {}; -struct arc : mpl::int_<6> {}; -struct ellipse : mpl::int_<7> {}; -struct elliptical_arc : mpl::int_<8> {}; -struct plane : mpl::int_<9> {}; -struct cylinder : mpl::int_<10> {}; +struct parameter : mpl::int_ {}; +struct direction : mpl::int_ {}; +struct point : mpl::int_ {}; +struct line : mpl::int_ {}; +struct segment : mpl::int_ {}; +struct circle : mpl::int_ {}; +struct arc : mpl::int_ {}; +struct ellipse : mpl::int_ {}; +struct elliptical_arc : mpl::int_ {}; +struct plane : mpl::int_ {}; +struct cylinder : mpl::int_ {}; } } // tag @@ -229,8 +247,8 @@ class Geometry { }; void transform(const Transform& t); - int getGeneralType() { - return m_general_type; + geometry::types getGeometryType() { + return geometry::types(m_general_type); }; int getExactType() { diff --git a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp index 921a361fbb77..062d8dd32226 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/distance.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/distance.hpp @@ -306,7 +306,7 @@ struct Distance::type< Kernel, tag::point3D, tag::cylinder3D > : public Distance g(6) = -1; }; }; - +//TODO: this won't work for parallel lines. switch to point-line distance when lines are parallel template struct Distance::type< Kernel, tag::line3D, tag::line3D > { diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index 650fe083331e..bdd1e7cd5929 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -314,6 +314,9 @@ struct Module3D { using inheriter_base::m_this; public: + using inheriter_base::createGeometry3D; + using inheriter_base::createConstraint3D; + template Geom createGeometry3D(T geom, Identifier id); Geom createGeometry3D(Identifier id); diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp index fcd810fa843c..d2977b98245d 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp @@ -125,7 +125,7 @@ struct segment3D { virtual bool check() { //even we have a real geometry segment - if(base::m_shape->getGeneralType() == tag::weight::segment::value) + if(base::m_shape->getGeometryType() == tag::weight::segment::value) return true; //or two point geometries @@ -137,7 +137,7 @@ struct segment3D { //initialise all relations between the geometries virtual void init() { - if(base::m_shape->getGeneralType() == dcm::tag::weight::segment::value) { + if(base::m_shape->getGeometryType() == dcm::tag::weight::segment::value) { //link the line geometrie to our shape boost::shared_ptr g1 = base::m_system->createGeometry3D(); @@ -171,7 +171,7 @@ struct segment3D { boost::shared_ptr g2 = base::m_geometries->operator[](1); //possibility 1: two points. we add a segment line an link the point in - if(g1->getGeneralType() == tag::weight::point::value || g2->getGeneralType() == tag::weight::point::value) { + if(g1->getGeometryType() == tag::weight::point::value || g2->getGeometryType() == tag::weight::point::value) { g1->template setProperty(startpoint); g2->template setProperty(endpoint); diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp index e5ca7b3bb5f1..7c4a2c6c88a1 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/geometry.hpp @@ -17,8 +17,8 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef GCM_GEOMETRY_HL3D_H -#define GCM_GEOMETRY_HL3D_H +#ifndef DCM_GEOMETRY_SHAPE3D_H +#define DCM_GEOMETRY_SHAPE3D_H #include "opendcm/core/geometry.hpp" #include "opendcm/module3d/geometry.hpp" diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp index dec011eaab57..dc157c81d622 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp @@ -42,10 +42,12 @@ #define APPEND_SINGLE(z, n, data) \ + typedef typename Sys::Identifier Identifier; \ typedef typename system_traits::template getModule::type::geometry_types gtypes; \ - g_ptr = details::converter_g::template apply(BOOST_PP_CAT(arg,n), m_this); \ + typedef typename system_traits::template getModule::type::geometry_types stypes; \ + g_ptr = details::converter_g::template apply(BOOST_PP_CAT(arg,n), m_this); \ if(!g_ptr) { \ - hlg_ptr = details::converter_hlg::template apply(BOOST_PP_CAT(arg,n), data); \ + hlg_ptr = details::converter_hlg::template apply(BOOST_PP_CAT(arg,n), data, m_this); \ if(!hlg_ptr) \ throw creation_error() << boost::errinfo_errno(216) << error_message("could not handle input"); \ else \ @@ -99,27 +101,36 @@ namespace details { template struct converter_g { //check if the type T is usable from within module3d, as it could also be a shape type - template + template static typename boost::enable_if< - mpl::not_< boost::is_same< - typename mpl::find::type,typename mpl::end::type> >, - boost::shared_ptr >::type apply(T const& t, Sys* sys) { + mpl::and_< + mpl::not_< boost::is_same::type,typename mpl::end::type> >, + mpl::not_ > + >, boost::shared_ptr >::type apply(T const& t, Sys* sys) { return sys->createGeometry3D(t); }; //seems to be a shape type, return an empty geometry - template + template static typename boost::enable_if< - boost::is_same< - typename mpl::find::type, typename mpl::end::type>, - boost::shared_ptr >::type apply(T const& t, Sys* sys) { + mpl::and_< + boost::is_same::type, typename mpl::end::type>, + mpl::not_ > + >, boost::shared_ptr >::type apply(T const& t, Sys* sys) { return boost::shared_ptr(); }; + + //seems to be an identifier type, lets check if we have such a geometry + template + static typename boost::enable_if< + boost::is_same, boost::shared_ptr >::type apply(T const& t, Sys* sys) { + return sys->getGeometry3D(t); + }; }; template struct converter_g< boost::shared_ptr, R> { - template + template static boost::shared_ptr apply(boost::shared_ptr t, Sys* sys) { return t; }; @@ -127,30 +138,41 @@ struct converter_g< boost::shared_ptr, R> { template struct converter_hlg { - template + template static typename boost::enable_if< - boost::is_same< - typename mpl::find::template getModule::type::geometry_types, T>::type, - typename mpl::end::template getModule::type::geometry_types>::type>, - boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self) { + mpl::and_< + boost::is_same::type, typename mpl::end::type>, + mpl::not_ > + >, + boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self, Sys* sys) { return boost::shared_ptr(); }; - template + template static typename boost::enable_if< - mpl::not_< boost::is_same< - typename mpl::find::template getModule::type::geometry_types, T>::type, - typename mpl::end::template getModule::type::geometry_types>::type> >, - boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self) { + mpl::not_< boost::is_same::type, typename mpl::end::type> >, + boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self, Sys* sys) { + + //shape can only be set one time, throw an error otherwise + if(self->holdsType()) + throw creation_error() << boost::errinfo_errno(410) << error_message("Shape can only be set with one geometry"); + self->set(t); return self; }; + + //seems to be an identifier type, lets check if we have such a geometry + template + static typename boost::enable_if< + boost::is_same, boost::shared_ptr >::type apply(T const& t, boost::shared_ptr self, Sys* sys) { + return sys->getShape3D(t); + }; }; template struct converter_hlg, R> { - template - static boost::shared_ptr apply(boost::shared_ptr t, boost::shared_ptr self) { + template + static boost::shared_ptr apply(boost::shared_ptr t, boost::shared_ptr self, Sys* sys) { return t; }; }; @@ -164,7 +186,7 @@ struct ModuleShape3D { template struct type : details::mshape3d { - typedef TypeList geometry_types; + typedef TypeList geometry_types; //forward declare struct inheriter_base; struct Shape3D; @@ -216,6 +238,7 @@ struct ModuleShape3D { /*shape access functions*/ typedef typename std::vector >::const_iterator geometry3d_iterator; typedef typename std::vector >::const_iterator shape3d_iterator; + typedef typename std::vector >::const_iterator constraint3d_iterator; shape3d_iterator beginShape3D() { return m_shapes.begin(); }; @@ -228,12 +251,18 @@ struct ModuleShape3D { geometry3d_iterator endGeometry3D() { return m_geometries.end(); }; + constraint3d_iterator beginConstraint3D() { + return m_constraints.begin(); + }; + constraint3d_iterator endConstraint3D() { + return m_constraints.end(); + }; boost::shared_ptr geometry(purpose f); template boost::shared_ptr subshape(); - void recalc(boost::shared_ptr g); + void recalc(boost::shared_ptr g); protected: typedef details::Geometry Base; @@ -346,19 +375,32 @@ struct ModuleShape3D { //inheriter for own functions struct inheriter_base { - inheriter_base(){ - m_this = (Sys*)this; - }; + inheriter_base() { + m_this = (Sys*)this; + }; - private: + protected: Sys* m_this; public: //with no vararg templates before c++11 we need preprocessor to create the overloads of create we need BOOST_PP_REPEAT(5, CREATE_DEF, ~) + void removeShape3D(boost::shared_ptr g); }; - struct inheriter_id : public inheriter_base {}; + + struct inheriter_id : public inheriter_base { + //we don't have a createshape3d method with identifier, as identifiers can be used to + //specifie creation geometries or shapes. therefore a call would always be ambigious. + + void removeShape3D(ID id); + bool hasShape3D(ID id); + boost::shared_ptr getShape3D(ID id); + + protected: + using inheriter_base::m_this; + }; + struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; //add properties to geometry and constraint to evaluate their shape partipance @@ -493,7 +535,7 @@ template template template void ModuleShape3D::type::Shape3D_base::recalc(boost::shared_ptr g) { - + //we recalculated thebase line, that means we have our new value. use it. Base::finishCalculation(); }; @@ -586,6 +628,60 @@ ModuleShape3D::type::Shape3D::Shape3D(const T& geometry, Sys& }; +template +template +void ModuleShape3D::type::inheriter_base::removeShape3D(boost::shared_ptr g) { + + //remove all constraints + typedef typename Shape3D::constraint3d_iterator cit; + for(cit it=g->constraint3dBegin(); it!=g->constraint3dEnd(); it++) + m_this->removeConstraint3D(*it); + + //remove all geometries + typedef typename Shape3D::geometry3d_iterator git; + for(git it=g->geometry3dBegin(); it!=g->geometry3dEnd(); it++) + m_this->removeGeometry3D(*it); + + //remove all subshapes + typedef typename Shape3D::shape3d_iterator sit; + for(sit it=g->shape3dBegin(); it!=g->shape3dEnd(); it++) + m_this->removeShape3D(*it); + + //emit remove shape signal bevore actually deleting it + g->template emitSignal(g); + m_this->erase(g); +}; + +template +template +bool ModuleShape3D::type::inheriter_id::hasShape3D(Identifier id) { + if(getShape3D(id)) + return true; + return false; +}; + +template +template +boost::shared_ptr::template type::Shape3D> +ModuleShape3D::type::inheriter_id::getShape3D(Identifier id) { + std::vector< boost::shared_ptr >& vec = inheriter_base::m_this->template objectVector(); + typedef typename std::vector< boost::shared_ptr >::iterator iter; + for(iter it=vec.begin(); it!=vec.end(); it++) { + if(compare_traits::compare((*it)->getIdentifier(), id)) + return *it; + }; + return boost::shared_ptr(); +}; + +template +template +void ModuleShape3D::type::inheriter_id::removeShape3D(Identifier id) { + + boost::shared_ptr s = getShape3D(id); + if(s) + removeShape3D(s); +}; + }//dcm #endif //GCM_MODULE_SHAPE3D_H diff --git a/src/Mod/Assembly/Gui/AlignmentDialog.ui b/src/Mod/Assembly/Gui/AlignmentDialog.ui deleted file mode 100644 index e02156e12a68..000000000000 --- a/src/Mod/Assembly/Gui/AlignmentDialog.ui +++ /dev/null @@ -1,111 +0,0 @@ - - - AlignmentDialog - - - - 0 - 0 - 270 - 95 - - - - Constraint value - - - - - - - - - 0 - 0 - - - - Offset: - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - Orientation: - - - - - - - true - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - AlignmentDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - AlignmentDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp index 482327b03845..20b57682f08c 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGui.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGui.cpp @@ -36,12 +36,7 @@ #include "ViewProviderPart.h" #include "ViewProviderAssembly.h" #include "ViewProviderConstraintGroup.h" -#include "ViewProviderConstraintFix.h" -#include "ViewProviderConstraintDistance.h" -#include "ViewProviderConstraintAngle.h" -#include "ViewProviderConstraintOrientation.h" -#include "ViewProviderConstraintCoincidence.h" -#include "ViewProviderConstraintAlignment.h" +#include "ViewProviderConstraint.h" #include @@ -90,12 +85,7 @@ void AssemblyGuiExport initAssemblyGui() AssemblyGui::ViewProviderItemAssembly::init(); AssemblyGui::ViewProviderConstraintGroup::init(); - AssemblyGui::ViewProviderConstraintFix::init(); - AssemblyGui::ViewProviderConstraintDistance::init(); - AssemblyGui::ViewProviderConstraintAngle::init(); - AssemblyGui::ViewProviderConstraintOrientation::init(); - AssemblyGui::ViewProviderConstraintCoincidence::init(); - AssemblyGui::ViewProviderConstraintAlignment::init(); + AssemblyGui::ViewProviderConstraint::init(); // add resources and reloads the translators loadAssemblyResource(); diff --git a/src/Mod/Assembly/Gui/CMakeLists.txt b/src/Mod/Assembly/Gui/CMakeLists.txt index 837b78fa94f8..19ce38bfb131 100644 --- a/src/Mod/Assembly/Gui/CMakeLists.txt +++ b/src/Mod/Assembly/Gui/CMakeLists.txt @@ -26,10 +26,17 @@ set(AssemblyGui_LIBS FreeCADGui ) +set(AssemblyGui_MOC_HDRS + TaskAssemblyConstraints.h + TaskDlgAssemblyConstraints.h +) +fc_wrap_cpp(AssemblyGui_MOC_SRCS ${AssemblyGui_MOC_HDRS}) +SOURCE_GROUP("Moc" FILES ${AssemblyGui_MOC_SRCS}) + qt4_add_resources(AssemblyGui_SRCS Resources/Assembly.qrc) set(AssemblyGui_UIC_SRCS - AlignmentDialog.ui + TaskAssemblyConstraints.ui ) qt4_wrap_ui(AssemblyGui_UIC_HDRS ${AssemblyGui_UIC_SRCS}) @@ -44,18 +51,10 @@ SET(AssemblyGuiViewProvider_SRCS ViewProviderConstraint.h ViewProviderConstraintGroup.cpp ViewProviderConstraintGroup.h - ViewProviderConstraintFix.cpp - ViewProviderConstraintFix.h - ViewProviderConstraintDistance.cpp - ViewProviderConstraintDistance.h - ViewProviderConstraintAngle.cpp - ViewProviderConstraintAngle.h - ViewProviderConstraintOrientation.cpp - ViewProviderConstraintOrientation.h - ViewProviderConstraintCoincidence.cpp - ViewProviderConstraintCoincidence.h - ViewProviderConstraintAlignment.cpp - ViewProviderConstraintAlignment.h + TaskDlgAssemblyConstraints.cpp + TaskDlgAssemblyConstraints.h + TaskAssemblyConstraints.h + TaskAssemblyConstraints.cpp ) SOURCE_GROUP("ViewProvider" FILES ${AssemblyGuiViewProvider_SRCS}) diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index ead8bd81b8b0..7f1541dd44fb 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -32,11 +32,14 @@ #include #include #include -#include "ui_AlignmentDialog.h" +#include +#include +#include #include #include #include +#include using namespace std; @@ -106,6 +109,90 @@ std::string asSubLinkString(Assembly::ItemPart* part, std::string element) //=========================================================================== +DEF_STD_CMD(CmdAssemblyConstraint); + +CmdAssemblyConstraint::CmdAssemblyConstraint() + : Command("Assembly_Constraint") +{ + sAppModule = "Assembly"; + sGroup = QT_TR_NOOP("Assembly"); + sMenuText = QT_TR_NOOP("Constraint"); + sToolTipText = QT_TR_NOOP("Add arbitrary constraints to the assembly"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Assembly_ConstraintGeneral"; +} + + +void CmdAssemblyConstraint::activated(int iMsg) +{ + Assembly::ItemAssembly* Asm = 0; + Assembly::ConstraintGroup* ConstGrp = 0; + + // retrive the standard objects needed + if(getConstraintPrerequisits(&Asm, &ConstGrp)) + return; + + std::vector objs = Gui::Selection().getSelectionEx(); + + if(objs.size() > 2) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Only two geometries supported by constraints")); + return; + }; + + std::stringstream typestr1, typestr2; + std::pair part1, part2; + if(objs.size()>=1) { + part1 = Asm->getContainingPart(objs[0].getObject()); + //checking the parts is enough, both or non! + if(!part1.first) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + return; + }; + typestr1 << "App.activeDocument().ActiveObject.First = " << asSubLinkString(part1.first, objs[0].getSubNames()[0]); + } + if(objs.size()>=2) { + part2 = Asm->getContainingPart(objs[1].getObject()); + //checking the parts is enough, both or non! + if(!part2.first) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts need to belong to the active assembly (active product or one of it's subproducts)")); + return; + }; + typestr2 << "App.activeDocument().ActiveObject.Second = " << asSubLinkString(part2.first, objs[1].getSubNames()[0]); + } + + + //check if this is the right place for the constraint + if(part1.first && part2.first && (part1.second == part2.second) && part1.second != Asm) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); + return; + } + + openCommand("Insert Constraint Distance"); + std::string ConstrName = getUniqueObjectName("Constraint"); + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + if(objs.size()>=1) + doCommand(Doc, typestr1.str().c_str()); + if(objs.size()>=2) + doCommand(Doc, typestr2.str().c_str()); + doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); + + updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + + commitCommand(); + + Gui::Selection().clearCompleteSelection(); +} + + +/******************************************************************************************/ + + DEF_STD_CMD(CmdAssemblyConstraintDistance); CmdAssemblyConstraintDistance::CmdAssemblyConstraintDistance() @@ -149,31 +236,26 @@ void CmdAssemblyConstraintDistance::activated(int iMsg) }; //check if this is the right place for the constraint - if( (part1.second == part2.second) && part1.second != Asm ) { + if((part1.second == part2.second) && part1.second != Asm) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); return; } - bool ok; - - double d = QInputDialog::getDouble(NULL, QObject::tr("Constraint value"), - QObject::tr("Distance:"), 0., -10000., 10000., 2, &ok); - - if(!ok) - return; - openCommand("Insert Constraint Distance"); std::string ConstrName = getUniqueObjectName("Distance"); - doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintDistance','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Type = 'Distance'"); doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc, "App.activeDocument().ActiveObject.Distance = %f", d); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - commitCommand(); updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + + commitCommand(); + Gui::Selection().clearCompleteSelection(); } /******************************************************************************************/ @@ -216,9 +298,9 @@ void CmdAssemblyConstraintFix::activated(int iMsg) Base::Console().Message("The selected part need to belong to the active assembly\n"); return; }; - + if(part.second != Asm) { - Base::Console().Message("The selected part need belongs to an subproduct, please add constraint there\n"); + Base::Console().Message("The selected part need belongs to an subproduct, please add constraint there\n"); return; } @@ -226,15 +308,15 @@ void CmdAssemblyConstraintFix::activated(int iMsg) std::string ConstrName = getUniqueObjectName("Fix"); - doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintFix','%s')", ConstrName.c_str()); - + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Type = 'Fix'"); doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part.first, objs[0].getSubNames()[0]).c_str()); - doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - commitCommand(); - updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + + commitCommand(); } @@ -284,30 +366,24 @@ void CmdAssemblyConstraintAngle::activated(int iMsg) }; //check if this is the right place for the constraint - if( ( (part1.second == part2.second) && part1.second != Asm ) && part1.second != Asm ) { + if(((part1.second == part2.second) && part1.second != Asm) && part1.second != Asm) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); return; } - bool ok; - - double d = QInputDialog::getDouble(NULL, QObject::tr("Constraint value"), - QObject::tr("Angle:"), 0., 0., 360., 2, &ok); - - if(!ok) - return; - openCommand("Insert Constraint Angle"); std::string ConstrName = getUniqueObjectName("Angle"); - doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintAngle','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Type = 'Angle'"); doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc, "App.activeDocument().ActiveObject.Angle = %f", d); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - commitCommand(); updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + + commitCommand(); } @@ -358,35 +434,24 @@ void CmdAssemblyConstraintOrientation::activated(int iMsg) }; //check if this is the right place for the constraint - if( (part1.second == part2.second) && part1.second != Asm ) { + if((part1.second == part2.second) && part1.second != Asm) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); return; } - QStringList items; - - items << QObject::tr("Parallel") << QObject::tr("Perpendicular") << QObject::tr("Equal") << QObject::tr("Opposite"); - - bool ok; - - QString item = QInputDialog::getItem(NULL, QObject::tr("Constraint value"), - QObject::tr("Orientation:"), items, 0, false, &ok); - - if(!ok || item.isEmpty()) - return; - openCommand("Insert Constraint Orientation"); std::string ConstrName = getUniqueObjectName("Orientation"); - doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintOrientation','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Type = 'Orientation'"); doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc, "App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - commitCommand(); updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + commitCommand(); } /******************************************************************************************/ @@ -435,35 +500,24 @@ void CmdAssemblyConstraintCoincidence::activated(int iMsg) }; //check if this is the right place for the constraint - if( (part1.second == part2.second) && part1.second != Asm ) { + if((part1.second == part2.second) && part1.second != Asm) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); return; } - QStringList items; - - items << QObject::tr("Parallel") << QObject::tr("Equal") << QObject::tr("Opposite"); - - bool ok; - - QString item = QInputDialog::getItem(NULL, QObject::tr("Constraint value"), - QObject::tr("Orientation:"), items, 0, false, &ok); - - if(!ok || item.isEmpty()) - return; - openCommand("Insert Constraint Coincidence"); std::string ConstrName = getUniqueObjectName("Coincidence"); - doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintCoincidence','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Type = 'Coincident'"); doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc, "App.activeDocument().ActiveObject.Orientation = '%s'", item.toStdString().c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - commitCommand(); updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + commitCommand(); } /******************************************************************************************/ @@ -512,45 +566,31 @@ void CmdAssemblyConstraintAlignment::activated(int iMsg) }; //check if this is the right place for the constraint - if( (part1.second == part2.second) && part1.second != Asm ) { + if((part1.second == part2.second) && part1.second != Asm) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("The selected parts belong both to the same subproduct, please add constraints there")); return; } - QStringList items; - - items << QObject::tr("Parallel") << QObject::tr("Equal") << QObject::tr("Opposite"); - - QDialog dialog; - - Ui_AlignmentDialog ui; - - ui.setupUi(&dialog); - - ui.comboBox->addItems(items); - - if(dialog.exec() != QDialog::Accepted) - return; - openCommand("Insert Constraint Alignment"); std::string ConstrName = getUniqueObjectName("Alignment"); - doCommand(Doc, "App.activeDocument().addObject('Assembly::ConstraintAlignment','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().addObject('Assembly::Constraint','%s')", ConstrName.c_str()); + doCommand(Doc, "App.activeDocument().ActiveObject.Type = 'Align'"); doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part1.first, objs[0].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); - doCommand(Doc, "App.activeDocument().ActiveObject.Orientation = '%s'", ui.comboBox->currentText().toStdString().c_str()); - doCommand(Doc, "App.activeDocument().ActiveObject.Offset = %f", ui.doubleSpinBox->value()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - commitCommand(); updateActive(); + doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); + commitCommand(); } void CreateAssemblyConstraintCommands(void) { Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); + rcCmdMgr.addCommand(new CmdAssemblyConstraint()); rcCmdMgr.addCommand(new CmdAssemblyConstraintFix()); rcCmdMgr.addCommand(new CmdAssemblyConstraintDistance()); rcCmdMgr.addCommand(new CmdAssemblyConstraintAngle()); diff --git a/src/Mod/Assembly/Gui/Resources/Assembly.qrc b/src/Mod/Assembly/Gui/Resources/Assembly.qrc index b680f4637f39..67337c609c3e 100644 --- a/src/Mod/Assembly/Gui/Resources/Assembly.qrc +++ b/src/Mod/Assembly/Gui/Resources/Assembly.qrc @@ -1,36 +1,44 @@ - - - icons/Assembly_ConstraintLock.svg - icons/Assembly_ConstraintDistance.svg - icons/Assembly_ConstraintAngle.svg - icons/Assembly_ConstraintOrientation.svg - icons/Assembly_ConstraintCoincidence.svg - icons/Assembly_ConstraintAlignment.svg - translations/Assembly_af.qm - translations/Assembly_de.qm - translations/Assembly_fi.qm - translations/Assembly_fr.qm - translations/Assembly_hr.qm - translations/Assembly_it.qm - translations/Assembly_nl.qm - translations/Assembly_no.qm - translations/Assembly_ru.qm - translations/Assembly_uk.qm - translations/Assembly_tr.qm - translations/Assembly_sv-SE.qm - translations/Assembly_pl.qm - translations/Assembly_zh-TW.qm - translations/Assembly_pt-BR.qm - translations/Assembly_cs.qm - translations/Assembly_sk.qm - translations/Assembly_es-ES.qm - translations/Assembly_zh-CN.qm - translations/Assembly_ja.qm - translations/Assembly_ro.qm - translations/Assembly_hu.qm - translations/Assembly_pt-PT.qm - translations/Assembly_sr.qm - translations/Assembly_el.qm - translations/Assembly_sl.qm - - + + + icons/Assembly_ConstraintBidirectional.svg + icons/Assembly_ConstraintUnidirectional1.svg + icons/Assembly_ConstraintUnidirectional2.svg + icons/Assembly_ConstraintPerpendicular.svg + icons/Assembly_ConstraintParallel.svg + icons/Assembly_ConstraintOpposite.svg + icons/Assembly_ConstraintEqual.svg + icons/Assembly_ConstraintLock.svg + icons/Assembly_ConstraintDistance.svg + icons/Assembly_ConstraintAngle.svg + icons/Assembly_ConstraintOrientation.svg + icons/Assembly_ConstraintCoincidence.svg + icons/Assembly_ConstraintAlignment.svg + icons/Assembly_ConstraintGeneral.svg + translations/Assembly_af.qm + translations/Assembly_de.qm + translations/Assembly_fi.qm + translations/Assembly_fr.qm + translations/Assembly_hr.qm + translations/Assembly_it.qm + translations/Assembly_nl.qm + translations/Assembly_no.qm + translations/Assembly_ru.qm + translations/Assembly_uk.qm + translations/Assembly_tr.qm + translations/Assembly_sv-SE.qm + translations/Assembly_pl.qm + translations/Assembly_zh-TW.qm + translations/Assembly_pt-BR.qm + translations/Assembly_cs.qm + translations/Assembly_sk.qm + translations/Assembly_es-ES.qm + translations/Assembly_zh-CN.qm + translations/Assembly_ja.qm + translations/Assembly_ro.qm + translations/Assembly_hu.qm + translations/Assembly_pt-PT.qm + translations/Assembly_sr.qm + translations/Assembly_el.qm + translations/Assembly_sl.qm + + diff --git a/src/Mod/Assembly/Gui/Resources/Assembly.qrc.orig b/src/Mod/Assembly/Gui/Resources/Assembly.qrc.orig new file mode 100644 index 000000000000..0af9ed22d37e --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/Assembly.qrc.orig @@ -0,0 +1,81 @@ +<<<<<<< d6421cef81c1d7a191d1524d88c63e56e3f6d864 + + + icons/Assembly_ConstraintLock.svg + icons/Assembly_ConstraintDistance.svg + icons/Assembly_ConstraintAngle.svg + icons/Assembly_ConstraintOrientation.svg + icons/Assembly_ConstraintCoincidence.svg + icons/Assembly_ConstraintAlignment.svg + translations/Assembly_af.qm + translations/Assembly_de.qm + translations/Assembly_fi.qm + translations/Assembly_fr.qm + translations/Assembly_hr.qm + translations/Assembly_it.qm + translations/Assembly_nl.qm + translations/Assembly_no.qm + translations/Assembly_ru.qm + translations/Assembly_uk.qm + translations/Assembly_tr.qm + translations/Assembly_sv-SE.qm + translations/Assembly_pl.qm + translations/Assembly_zh-TW.qm + translations/Assembly_pt-BR.qm + translations/Assembly_cs.qm + translations/Assembly_sk.qm + translations/Assembly_es-ES.qm + translations/Assembly_zh-CN.qm + translations/Assembly_ja.qm + translations/Assembly_ro.qm + translations/Assembly_hu.qm + translations/Assembly_pt-PT.qm + translations/Assembly_sr.qm + translations/Assembly_el.qm + translations/Assembly_sl.qm + + +======= + + + icons/Assembly_ConstraintBidirectional.svg + icons/Assembly_ConstraintUnidirectional1.svg + icons/Assembly_ConstraintUnidirectional2.svg + icons/Assembly_ConstraintPerpendicular.svg + icons/Assembly_ConstraintParallel.svg + icons/Assembly_ConstraintOpposite.svg + icons/Assembly_ConstraintEqual.svg + icons/Assembly_ConstraintLock.svg + icons/Assembly_ConstraintDistance.svg + icons/Assembly_ConstraintAngle.svg + icons/Assembly_ConstraintOrientation.svg + icons/Assembly_ConstraintCoincidence.svg + icons/Assembly_ConstraintAlignment.svg + icons/Assembly_ConstraintGeneral.svg + translations/Assembly_af.qm + translations/Assembly_de.qm + translations/Assembly_fi.qm + translations/Assembly_fr.qm + translations/Assembly_hr.qm + translations/Assembly_it.qm + translations/Assembly_nl.qm + translations/Assembly_no.qm + translations/Assembly_ru.qm + translations/Assembly_uk.qm + translations/Assembly_tr.qm + translations/Assembly_sv-SE.qm + translations/Assembly_pl.qm + translations/Assembly_zh-TW.qm + translations/Assembly_pt-BR.qm + translations/Assembly_cs.qm + translations/Assembly_sk.qm + translations/Assembly_es-ES.qm + translations/Assembly_zh-CN.qm + translations/Assembly_ja.qm + translations/Assembly_ro.qm + translations/Assembly_hu.qm + translations/Assembly_pt-PT.qm + translations/Assembly_sr.qm + + +>>>>>>> revidsed assembly constraint gui interaction diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintBidirectional.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintBidirectional.svg new file mode 100644 index 000000000000..6afdaba3baf3 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintBidirectional.svg @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintEqual.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintEqual.svg new file mode 100644 index 000000000000..187e17e9579e --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintEqual.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintGeneral.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintGeneral.svg new file mode 100644 index 000000000000..0a1a154979d9 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintGeneral.svg @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOpposite.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOpposite.svg new file mode 100644 index 000000000000..1c0f0f1ba980 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintOpposite.svg @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintParallel.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintParallel.svg new file mode 100644 index 000000000000..4f7b9b3db9ff --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintParallel.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintPerpendicular.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintPerpendicular.svg new file mode 100644 index 000000000000..df64b8ecb172 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintPerpendicular.svg @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional1.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional1.svg new file mode 100644 index 000000000000..5ddb1adc8609 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional1.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional2.svg b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional2.svg new file mode 100644 index 000000000000..1953a3f54688 --- /dev/null +++ b/src/Mod/Assembly/Gui/Resources/icons/Assembly_ConstraintUnidirectional2.svg @@ -0,0 +1,394 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp new file mode 100644 index 000000000000..b77c7025cafe --- /dev/null +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp @@ -0,0 +1,412 @@ +/*************************************************************************** + * Copyright (c) 2009 Juergen Riegel * + * * + * 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 +# include +#endif + + +#include "TaskAssemblyConstraints.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace AssemblyGui; +using namespace Gui::TaskView; + +extern Assembly::Item* ActiveAsmObject; + +TaskAssemblyConstraints::TaskAssemblyConstraints(ViewProviderConstraint* vp) + : TaskBox(Gui::BitmapFactory().pixmap("document-new"),tr("Constraints"),true, 0), view(vp) +{ + // we need a separate container widget to add all controls to + proxy = new QWidget(this); + ui = new Ui::TaskAssemblyConstraints(); + ui->setupUi(proxy); + this->groupLayout()->addWidget(proxy); + + //initialy hide the value and orientation field + ui->value_widget->hide(); + ui->orientation_widget->hide(); + + //set all basic values + Assembly::ItemAssembly* ass = NULL; + Assembly::Constraint* obj = dynamic_cast(vp->getObject()); + if(obj->First.getValue()) { + QString str; + str = QString::fromAscii(obj->First.getValue()->getNameInDocument()) + QString::fromAscii(".") + QString::fromStdString(obj->First.getSubValues().front()); + ui->first_geom->setText(str); + ass = dynamic_cast(obj->First.getValue())->getParentAssembly(); + }; + if(obj->Second.getValue()) { + QString str; + str = QString::fromAscii(obj->Second.getValue()->getNameInDocument()) + QString::fromAscii(".") + QString::fromStdString(obj->Second.getSubValues().front()); + ui->second_geom->setText(str); + if(!ass) + ass = dynamic_cast(obj->Second.getValue())->getParentAssembly(); + }; + + if(ass) + ass->execute(); + + //get the individual constraint settings + ui->value->setValue(obj->Value.getValue()); + setOrientation(dcm::Direction(obj->Orientation.getValue())); + + int v = obj->Type.getValue(); + if(v==0) + ui->fix->setChecked(true); + + if(v==1) + ui->distance->setChecked(true); + + if(v==2) + ui->orientation->setChecked(true); + + if(v==3) + ui->angle->setChecked(true); + + if(v==4) + ui->align->setChecked(true); + + if(v==5) + ui->coincident->setChecked(true); + + + setPossibleConstraints(); + + //setup all signals for event processing + QObject::connect( + ui->fix, SIGNAL(toggled(bool)), + this, SLOT(on_constraint_selection(bool))); + QObject::connect( + ui->distance, SIGNAL(toggled(bool)), + this, SLOT(on_constraint_selection(bool))); + QObject::connect( + ui->orientation, SIGNAL(toggled(bool)), + this, SLOT(on_constraint_selection(bool))); + QObject::connect( + ui->angle, SIGNAL(toggled(bool)), + this, SLOT(on_constraint_selection(bool))); + QObject::connect( + ui->align, SIGNAL(toggled(bool)), + this, SLOT(on_constraint_selection(bool))); + QObject::connect( + ui->coincident, SIGNAL(toggled(bool)), + this, SLOT(on_constraint_selection(bool))); + QObject::connect( + ui->parallel, SIGNAL(toggled(bool)), + this, SLOT(on_orientation_selection(bool))); + QObject::connect( + ui->equal, SIGNAL(toggled(bool)), + this, SLOT(on_orientation_selection(bool))); + QObject::connect( + ui->opposite, SIGNAL(toggled(bool)), + this, SLOT(on_orientation_selection(bool))); + QObject::connect( + ui->perpendicular, SIGNAL(toggled(bool)), + this, SLOT(on_orientation_selection(bool))); + QObject::connect( + ui->value, SIGNAL(valueChanged(double)), + this, SLOT(on_value_change(double))); + QObject::connect( + ui->clear_first, SIGNAL(pressed()), + this, SLOT(on_clear_first())); + QObject::connect( + ui->clear_second, SIGNAL(pressed()), + this, SLOT(on_clear_second())); + +} + +dcm::Direction TaskAssemblyConstraints::getOrientation() +{ + if(ui->parallel->isChecked()) + return dcm::parallel; + if(ui->equal->isChecked()) + return dcm::equal; + if(ui->opposite->isChecked()) + return dcm::opposite; + + return dcm::perpendicular; +} + +void TaskAssemblyConstraints::setOrientation(dcm::Direction d) +{ + switch(d) { + case dcm::perpendicular: + ui->perpendicular->setChecked(true); + break; + case dcm::equal: + ui->equal->setChecked(true); + break; + case dcm::opposite: + ui->opposite->setChecked(true); + break; + default: + ui->parallel->setChecked(true); + } +} + + +TaskAssemblyConstraints::~TaskAssemblyConstraints() +{ + delete ui; +} + +void TaskAssemblyConstraints::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if(msg.Type == Gui::SelectionChanges::AddSelection) { + + //add it as the first geometry? + if(ui->first_geom->text().isEmpty()) { + std::vector objs = Gui::Selection().getSelectionEx(); + Assembly::Constraint* con = dynamic_cast(view->getObject()); + + if(!ActiveAsmObject || !ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Assembly"), + QObject::tr("You need a active (blue) Assembly to insert a Constraint. Please create a new one or make one active (double click).")); + return; + } + + std::pair part1 = static_cast(ActiveAsmObject)->getContainingPart(objs.back().getObject()); + con->First.setValue(part1.first, objs.back().getSubNames()); + QString str; + str = QString::fromAscii(part1.first->getNameInDocument()) + QString::fromAscii(".") + QString::fromStdString(con->First.getSubValues().front()); + ui->first_geom->setText(str); + + App::GetApplication().getActiveDocument()->recompute(); + setPossibleConstraints(); + view->draw(); + return; + } + + if(ui->second_geom->text().isEmpty()) { + std::vector objs = Gui::Selection().getSelectionEx(); + Assembly::Constraint* con = dynamic_cast(view->getObject()); + + if(!ActiveAsmObject || !ActiveAsmObject->getTypeId().isDerivedFrom(Assembly::ItemAssembly::getClassTypeId())) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No active Assembly"), + QObject::tr("You need a active (blue) Assembly to insert a Constraint. Please create a new one or make one active (double click).")); + return; + } + + std::pair part2 = static_cast(ActiveAsmObject)->getContainingPart(objs.back().getObject()); + con->Second.setValue(part2.first, objs.back().getSubNames()); + QString str; + str = QString::fromAscii(part2.first->getNameInDocument()) + QString::fromAscii(".") + QString::fromStdString(con->Second.getSubValues().front()); + ui->second_geom->setText(str); + + App::GetApplication().getActiveDocument()->recompute(); + setPossibleConstraints(); + view->draw(); + return; + } + }; +} + +void TaskAssemblyConstraints::on_constraint_selection(bool clicked) +{ + if(clicked) { + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + + if(ui->fix->isChecked()) + obj->Type.setValue("Fix"); + + if(ui->distance->isChecked()) + obj->Type.setValue("Distance"); + + if(ui->orientation->isChecked()) + obj->Type.setValue("Orientation"); + + if(ui->angle->isChecked()) + obj->Type.setValue("Angle"); + + if(ui->align->isChecked()) + obj->Type.setValue("Align"); + + if(ui->coincident->isChecked()) + obj->Type.setValue("Coincident"); + + App::GetApplication().getActiveDocument()->recompute(); + view->draw(); + } + +} + +void TaskAssemblyConstraints::on_orientation_selection(bool clicked) +{ + if(clicked) { + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + obj->Orientation.setValue(getOrientation()); + + App::GetApplication().getActiveDocument()->recompute(); + view->draw(); + } +} + +void TaskAssemblyConstraints::on_value_change(double val) +{ + + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + obj->Value.setValue(ui->value->value()); + + App::GetApplication().getActiveDocument()->recompute(); + view->draw(); +} + +void TaskAssemblyConstraints::on_clear_first() +{ + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + obj->First.setValue(NULL); + ui->first_geom->clear(); + setPossibleConstraints(); + view->draw(); +} + +void TaskAssemblyConstraints::on_clear_second() +{ + + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + obj->Second.setValue(NULL); + ui->second_geom->clear(); + setPossibleConstraints(); + view->draw(); +} + +void TaskAssemblyConstraints::setPossibleConstraints() +{ + ui->fix->setEnabled(false); + ui->distance->setEnabled(false); + ui->orientation->setEnabled(false); + ui->angle->setEnabled(false); + ui->align->setEnabled(false); + ui->coincident->setEnabled(false); + + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + if(obj->First.getValue()) { + + Assembly::ItemPart* p1 = dynamic_cast(obj->First.getValue()); + + if(!p1) + return; + + Assembly::ItemAssembly* ass = p1->getParentAssembly(); + + //extract the geometries to use for comparison + boost::shared_ptr g1 = ass->m_solver->getGeometry3D(obj->First.getSubValues()[0].c_str()); + if(obj->Second.getValue()) { + Assembly::ItemPart* p2 = dynamic_cast(obj->Second.getValue()); + if(!p2) + return; + + boost::shared_ptr g2 = ass->m_solver->getGeometry3D(obj->Second.getSubValues()[0].c_str()); + + //check all valid combinaions + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::point)) { + ui->distance->setEnabled(true); + ui->coincident->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::line)) { + ui->distance->setEnabled(true); + ui->coincident->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::plane)) { + ui->distance->setEnabled(true); + ui->coincident->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::cylinder)) { + ui->distance->setEnabled(true); + ui->coincident->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::line)) { + ui->distance->setEnabled(true); + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); + ui->coincident->setEnabled(true); + ui->align->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::plane)) { + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); + ui->coincident->setEnabled(true); + ui->align->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder)) { + ui->distance->setEnabled(true); + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); + ui->coincident->setEnabled(true); + ui->align->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::plane)) { + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); + ui->coincident->setEnabled(true); + ui->align->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); + ui->coincident->setEnabled(true); + ui->align->setEnabled(true); + }; + if(isCombination(g1,g2, dcm::geometry::cylinder, dcm::geometry::cylinder)) { + ui->coincident->setEnabled(true); + }; + } + else { + //only fix works + ui->fix->setEnabled(true); + }; + } +} + +bool TaskAssemblyConstraints::isCombination(boost::shared_ptr g1, boost::shared_ptr g2, dcm::geometry::types t1, dcm::geometry::types t2) +{ + if(g1->getGeometryType() == t1 && g2->getGeometryType() == t2) + return true; + + if(g1->getGeometryType() == t2 && g2->getGeometryType() == t1) + return true; + + return false; +} + + + + +#include "moc_TaskAssemblyConstraints.cpp" + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h similarity index 57% rename from src/Mod/Assembly/Gui/ViewProviderConstraintFix.h rename to src/Mod/Assembly/Gui/TaskAssemblyConstraints.h index 7e0658880721..522e8095feb3 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.h +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h @@ -21,24 +21,52 @@ ***************************************************************************/ -#ifndef ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTFIX_H -#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTFIX_H +#ifndef GUI_TASKVIEW_TaskAssemblyConstraints_H +#define GUI_TASKVIEW_TaskAssemblyConstraints_H +#include +#include #include "ViewProviderConstraint.h" +#include +#include +#include +#include "ui_TaskAssemblyConstraints.h" -namespace AssemblyGui { - -class AssemblyGuiExport ViewProviderConstraintFix : public ViewProviderConstraint { +namespace App { +class Property; +} - PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintFix); +namespace AssemblyGui { + +class TaskAssemblyConstraints : public Gui::TaskView::TaskBox, public Gui::SelectionObserver +{ + Q_OBJECT public: - ViewProviderConstraintFix(); + TaskAssemblyConstraints(ViewProviderConstraint* vp); + ~TaskAssemblyConstraints(); - // override linked shape as we want to highlight the whole part - TopoDS_Shape getConstraintShape(int link); -}; + /// Observer message from the Selection + void onSelectionChanged(const Gui::SelectionChanges& msg); + +public Q_SLOTS: + void on_constraint_selection(bool clicked); + void on_value_change(double val); + void on_orientation_selection(bool clicked); + void on_clear_first(); + void on_clear_second(); +private: + QWidget* proxy; + Ui::TaskAssemblyConstraints* ui; + ViewProviderConstraint* view; + + void setOrientation(dcm::Direction); + dcm::Direction getOrientation(); + void setPossibleConstraints(); + bool isCombination(boost::shared_ptr g1, boost::shared_ptr g2, dcm::geometry::types t1, dcm::geometry::types t2); }; -#endif // VIEWPROVIDERCONSTRAINTFIX_H +} //namespace AssemblyGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui new file mode 100644 index 000000000000..f7039c466611 --- /dev/null +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui @@ -0,0 +1,979 @@ + + + TaskAssemblyConstraints + + + + 0 + 0 + 297 + 541 + + + + Form + + + + + + + + false + + + true + + + First constraint geometry + + + + + + + ... + + + + :/icons/delete.png:/icons/delete.png + + + true + + + + + + + + + + + false + + + true + + + Second constraint geometry + + + + + + + ... + + + + :/icons/delete.png:/icons/delete.png + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + QLayout::SetNoConstraint + + + + + + 0 + 0 + + + + Distance + + + + :/icons/Assembly_ConstraintDistance.svg:/icons/Assembly_ConstraintDistance.svg + + + + 20 + 20 + + + + true + + + false + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + 0 + 0 + + + + Coincident + + + + :/icons/Assembly_ConstraintCoincidence.svg:/icons/Assembly_ConstraintCoincidence.svg + + + + 20 + 20 + + + + true + + + false + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + 0 + 0 + + + + Fix + + + + :/icons/Assembly_ConstraintLock.svg:/icons/Assembly_ConstraintLock.svg + + + + 20 + 20 + + + + true + + + false + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + 0 + 0 + + + + Orientation + + + + :/icons/Assembly_ConstraintOrientation.svg:/icons/Assembly_ConstraintOrientation.svg + + + + 20 + 20 + + + + true + + + false + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + 0 + 0 + + + + Align + + + + :/icons/Assembly_ConstraintAlignment.svg:/icons/Assembly_ConstraintAlignment.svg + + + + 20 + 20 + + + + true + + + false + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + 0 + 0 + + + + Angle + + + + :/icons/Assembly_ConstraintAngle.svg:/icons/Assembly_ConstraintAngle.svg + + + + 20 + 20 + + + + true + + + false + + + true + + + Qt::ToolButtonTextBesideIcon + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 13 + + + + + + + + QFrame::HLine + + + QFrame::Raised + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 13 + + + + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + value + + + + + + + + 0 + 0 + + + + + + + + + + + ... + + + + :/icons/Assembly_ConstraintBidirectional.svg:/icons/Assembly_ConstraintBidirectional.svg + + + + 16 + 16 + + + + true + + + true + + + true + + + true + + + + + + + + 0 + 0 + + + + ... + + + + :/icons/Assembly_ConstraintUnidirectional2.svg:/icons/Assembly_ConstraintUnidirectional2.svg + + + + 16 + 16 + + + + true + + + true + + + true + + + + + + + + 0 + 0 + + + + ... + + + + :/icons/Assembly_ConstraintUnidirectional1.svg:/icons/Assembly_ConstraintUnidirectional1.svg + + + + 16 + 16 + + + + true + + + true + + + true + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 5 + 5 + + + + + + + + + + + + 0 + 0 + + + + Parallel + + + + :/icons/Assembly_ConstraintParallel.svg:/icons/Assembly_ConstraintParallel.svg + + + + 20 + 20 + + + + true + + + true + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + 0 + 0 + + + + Equal + + + + :/icons/Assembly_ConstraintEqual.svg:/icons/Assembly_ConstraintEqual.svg + + + + 20 + 20 + + + + true + + + true + + + true + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + 0 + 0 + + + + Opposite + + + + :/icons/Assembly_ConstraintOpposite.svg:/icons/Assembly_ConstraintOpposite.svg + + + + 20 + 20 + + + + true + + + true + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + 0 + 0 + + + + false + + + Perpend. + + + + :/icons/Assembly_ConstraintPerpendicular.svg:/icons/Assembly_ConstraintPerpendicular.svg + + + + 20 + 20 + + + + true + + + true + + + Qt::ToolButtonTextUnderIcon + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + distance + toggled(bool) + value_widget + setVisible(bool) + + + 170 + 94 + + + 172 + 210 + + + + + distance + toggled(bool) + orientation_widget + setHidden(bool) + + + 170 + 94 + + + 209 + 247 + + + + + fix + toggled(bool) + value_widget + setHidden(bool) + + + 58 + 94 + + + 209 + 210 + + + + + fix + toggled(bool) + orientation_widget + setHidden(bool) + + + 58 + 94 + + + 209 + 247 + + + + + orientation + toggled(bool) + value_widget + setHidden(bool) + + + 284 + 94 + + + 209 + 210 + + + + + orientation + toggled(bool) + orientation_widget + setVisible(bool) + + + 284 + 94 + + + 209 + 247 + + + + + angle + toggled(bool) + value_widget + setVisible(bool) + + + 58 + 126 + + + 172 + 209 + + + + + angle + toggled(bool) + orientation_widget + setHidden(bool) + + + 58 + 126 + + + 172 + 246 + + + + + align + toggled(bool) + value_widget + setVisible(bool) + + + 170 + 126 + + + 172 + 209 + + + + + align + toggled(bool) + orientation_widget + setVisible(bool) + + + 170 + 126 + + + 172 + 246 + + + + + coincident + toggled(bool) + value_widget + setHidden(bool) + + + 284 + 126 + + + 172 + 209 + + + + + coincident + toggled(bool) + orientation_widget + setVisible(bool) + + + 284 + 126 + + + 172 + 246 + + + + + distance + toggled(bool) + value + setFocus() + + + 170 + 94 + + + 147 + 203 + + + + + distance + toggled(bool) + value + selectAll() + + + 170 + 94 + + + 147 + 203 + + + + + angle + toggled(bool) + value + setFocus() + + + 58 + 126 + + + 147 + 203 + + + + + angle + toggled(bool) + value + selectAll() + + + 58 + 126 + + + 147 + 203 + + + + + align + toggled(bool) + value + setFocus() + + + 170 + 126 + + + 147 + 203 + + + + + align + toggled(bool) + value + selectAll() + + + 170 + 126 + + + 147 + 203 + + + + + diff --git a/src/Mod/Assembly/App/ConstraintFix.cpp b/src/Mod/Assembly/Gui/TaskDlgAssemblyConstraints.cpp similarity index 50% rename from src/Mod/Assembly/App/ConstraintFix.cpp rename to src/Mod/Assembly/Gui/TaskDlgAssemblyConstraints.cpp index fe05bb32baef..6834060da877 100644 --- a/src/Mod/Assembly/App/ConstraintFix.cpp +++ b/src/Mod/Assembly/Gui/TaskDlgAssemblyConstraints.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2010 Juergen Riegel * + * Copyright (c) 2009 Jürgen Riegel * * * * This file is part of the FreeCAD CAx development system. * * * @@ -22,60 +22,68 @@ #include "PreCompiled.h" + #ifndef _PreComp_ #endif -#include -#include -#include "ItemPart.h" +#include "TaskDlgAssemblyConstraints.h" +#include +#include -#include "ConstraintFix.h" +using namespace AssemblyGui; -using namespace Assembly; +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -namespace Assembly { +TaskDlgAssemblyConstraints::TaskDlgAssemblyConstraints(ViewProviderConstraint* vp) + : TaskDialog(), view(vp) +{ + Constraints = new TaskAssemblyConstraints(vp); + + Content.push_back(Constraints); +} +TaskDlgAssemblyConstraints::~TaskDlgAssemblyConstraints() +{ -PROPERTY_SOURCE(Assembly::ConstraintFix, Assembly::Constraint) +} -ConstraintFix::ConstraintFix() { +//==== calls from the TaskView =============================================================== -} -ConstraintFix::~ConstraintFix() { +void TaskDlgAssemblyConstraints::open() +{ - Assembly::ItemPart* part = static_cast(First.getValue()); - if(part && part->m_part) { - part->m_part->fix(false); - } } -short ConstraintFix::mustExecute() const { - //if (Sketch.isTouched() || - // Length.isTouched()) - // return 1; - return 0; +void TaskDlgAssemblyConstraints::clicked(int) +{ + } -App::DocumentObjectExecReturn* ConstraintFix::execute(void) { +bool TaskDlgAssemblyConstraints::accept() +{ + std::string document = getDocumentName(); // needed because resetEdit() deletes this instance + Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').resetEdit()", document.c_str()); - return App::DocumentObject::StdReturn; + return true; } -void ConstraintFix::init(Assembly::ItemAssembly* ass) { +bool TaskDlgAssemblyConstraints::reject() +{ + std::string document = getDocumentName(); // needed because resetEdit() deletes this instance + Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').resetEdit()", document.c_str()); - //cant use the base class init as we only need one part - initLink(First); - - //get the part - Assembly::ItemPart* part = static_cast(First.getValue()); - if(!part) - return; - - //init the constraint - part->m_part->fix(true); + return true; +} -}; +void TaskDlgAssemblyConstraints::helpRequested() +{ } + + +#include "moc_TaskDlgAssemblyConstraints.cpp" diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h b/src/Mod/Assembly/Gui/TaskDlgAssemblyConstraints.h similarity index 52% rename from src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h rename to src/Mod/Assembly/Gui/TaskDlgAssemblyConstraints.h index 51b1e849ae8f..08c9d9ea4eac 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.h +++ b/src/Mod/Assembly/Gui/TaskDlgAssemblyConstraints.h @@ -1,42 +1,70 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTANGLE_H -#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTANGLE_H - -#include "ViewProviderConstraint.h" - -namespace AssemblyGui { - -class AssemblyGuiExport ViewProviderConstraintAngle : public ViewProviderConstraint { - - PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintAngle); - -public: - ViewProviderConstraintAngle(); - -}; - -}; - -#endif // VIEWPROVIDERCONSTRAINTFIX_H +/*************************************************************************** + * Copyright (c) 2009 Jürgen Riegel * + * * + * 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 ASSEMBLYGUI_TaskDlgAssemblyConstraints_H +#define ASSEMBLYGUI_TaskDlgAssemblyConstraints_H + +#include +#include "TaskAssemblyConstraints.h" +#include "ViewProviderConstraint.h" + +namespace AssemblyGui { + + +/// simulation dialog for the TaskView +class AssemblyGuiExport TaskDlgAssemblyConstraints : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgAssemblyConstraints(ViewProviderConstraint* vp); + ~TaskDlgAssemblyConstraints(); + +public: + /// is called the TaskView when the dialog is opened + virtual void open(); + /// is called by the framework if an button is clicked which has no accept or reject role + virtual void clicked(int); + /// is called by the framework if the dialog is accepted (Ok) + virtual bool accept(); + /// is called by the framework if the dialog is rejected (Cancel) + virtual bool reject(); + /// is called by the framework if the user presses the help button + virtual void helpRequested(); + virtual bool isAllowedAlterDocument(void) const + { return false; } + + /// returns for Close and Help button + virtual QDialogButtonBox::StandardButtons getStandardButtons(void) const + { return QDialogButtonBox::Ok|QDialogButtonBox::Help; } + +protected: + TaskAssemblyConstraints *Constraints; + ViewProviderConstraint *view; +}; + + + +} //namespace AssemblyGui + +#endif // ASSEMBLYGUI_TaskDlgAssemblyConstraints_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp index 19445eba2156..f488bc9080c8 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.cpp @@ -22,11 +22,14 @@ #include "PreCompiled.h" #include "ViewProviderConstraint.h" +#include "TaskAssemblyConstraints.h" +#include "TaskDlgAssemblyConstraints.h" #include "Mod/Assembly/App/Constraint.h" #include "Mod/Assembly/App/ItemPart.h" #include #include #include +#include #include #include #include @@ -43,7 +46,7 @@ ViewProviderConstraintInternal::ViewProviderConstraintInternal() { //constraint entiti color ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 56319UL); + unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 56319UL); float r, g, b; r = ((scol >> 24) & 0xff) / 255.0; g = ((scol >> 16) & 0xff) / 255.0; @@ -74,6 +77,7 @@ ViewProviderConstraintInternal::ViewProviderConstraintInternal() PointSize.setValue(lwidth); Transparency.setValue(50); + }; void ViewProviderConstraintInternal::updateVis(const TopoDS_Shape& shape) @@ -103,10 +107,10 @@ void ViewProviderConstraintInternal::switch_node(bool onoff) pcModeSwitch->whichChild = -1; } -void ViewProviderConstraint::setDisplayMode(const char* ModeName) +void ViewProviderConstraint::setDisplayMode(const char* ModeName) { - setDisplayMaskMode("Flat Lines"); - + setDisplayMaskMode("Flat Lines"); + } std::vector ViewProviderConstraint::getDisplayModes(void) const @@ -127,7 +131,7 @@ ViewProviderConstraint::ViewProviderConstraint() : m_selected(false) //constraint entiti color ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 56319UL); + unsigned long scol = hGrp->GetUnsigned("ConstructionColor", 56319UL); float r, g, b; r = ((scol >> 24) & 0xff) / 255.0; g = ((scol >> 16) & 0xff) / 255.0; @@ -196,6 +200,24 @@ void ViewProviderConstraint::update(const App::Property* prop) { void ViewProviderConstraint::updateData(const App::Property* prop) { + + //set the icon + int v = dynamic_cast(getObject())->Type.getValue(); + if(v == 4) + sPixmap = "Assembly_ConstraintAlignment"; + if(v == 3) + sPixmap = "Assembly_ConstraintAngle"; + if(v == 5) + sPixmap = "Assembly_ConstraintCoincidence"; + if(v == 1) + sPixmap = "Assembly_ConstraintDistance"; + if(v == 0) + sPixmap = "Assembly_ConstraintLock"; + if(v == 2) + sPixmap = "Assembly_ConstraintOrientation"; + if(v==6) + sPixmap = "Assembly_ConstraintGeneral"; + if(Visibility.getValue() && m_selected) { draw(); @@ -206,7 +228,7 @@ void ViewProviderConstraint::updateData(const App::Property* prop) { } void ViewProviderConstraint::onChanged(const App::Property* prop) -{ +{ // parent expects the app object to be part::feature, but it isn't. so we have to avoid // the visability prop as this results in accessing of the part::feature and would crash if(prop == &Visibility) { @@ -293,22 +315,22 @@ void ViewProviderConstraint::draw() } void ViewProviderConstraint::upstream_placement(Base::Placement& p, Assembly::Item* item) { - - //successive transformation for this item - p = item->Placement.getValue() * p; - typedef std::vector::const_iterator iter; + //successive transformation for this item + p = item->Placement.getValue() * p; - //get all links to this item and see if we have more ItemAssemblys - const std::vector& vector = item->getInList(); - for(iter it=vector.begin(); it != vector.end(); it++) { + typedef std::vector::const_iterator iter; - if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + //get all links to this item and see if we have more ItemAssemblys + const std::vector& vector = item->getInList(); + for(iter it=vector.begin(); it != vector.end(); it++) { - upstream_placement(p, static_cast(*it)); - return; - } - }; + if((*it)->getTypeId() == Assembly::ItemAssembly::getClassTypeId()) { + + upstream_placement(p, static_cast(*it)); + return; + } + }; }; void ViewProviderConstraint::onSelectionChanged(const Gui::SelectionChanges& msg) @@ -320,7 +342,7 @@ void ViewProviderConstraint::onSelectionChanged(const Gui::SelectionChanges& msg pcModeSwitch->whichChild = 0; draw(); } - else { + else if(!isEditing()) { internal_vp.switch_node(false); pcModeSwitch->whichChild = -1; m_selected = false; @@ -350,7 +372,8 @@ TopoDS_Shape ViewProviderConstraint::getConstraintShape(int link) if(feature1->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { ts = static_cast(feature1)->Shape.getShape(); } - else return TopoDS_Shape(); + else + return TopoDS_Shape(); TopoDS_Shape s1 = ts.getSubShape(dynamic_cast(pcObject)->First.getSubValues()[0].c_str()); @@ -375,7 +398,8 @@ TopoDS_Shape ViewProviderConstraint::getConstraintShape(int link) if(feature2->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { ts2 = static_cast(feature2)->Shape.getShape(); } - else return TopoDS_Shape(); + else + return TopoDS_Shape(); TopoDS_Shape s2 = ts2.getSubShape(dynamic_cast(pcObject)->Second.getSubValues()[0].c_str()); @@ -387,3 +411,36 @@ void ViewProviderConstraint::setupContextMenu(QMenu* menu, QObject* receiver, co { ViewProviderDocumentObject::setupContextMenu(menu, receiver, member); } + +bool ViewProviderConstraint::setEdit(int ModNum) +{ + + // When double-clicking on the item for this sketch the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + TaskDlgAssemblyConstraints* ConstraintsDlg = qobject_cast(dlg); + + // start the edit dialog + if(ConstraintsDlg) + Gui::Control().showDialog(ConstraintsDlg); + else + Gui::Control().showDialog(new TaskDlgAssemblyConstraints(this)); + + //show the constraint geometries + internal_vp.switch_node(true); + pcModeSwitch->whichChild = 0; + draw(); + + return true; +} + +void ViewProviderConstraint::unsetEdit(int ModNum) +{ + if(!Gui::Selection().isSelected(pcObject) || !Visibility.getValue()) { + internal_vp.switch_node(false); + pcModeSwitch->whichChild = -1; + m_selected = false; + } +} + diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraint.h b/src/Mod/Assembly/Gui/ViewProviderConstraint.h index 7164968b922c..7aa57ef20a2f 100644 --- a/src/Mod/Assembly/Gui/ViewProviderConstraint.h +++ b/src/Mod/Assembly/Gui/ViewProviderConstraint.h @@ -91,16 +91,18 @@ class AssemblyGuiExport ViewProviderConstraint: public PartGui::ViewProviderPart virtual void setDisplayMode(const char* ModeName); virtual std::vector getDisplayModes(void) const; - //avoid transformation on doouble click - virtual bool doubleClicked(void) {return true;}; + //bring up constraint task when in edit mode + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + + //update visualisation and placements of the scenegraph + void draw(); private: //we need two seperate visual representations, as both constraint parts have different //placements. ViewProviderConstraintInternal internal_vp; - //update visualisation and placements of the scenegraph - void draw(); void upstream_placement(Base::Placement& p, Assembly::Item* item); //watch if something got selected in the tree diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp deleted file mode 100644 index b602be39e21d..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 "ViewProviderConstraintAlignment.h" - -using namespace AssemblyGui; - -PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintAlignment, Gui::ViewProviderDocumentObject) - -ViewProviderConstraintAlignment::ViewProviderConstraintAlignment() { - - sPixmap = "Assembly_ConstraintAlignment"; -} - diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h b/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h deleted file mode 100644 index 703937d25cb7..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAlignment.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTAlignment_H -#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTAlignment_H - -#include "ViewProviderConstraint.h" - -namespace AssemblyGui { - -class AssemblyGuiExport ViewProviderConstraintAlignment : public ViewProviderConstraint { - - PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintAlignment); - -public: - ViewProviderConstraintAlignment(); -}; - -}; - -#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp deleted file mode 100644 index 229f80869f56..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintAngle.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 "ViewProviderConstraintAngle.h" - -using namespace AssemblyGui; - -PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintAngle, Gui::ViewProviderDocumentObject) - -ViewProviderConstraintAngle::ViewProviderConstraintAngle() { - - sPixmap = "Assembly_ConstraintAngle"; -} - diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp deleted file mode 100644 index eeca7d5c024c..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 "ViewProviderConstraintCoincidence.h" - -using namespace AssemblyGui; - -PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintCoincidence, Gui::ViewProviderDocumentObject) - -ViewProviderConstraintCoincidence::ViewProviderConstraintCoincidence() { - - sPixmap = "Assembly_ConstraintCoincidence"; -} - diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h b/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h deleted file mode 100644 index e922488d06a2..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintCoincidence.h +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTCoincidence_H -#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTCoincidence_H - -#include "ViewProviderConstraint.h" - -namespace AssemblyGui { - -class AssemblyGuiExport ViewProviderConstraintCoincidence : public ViewProviderConstraint { - - PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintCoincidence); - -public: - ViewProviderConstraintCoincidence(); - -}; - -}; - -#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp deleted file mode 100644 index 817a6432f567..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 "ViewProviderConstraintDistance.h" - -using namespace AssemblyGui; - -PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintDistance, Gui::ViewProviderDocumentObject) - -ViewProviderConstraintDistance::ViewProviderConstraintDistance() { - - sPixmap = "Assembly_ConstraintDistance"; -} - diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h b/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h deleted file mode 100644 index 574158da1d80..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintDistance.h +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTDISTANCE_H -#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTDISTANCE_H - -#include -#include "ViewProviderConstraint.h" - -namespace AssemblyGui { - -class AssemblyGuiExport ViewProviderConstraintDistance : public ViewProviderConstraint { - - PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintDistance); - -public: - ViewProviderConstraintDistance(); - -}; - -}; - -#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp deleted file mode 100644 index 5e03f755b6b7..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintFix.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 "ViewProviderConstraintFix.h" -#include "Mod/Assembly/App/ConstraintFix.h" -#include "Mod/Assembly/App/ItemPart.h" -#include - -using namespace AssemblyGui; - -PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintFix, Gui::ViewProviderDocumentObject) - -ViewProviderConstraintFix::ViewProviderConstraintFix() { - - sPixmap = "Assembly_ConstraintLock"; -} - -TopoDS_Shape ViewProviderConstraintFix::getConstraintShape(int link) -{ - if(link == 1) { - - App::DocumentObject* obj = dynamic_cast(pcObject)->First.getValue(); - if(!obj) - return TopoDS_Shape(); - - Assembly::ItemPart* part = static_cast(obj); - if(!part) - return TopoDS_Shape(); - - //return the whole shape - return part->getShape(); - } - - //there is no second link, only one part is fixed per constraint - return TopoDS_Shape(); -} diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp deleted file mode 100644 index 4240613c49ce..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 "ViewProviderConstraintOrientation.h" - -using namespace AssemblyGui; - -PROPERTY_SOURCE(AssemblyGui::ViewProviderConstraintOrientation, Gui::ViewProviderDocumentObject) - -ViewProviderConstraintOrientation::ViewProviderConstraintOrientation() { - - sPixmap = "Assembly_ConstraintOrientation"; -} - diff --git a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h b/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h deleted file mode 100644 index 3f4bebfc0c50..000000000000 --- a/src/Mod/Assembly/Gui/ViewProviderConstraintOrientation.h +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2013 Stefan Tröger * - * * - * 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 ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTORIENTATION_H -#define ASSEMBLYGUI_VIEWPROVIDERCONSTRAINTORIENTATION_H - -#include "ViewProviderConstraint.h" - -namespace AssemblyGui { - -class AssemblyGuiExport ViewProviderConstraintOrientation : public ViewProviderConstraint { - - PROPERTY_HEADER(AssemblyGui::ViewProviderConstraintOrientation); - -public: - ViewProviderConstraintOrientation(); - -}; - -}; - -#endif // VIEWPROVIDERCONSTRAINTFIX_H diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index 3db61cf6bf3f..e003dbedc100 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -52,6 +52,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const Gui::ToolBarItem* root = StdWorkbench::setupToolBars(); Gui::ToolBarItem* part = new Gui::ToolBarItem(root); part->setCommand(QT_TR_NOOP("Assembly")); + *part << "Assembly_Constraint"; *part << "Assembly_ConstraintFix"; *part << "Assembly_ConstraintDistance"; *part << "Assembly_ConstraintOrientation"; From 5376e3a3e5ac7d902b06c97bc8e07a5b23b60ba9 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Tue, 15 Oct 2013 20:51:56 +0200 Subject: [PATCH 225/664] Fixed bugs in various features that reversed the list of selections --- .../PartDesign/Gui/TaskChamferParameters.cpp | 5 ++-- .../PartDesign/Gui/TaskDraftParameters.cpp | 5 ++-- .../PartDesign/Gui/TaskDressUpParameters.cpp | 2 +- .../PartDesign/Gui/TaskFilletParameters.cpp | 5 ++-- .../Gui/TaskLinearPatternParameters.cpp | 4 ++-- .../Gui/TaskLinearPatternParameters.cpp.orig | 24 ++++++++----------- .../PartDesign/Gui/TaskMirroredParameters.cpp | 4 ++-- .../Gui/TaskMirroredParameters.cpp.orig | 24 ++++++++----------- .../Gui/TaskMultiTransformParameters.cpp | 4 ++-- .../Gui/TaskMultiTransformParameters.cpp.orig | 24 ++++++++----------- .../Gui/TaskPolarPatternParameters.cpp | 4 ++-- .../Gui/TaskPolarPatternParameters.cpp.orig | 24 ++++++++----------- .../PartDesign/Gui/TaskScaledParameters.cpp | 4 ++-- .../Gui/TaskScaledParameters.cpp.orig | 24 ++++++++----------- 14 files changed, 70 insertions(+), 87 deletions(-) diff --git a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp index a0d53d1a75f5..9e9d9351f81e 100644 --- a/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskChamferParameters.cpp @@ -80,7 +80,7 @@ TaskChamferParameters::TaskChamferParameters(ViewProviderDressUp *DressUpView,QW std::vector strings = pcChamfer->Base.getSubValues(); for (std::vector::const_iterator i = strings.begin(); i != strings.end(); i++) { - ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); + ui->listWidgetReferences->addItem(QString::fromStdString(*i)); } // Create context menu QAction* action = new QAction(tr("Remove"), this); @@ -97,7 +97,7 @@ void TaskChamferParameters::onSelectionChanged(const Gui::SelectionChanges& msg) if (msg.Type == Gui::SelectionChanges::AddSelection) { if (referenceSelected(msg)) { if (selectionMode == refAdd) - ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName)); else removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); clearButtons(none); @@ -110,6 +110,7 @@ void TaskChamferParameters::clearButtons(const selectionModes notThis) { if (notThis != refAdd) ui->buttonRefAdd->setChecked(false); if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); + DressUpView->highlightReferences(false); } void TaskChamferParameters::onRefDeleted(void) diff --git a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp index a967509c62b7..65702bea7172 100644 --- a/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDraftParameters.cpp @@ -89,7 +89,7 @@ TaskDraftParameters::TaskDraftParameters(ViewProviderDressUp *DressUpView,QWidge std::vector strings = pcDraft->Base.getSubValues(); for (std::vector::const_iterator i = strings.begin(); i != strings.end(); ++i) { - ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); + ui->listWidgetReferences->addItem(QString::fromStdString(*i)); } // Create context menu QAction* action = new QAction(tr("Remove"), this); @@ -114,7 +114,7 @@ void TaskDraftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) if (msg.Type == Gui::SelectionChanges::AddSelection) { if (referenceSelected(msg)) { if (selectionMode == refAdd) - ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName)); else removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); clearButtons(none); @@ -151,6 +151,7 @@ void TaskDraftParameters::clearButtons(const selectionModes notThis) if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); if (notThis != line) ui->buttonLine->setChecked(false); if (notThis != plane) ui->buttonPlane->setChecked(false); + DressUpView->highlightReferences(false); } void TaskDraftParameters::onButtonPlane(bool checked) diff --git a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp index 31e1ca1f1c33..82afe610d458 100644 --- a/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDressUpParameters.cpp @@ -96,8 +96,8 @@ const bool TaskDressUpParameters::referenceSelected(const Gui::SelectionChanges& else return false; } - pcDressUp->Base.setValue(base, refs); DressUpView->highlightReferences(false); + pcDressUp->Base.setValue(base, refs); pcDressUp->getDocument()->recomputeFeature(pcDressUp); return true; diff --git a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp index 19ecbc715ec4..089534a6fab4 100644 --- a/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskFilletParameters.cpp @@ -80,7 +80,7 @@ TaskFilletParameters::TaskFilletParameters(ViewProviderDressUp *DressUpView,QWid std::vector strings = pcFillet->Base.getSubValues(); for (std::vector::const_iterator i = strings.begin(); i != strings.end(); i++) { - ui->listWidgetReferences->insertItem(0, QString::fromStdString(*i)); + ui->listWidgetReferences->addItem(QString::fromStdString(*i)); } // Create context menu QAction* action = new QAction(tr("Remove"), this); @@ -97,7 +97,7 @@ void TaskFilletParameters::onSelectionChanged(const Gui::SelectionChanges& msg) if (msg.Type == Gui::SelectionChanges::AddSelection) { if (referenceSelected(msg)) { if (selectionMode == refAdd) - ui->listWidgetReferences->insertItem(0, QString::fromStdString(msg.pSubName)); + ui->listWidgetReferences->addItem(QString::fromStdString(msg.pSubName)); else removeItemFromListWidget(ui->listWidgetReferences, msg.pSubName); clearButtons(none); @@ -110,6 +110,7 @@ void TaskFilletParameters::clearButtons(const selectionModes notThis) { if (notThis != refAdd) ui->buttonRefAdd->setChecked(false); if (notThis != refRemove) ui->buttonRefRemove->setChecked(false); + DressUpView->highlightReferences(false); } void TaskFilletParameters::onRefDeleted(void) diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp index ad2c757852d5..0a560e66c9bf 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp @@ -133,7 +133,7 @@ void TaskLinearPatternParameters::setupUI() for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); + ui->listWidgetFeatures->addItem(QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -235,7 +235,7 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges if (msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + ui->listWidgetFeatures->addItem(QString::fromLatin1(msg.pObjectName)); else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); diff --git a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig index 8357e5423591..00495a34d40d 100644 --- a/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskLinearPatternParameters.cpp.orig @@ -132,15 +132,12 @@ void TaskLinearPatternParameters::setupUI() // Fill data into dialog elements for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } -======= if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); ->>>>>>> Enable multiple originals for the transformed features +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Fixed bugs in various features that reversed the list of selections } // --------------------- @@ -241,18 +238,17 @@ void TaskLinearPatternParameters::onSelectionChanged(const Gui::SelectionChanges { if (msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode) { -======= if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii(msg.pObjectName)); +>>>>>>> Fixed bugs in various features that reversed the list of selections else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); } else if (selectionMode == reference) { ->>>>>>> Enable multiple originals for the transformed features // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp index e99932399099..7ef7507859ba 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp @@ -118,7 +118,7 @@ void TaskMirroredParameters::setupUI() for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); + ui->listWidgetFeatures->addItem(QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -192,7 +192,7 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg if (originalSelected(msg)) { if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + ui->listWidgetFeatures->addItem(QString::fromLatin1(msg.pObjectName)); else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); diff --git a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig index 37fc6cf74414..d4e499753a02 100644 --- a/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskMirroredParameters.cpp.orig @@ -117,15 +117,12 @@ void TaskMirroredParameters::setupUI() // Fill data into dialog elements for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } -======= if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); ->>>>>>> Enable multiple originals for the transformed features +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Fixed bugs in various features that reversed the list of selections } // --------------------- @@ -198,17 +195,16 @@ void TaskMirroredParameters::onSelectionChanged(const Gui::SelectionChanges& msg if (msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode) { -======= if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii(msg.pObjectName)); +>>>>>>> Fixed bugs in various features that reversed the list of selections else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); } else if (selectionMode == reference) { ->>>>>>> Enable multiple originals for the transformed features // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp index 98a2f4635ddf..7cd9a8eaf15d 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp @@ -142,7 +142,7 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform for (std::vector::const_iterator i = originals.begin(); i != originals.end(); i++) { if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); + ui->listWidgetFeatures->addItem(QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- } @@ -151,7 +151,7 @@ void TaskMultiTransformParameters::onSelectionChanged(const Gui::SelectionChange { if (originalSelected(msg)) { if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + ui->listWidgetFeatures->addItem(QString::fromLatin1(msg.pObjectName)); else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); diff --git a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig index ba9a802e0275..c9c1474e5d2e 100644 --- a/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskMultiTransformParameters.cpp.orig @@ -141,15 +141,12 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform // Fill data into dialog elements for (std::vector::const_iterator i = originals.begin(); i != originals.end(); i++) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } -======= if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); ->>>>>>> Enable multiple originals for the transformed features +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Fixed bugs in various features that reversed the list of selections } // --------------------- } @@ -157,16 +154,15 @@ TaskMultiTransformParameters::TaskMultiTransformParameters(ViewProviderTransform void TaskMultiTransformParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (originalSelected(msg)) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - App::DocumentObject* selectedObject = TransformedView->getObject()->getDocument()->getActiveObject(); - ui->lineOriginal->setText(QString::fromLatin1(selectedObject->getNameInDocument())); -======= if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii(msg.pObjectName)); +>>>>>>> Fixed bugs in various features that reversed the list of selections else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); ->>>>>>> Enable multiple originals for the transformed features } } diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp index 16faa793d097..330e585e6b27 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp @@ -132,7 +132,7 @@ void TaskPolarPatternParameters::setupUI() for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); + ui->listWidgetFeatures->addItem(QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -206,7 +206,7 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& if (originalSelected(msg)) { if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + ui->listWidgetFeatures->addItem(QString::fromLatin1(msg.pObjectName)); else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); diff --git a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig index 5ab4878fce73..0b5b6c0f500c 100644 --- a/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskPolarPatternParameters.cpp.orig @@ -131,15 +131,12 @@ void TaskPolarPatternParameters::setupUI() // Fill data into dialog elements for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } -======= if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); ->>>>>>> Enable multiple originals for the transformed features +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Fixed bugs in various features that reversed the list of selections } // --------------------- @@ -212,17 +209,16 @@ void TaskPolarPatternParameters::onSelectionChanged(const Gui::SelectionChanges& if (msg.Type == Gui::SelectionChanges::AddSelection) { if (originalSelected(msg)) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - ui->lineOriginal->setText(QString::fromLatin1(msg.pObjectName)); - } else if (referenceSelectionMode) { -======= if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii(msg.pObjectName)); +>>>>>>> Fixed bugs in various features that reversed the list of selections else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); } else if (selectionMode == reference) { ->>>>>>> Enable multiple originals for the transformed features // Note: ReferenceSelection has already checked the selection for validity exitSelectionMode(); if (!blockUpdate) { diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp index fd5995794e58..815bcff7c139 100644 --- a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp @@ -114,7 +114,7 @@ void TaskScaledParameters::setupUI() for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); + ui->listWidgetFeatures->addItem(QString::fromLatin1((*i)->getNameInDocument())); } // --------------------- @@ -149,7 +149,7 @@ void TaskScaledParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (originalSelected(msg)) { if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); + ui->listWidgetFeatures->addItem(QString::fromLatin1(msg.pObjectName)); else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); diff --git a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig index 5729ca98d105..a727feefe708 100644 --- a/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig +++ b/src/Mod/PartDesign/Gui/TaskScaledParameters.cpp.orig @@ -113,15 +113,12 @@ void TaskScaledParameters::setupUI() // Fill data into dialog elements for (std::vector::const_iterator i = originals.begin(); i != originals.end(); ++i) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - if ((*i) != NULL) { // find the first valid original - ui->lineOriginal->setText(QString::fromLatin1((*i)->getNameInDocument())); - break; - } -======= if ((*i) != NULL) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii((*i)->getNameInDocument())); ->>>>>>> Enable multiple originals for the transformed features +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1((*i)->getNameInDocument())); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii((*i)->getNameInDocument())); +>>>>>>> Fixed bugs in various features that reversed the list of selections } // --------------------- @@ -155,16 +152,15 @@ void TaskScaledParameters::updateUI() void TaskScaledParameters::onSelectionChanged(const Gui::SelectionChanges& msg) { if (originalSelected(msg)) { -<<<<<<< eb9a4ab96f8703de819cdc5e405217b784ccff90 - App::DocumentObject* selectedObject = TransformedView->getObject()->getDocument()->getActiveObject(); - ui->lineOriginal->setText(QString::fromLatin1(selectedObject->getNameInDocument())); -======= if (selectionMode == addFeature) - ui->listWidgetFeatures->insertItem(0, QString::fromAscii(msg.pObjectName)); +<<<<<<< 9bd4990584bfddd638e710ece8d981c1d8e4cc5e + ui->listWidgetFeatures->insertItem(0, QString::fromLatin1(msg.pObjectName)); +======= + ui->listWidgetFeatures->addItem(QString::fromAscii(msg.pObjectName)); +>>>>>>> Fixed bugs in various features that reversed the list of selections else removeItemFromListWidget(ui->listWidgetFeatures, msg.pObjectName); exitSelectionMode(); ->>>>>>> Enable multiple originals for the transformed features } } From 3abda4dd67c9133ebb51bffc5fed11ab349b57aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Fri, 18 Oct 2013 19:02:54 +0000 Subject: [PATCH 226/664] new dcm version --- .../Assembly/App/opendcm/core/constraint.hpp | 2 +- .../Assembly/App/opendcm/core/equations.hpp | 173 +++++++++++++----- .../App/opendcm/module3d/alignment.hpp | 16 +- .../Assembly/App/opendcm/module3d/angle.hpp | 4 +- .../App/opendcm/module3d/coincident.hpp | 25 ++- .../App/opendcm/module3d/distance.hpp | 122 ++++++++++-- .../App/opendcm/module3d/parallel.hpp | 35 ++-- .../App/opendcm/moduleShape3d/distance.hpp | 5 +- .../App/opendcm/moduleShape3d/fixed.hpp | 15 +- 9 files changed, 290 insertions(+), 107 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index 5d5cf88b76cc..c9cc12259872 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -447,7 +447,7 @@ Constraint::holder::OptionSetter::op typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; BOOST_MPL_ASSERT((mpl::not_::type > >)); - val.m_eq.value = fusion::at(objects).value; + fusion::copy(fusion::at(objects).values, val.m_eq.values); val.pure_rotation = fusion::at(objects).pure_rotation; }; diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index 0bca861343dd..2b345f9e2563 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -34,6 +34,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -44,12 +48,18 @@ namespace mpl = boost::mpl; namespace dcm { +//the possible directions +enum Direction { parallel, equal, opposite, perpendicular }; + +//the possible solution spaces +enum SolutionSpace {unidirectional, positiv_directional, negative_directional}; + struct no_option {}; template struct Pseudo { typedef std::vector > Vec; - + template void calculatePseudo(const E::MatrixBase& param1, Vec& v1, const E::MatrixBase& param2, Vec& v2) {}; }; @@ -62,7 +72,7 @@ struct Scale { template struct PseudoScale { typedef std::vector > Vec; - + template void calculatePseudo(const E::MatrixBase& param1, Vec& v1, const E::MatrixBase& param2, Vec& v2) {}; void setScale(typename Kernel::number_type scale) {}; @@ -83,8 +93,8 @@ struct constraint_sequence : public seq { typedef typename pushed_seq::type Sequence; typedef typename fusion::result_of::begin::type Begin; - typedef typename fusion::result_of::end::type End; - typedef typename fusion::result_of::prior::type EndOld; + typedef typename fusion::result_of::find::S1>::type >::type EndOld; + //create the new sequence Sequence vec; @@ -97,7 +107,7 @@ struct constraint_sequence : public seq { fusion::copy(*this, range); //insert this object at the end of the sequence - fusion::back(vec) = val; + *fusion::find(vec) = val; //and return our new extendet sequence return vec; @@ -114,27 +124,31 @@ struct constraint_sequence : public seq { typedef typename pushed_seq::type Sequence; typedef typename fusion::result_of::begin::type Begin; - typedef typename fusion::result_of::end::type End; + typedef typename fusion::result_of::find::S1>::type >::type EndF; - typedef typename mpl::distance< typename mpl::begin::type, typename mpl::end::type >::type distanceF; - typedef typename fusion::result_of::advance::type EndF; //create the new sequence Sequence vec; - //copy the given values into the new sequence Begin b(vec); EndF ef(vec); fusion::iterator_range range(b, ef); fusion::copy(val, range); - //copy the objects value into the new sequence - EndF bb(vec); - End e(vec); - fusion::iterator_range range2(bb, e); - fusion::copy(*this, range2); + //to copy the types of the second sequence is not as easy as before. If types were already present in + //the original sequence they are not added again. therefore we need to find all types of the second sequence + //in the new one and assign the objects to this positions. + + //get a index vector for all second-sequence-elements + typedef typename mpl::transform::S2, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector; + + //and copy the types in + fusion::nview view(vec); + fusion::copy(*this, view); //and return our new extendet sequence return vec; @@ -145,45 +159,82 @@ template struct pushed_seq { typedef typename mpl::if_, Seq, fusion::vector1 >::type S1; typedef typename mpl::if_, T, fusion::vector1 >::type S2; - typedef typename fusion::result_of::as_vector >::type >::type vec; + + typedef typename mpl::fold< S2, S1, mpl::if_< boost::is_same< + mpl::find, mpl::end >, mpl::push_back, mpl::_1> >::type unique_vector; + + typedef typename fusion::result_of::as_vector< unique_vector >::type vec; typedef constraint_sequence type; }; template struct Equation : public EQ { - typedef Option option_type; - option_type value; + typedef typename mpl::if_, Option, mpl::vector - + From 64ec142d61a38971abfff056dc1e31f9b1cdcda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Sun, 20 Oct 2013 15:01:47 +0200 Subject: [PATCH 228/664] Fix solution space behaviour and further distinguish alignment/coincident --- src/Mod/Assembly/App/ItemAssembly.cpp | 14 ++- .../App/opendcm/module3d/alignment.hpp | 99 +++++++++++++++- .../App/opendcm/module3d/coincident.hpp | 43 +++++-- .../App/opendcm/module3d/distance.hpp | 18 ++- .../App/opendcm/module3d/parallel.hpp | 13 +-- .../Assembly/Gui/TaskAssemblyConstraints.cpp | 110 +++++++++++++++++- .../Assembly/Gui/TaskAssemblyConstraints.h | 1 + 7 files changed, 273 insertions(+), 25 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 431ec584e425..5ef714b337dd 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -75,17 +75,25 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) { } catch(dcm::solving_error& e) { - Base::Console().Error("Solver failed with error %i: %s", + Base::Console().Error("Solver failed with error %i: %s\n", *boost::get_error_info(e), boost::get_error_info(e)->c_str()); } catch(dcm::creation_error& e) { - Base::Console().Error("Creation failed with error %i: %s", + Base::Console().Error("Creation failed with error %i: %s\n", + *boost::get_error_info(e), + boost::get_error_info(e)->c_str()); + } + catch(boost::exception& e) { + Base::Console().Error("Solver exception raised: %i: %s\n", *boost::get_error_info(e), boost::get_error_info(e)->c_str()); } catch(std::exception& e) { - Base::Console().Error("Exception raised in assembly solver: %s", e.what()); + Base::Console().Error("Exception raised in assembly solver: %s\n", e.what()); + } + catch(...) { + Base::Console().Error("Unknown Exception raised in assembly solver during execution\n"); }; this->touch(); return App::DocumentObject::StdReturn; diff --git a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp index 23893ac3fb1b..df4764556917 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp @@ -22,12 +22,107 @@ #include #include "distance.hpp" +#include "coincident.hpp" namespace dcm { -struct Alignment : public constraint_sequence< fusion::vector2< Distance, Orientation > > { +namespace details { +//we need a custom orientation type to allow coincidents with points. We can't use the ci_orietation +//as some geometries are supporte by align but not by coincident +struct al_orientation : public Equation { + + using Equation::operator=; + using Equation::options; + al_orientation() : Equation() { + setDefault(); + }; + + al_orientation& operator=(const al_orientation& d) { + return Equation::operator=(d); + }; + + void setDefault() { + fusion::at_key(values) = std::make_pair(false, parallel); + }; + + template< typename Kernel, typename Tag1, typename Tag2 > + struct type : public PseudoScale { + + type() { + throw constraint_error() << boost::errinfo_errno(103) << error_message("unsupported geometry in alignment orientation constraint") + << error_type_first_geometry(typeid(Tag1).name()) << error_type_second_geometry(typeid(Tag2).name()); + }; + + typedef typename Kernel::number_type Scalar; + typedef typename Kernel::VectorMap Vector; + typedef std::vector > Vec; + + typename al_orientation::options values; + template + Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { + assert(false); + return 0; + }; + template + Scalar calculateGradientFirst(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam1) { + assert(false); + return 0; + }; + template + Scalar calculateGradientSecond(const E::MatrixBase& param1, + const E::MatrixBase& param2, + const E::MatrixBase& dparam2) { + assert(false); + return 0; + }; + template + void calculateGradientFirstComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { + assert(false); + }; + template + void calculateGradientSecondComplete(const E::MatrixBase& param1, + const E::MatrixBase& param2, + E::MatrixBase& gradient) { + assert(false); + }; + }; +}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::line3D, tag::line3D > : public ci_orientation::type< Kernel, tag::line3D, tag::line3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::line3D, tag::plane3D > : public ci_orientation::type< Kernel, tag::line3D, tag::plane3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > {}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::plane3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::cylinder3D > { + //we missuse the scale method to change whatever direction was set to the only valid one: perpendicular + void setScale(typename Kernel::number_type scale) { + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D >::values).second = perpendicular; + }; +}; + +template< typename Kernel > +struct al_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; + - using constraint_sequence::operator=; +}; //namespace details + +//use al_orientation to ensure the correct orientations for alignment (distance is only defined for special +//orientations) +struct Alignment : public constraint_sequence< fusion::vector2< Distance, details::al_orientation > > { + + using constraint_sequence::operator=; }; static Alignment alignment; diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index 566075453995..86fb690168d5 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -35,7 +35,7 @@ struct ci_orientation : public Equation { ci_orientation() : Equation() { setDefault(); }; - + ci_orientation& operator=(const ci_orientation& d) { return Equation::operator=(d); }; @@ -138,19 +138,48 @@ template< typename Kernel > struct ci_orientation::type< Kernel, tag::point3D, tag::cylinder3D > : public ci_orientation::type< Kernel, tag::point3D, tag::point3D > {}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::line3D > {}; +struct ci_orientation::type< Kernel, tag::line3D, tag::line3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::line3D > { + //we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::line3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::line3D >::values).second = parallel; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D > {}; +struct ci_orientation::type< Kernel, tag::line3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D > { + //we missuse the scale method to change whatever direction was set to the only valid one: perpendicular + void setScale(typename Kernel::number_type scale) { + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::plane3D >::values).second = perpendicular; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D > {}; +struct ci_orientation::type< Kernel, tag::line3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D > { + //we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::line3D, tag::cylinder3D >::values).second = parallel; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D > {}; +struct ci_orientation::type< Kernel, tag::plane3D, tag::plane3D > : public dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D > { +//we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::plane3D, tag::plane3D >::values).second = parallel; + }; +}; template< typename Kernel > -struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > {}; +struct ci_orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > : public dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D > { + //we missuse the scale method to prevent a unallowed direcion: perpendicular (ad distance is not defined for it) + void setScale(typename Kernel::number_type scale) { + if(fusion::at_key(dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D >::values).second == perpendicular) + fusion::at_key(dcm::Orientation::type< Kernel, tag::cylinder3D, tag::cylinder3D >::values).second = parallel; + }; +}; @@ -162,7 +191,7 @@ struct ci_distance : public Equation : public Distance: typedef typename Kernel::number_type Scalar; typedef typename Kernel::VectorMap Vector; + using Distance::type< Kernel, tag::line3D, tag::line3D >::sc_value; + Scalar result; + SolutionSpace sspace; #ifdef USE_LOGGING type() : Distance::type< Kernel, tag::line3D, tag::line3D >() { @@ -578,11 +581,22 @@ struct Distance::type< Kernel, tag::line3D, tag::cylinder3D > : public Distance: }; #endif + void setScale(Scalar scale) { + Distance::type< Kernel, tag::line3D, tag::line3D >::setScale(scale); + sspace = fusion::at_key(Distance::type< Kernel, tag::line3D, tag::line3D >::values).second; + }; + template Scalar calculate(const E::MatrixBase& param1, const E::MatrixBase& param2) { //(p1-p2)°n / |n| - distance - const Scalar res = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2); - return res - param2(6); + result = Distance::type< Kernel, tag::line3D, tag::line3D >::calculate(param1, param2) - param2(6); + + //for parallel line and cylinder we may use the solution space methods + if(Kernel::isSame(Distance::type< Kernel, tag::line3D, tag::line3D >::nxn_n, 0, 1e-6) && + (sspace==negative_directional || (sspace == bidirectional && (result+sc_value)<0.))) + return result+2*sc_value; + + return result; }; template diff --git a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp index 7f8b504ba7d2..f93eebf220a2 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/parallel.hpp @@ -47,7 +47,8 @@ inline typename Kernel::number_type calc(const E::MatrixBase& d1, return (d1+d2).norm(); case perpendicular: return d1.dot(d2); - default: + default + : assert(false); } return 0; @@ -265,13 +266,9 @@ struct Orientation::type< Kernel, tag::line3D, tag::plane3D > : public Orientati options values; - dcm::Direction getValue() { - dcm::Direction value = fusion::at_key(values).second; - if(value==parallel) - return perpendicular; - if(value==perpendicular) - return parallel; - return value; + //makes it possible to allow only partial directions for derived constraints + inline dcm::Direction getValue() { + return fusion::at_key(values).second; }; //template definition diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp index b4e9a265c058..7e27153b00e3 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp @@ -108,6 +108,7 @@ TaskAssemblyConstraints::TaskAssemblyConstraints(ViewProviderConstraint* vp) setPossibleConstraints(); + setPossibleOptions(); //setup all signals for event processing QObject::connect( @@ -188,7 +189,8 @@ void TaskAssemblyConstraints::setOrientation(dcm::Direction d) case dcm::opposite: ui->opposite->setChecked(true); break; - default: + default + : ui->parallel->setChecked(true); } } @@ -212,7 +214,8 @@ void TaskAssemblyConstraints::setSolutionSpace(dcm::SolutionSpace d) case dcm::positiv_directional: ui->pos_direction->setChecked(true); break; - default: + default + : ui->neg_direction->setChecked(true); } } @@ -246,6 +249,7 @@ void TaskAssemblyConstraints::onSelectionChanged(const Gui::SelectionChanges& ms App::GetApplication().getActiveDocument()->recompute(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); return; } @@ -268,6 +272,7 @@ void TaskAssemblyConstraints::onSelectionChanged(const Gui::SelectionChanges& ms App::GetApplication().getActiveDocument()->recompute(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); return; } @@ -300,6 +305,7 @@ void TaskAssemblyConstraints::on_constraint_selection(bool clicked) App::GetApplication().getActiveDocument()->recompute(); view->draw(); } + setPossibleOptions(); } @@ -341,6 +347,7 @@ void TaskAssemblyConstraints::on_clear_first() obj->First.setValue(NULL); ui->first_geom->clear(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); } @@ -351,11 +358,107 @@ void TaskAssemblyConstraints::on_clear_second() obj->Second.setValue(NULL); ui->second_geom->clear(); setPossibleConstraints(); + setPossibleOptions(); view->draw(); } +void TaskAssemblyConstraints::setPossibleOptions() { + + //disable all orientations for later easy disabling + ui->parallel->setEnabled(false); + ui->equal->setEnabled(false); + ui->opposite->setEnabled(false); + ui->perpendicular->setEnabled(false); + + //disable solution spaces for later easy enabling + ui->bidirectional->setEnabled(false); + ui->pos_direction->setEnabled(false); + ui->neg_direction->setEnabled(false); + + //this only works if both objects are set + Assembly::Constraint* obj = dynamic_cast(view->getObject()); + if(obj->First.getValue()) { + + Assembly::ItemPart* p1 = dynamic_cast(obj->First.getValue()); + if(!p1) + return; + + Assembly::ItemAssembly* ass = p1->getParentAssembly(); + + //extract the geometries to use for comparison + boost::shared_ptr g1 = ass->m_solver->getGeometry3D(obj->First.getSubValues()[0].c_str()); + if(obj->Second.getValue()) { + + Assembly::ItemPart* p2 = dynamic_cast(obj->Second.getValue()); + if(!p2) + return; + boost::shared_ptr g2 = ass->m_solver->getGeometry3D(obj->Second.getSubValues()[0].c_str()); + + //distance + if(obj->Type.getValue() == 1) { + + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::point, dcm::geometry::cylinder)) { + ui->bidirectional->setEnabled(true); + ui->pos_direction->setEnabled(true); + ui->neg_direction->setEnabled(true); + }; + }; + //align & coincident + if(obj->Type.getValue() == 4 || obj->Type.getValue() == 5) { + + if(isCombination(g1,g2, dcm::geometry::point, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::point, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { + ui->bidirectional->setEnabled(true); + ui->pos_direction->setEnabled(true); + ui->neg_direction->setEnabled(true); + }; + + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder)) { + ui->parallel->setEnabled(true); + ui->equal->setEnabled(true); + ui->opposite->setEnabled(true); + + //ensure that perpendicular is not checked + if(ui->perpendicular->isChecked()) { + ui->parallel->setChecked(true); + obj->Orientation.setValue((long)0); + } + }; + + if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::plane) || + isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { + ui->perpendicular->setEnabled(true); + + //ensure that perpendicular is checked + if(!ui->perpendicular->isChecked()) { + ui->perpendicular->setChecked(true); + obj->Orientation.setValue((long)3); + } + }; + }; + + //orientation + if(obj->Type.getValue() == 2) { + ui->parallel->setEnabled(true); + ui->equal->setEnabled(true); + ui->opposite->setEnabled(true); + ui->perpendicular->setEnabled(true); + } + + } + } +}; + void TaskAssemblyConstraints::setPossibleConstraints() { + //diasble all constraints for easyer enabling ui->fix->setEnabled(false); ui->distance->setEnabled(false); ui->orientation->setEnabled(false); @@ -428,11 +531,12 @@ void TaskAssemblyConstraints::setPossibleConstraints() if(isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::cylinder)) { ui->orientation->setEnabled(true); ui->angle->setEnabled(true); - ui->coincident->setEnabled(true); ui->align->setEnabled(true); }; if(isCombination(g1,g2, dcm::geometry::cylinder, dcm::geometry::cylinder)) { ui->coincident->setEnabled(true); + ui->orientation->setEnabled(true); + ui->angle->setEnabled(true); }; } else { diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h index 7f176faef128..a745ce53f796 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h @@ -67,6 +67,7 @@ public Q_SLOTS: void setSolutionSpace(dcm::SolutionSpace d); dcm::SolutionSpace getSolutionSpace(); void setPossibleConstraints(); + void setPossibleOptions(); bool isCombination(boost::shared_ptr g1, boost::shared_ptr g2, dcm::geometry::types t1, dcm::geometry::types t2); }; From c1d799e8315bd9dcafd52d4b9c4413a0b2142b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 21 Oct 2013 21:49:54 +0200 Subject: [PATCH 229/664] prevent dangling pointers by clearing the active assembly after it was deleted --- src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp | 61 ++++++++++++------- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 4 ++ 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp index 9f75430d330d..84fbd5d71428 100644 --- a/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp +++ b/src/Mod/Assembly/Gui/AppAssemblyGuiPy.cpp @@ -37,53 +37,63 @@ #include // pointer to the active assembly object -Assembly::Item *ActiveAsmObject =0; -Gui::Document *ActiveGuiDoc =0; -App::Document *ActiveAppDoc =0; -Gui::ViewProviderDocumentObject *ActiveVp =0; +Assembly::Item* ActiveAsmObject =0; +Gui::Document* ActiveGuiDoc =0; +App::Document* ActiveAppDoc =0; +Gui::ViewProviderDocumentObject* ActiveVp =0; /* module functions */ -static PyObject * setActiveAssembly(PyObject *self, PyObject *args) -{ - if(ActiveAsmObject){ +static PyObject* setActiveAssembly(PyObject* self, PyObject* args) +{ + if(ActiveAsmObject) { // check if the document not already closed std::vector docs = App::GetApplication().getDocuments(); - for(std::vector::const_iterator it=docs.begin();it!=docs.end();++it) - if(*it == ActiveAppDoc){ + for(std::vector::const_iterator it=docs.begin(); it!=docs.end(); ++it) + if(*it == ActiveAppDoc) { ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,false); break; } - + ActiveAsmObject = 0; ActiveGuiDoc =0; ActiveAppDoc =0; ActiveVp =0; } - PyObject *object=0; - if (PyArg_ParseTuple(args,"|O!",&(Assembly::ItemPy::Type), &object)&& object) { + PyObject* object=0; + if(PyArg_ParseTuple(args,"|O!",&(Assembly::ItemPy::Type), &object)&& object) { Assembly::Item* Item = static_cast(object)->getItemPtr(); // Should be set! - assert(Item); + assert(Item); - // get the gui document of the Assembly Item + // get the gui document of the Assembly Item ActiveAsmObject = Item; ActiveAppDoc = Item->getDocument(); ActiveGuiDoc = Gui::Application::Instance->getDocument(ActiveAppDoc); - ActiveVp = dynamic_cast (ActiveGuiDoc->getViewProvider(Item)) ; + ActiveVp = dynamic_cast(ActiveGuiDoc->getViewProvider(Item)) ; ActiveGuiDoc->signalHighlightObject(*ActiveVp,Gui::Blue,true); } Py_Return; } +static PyObject* clearActiveAssembly(PyObject* self, PyObject* args) { + + ActiveAsmObject = 0; + ActiveGuiDoc =0; + ActiveAppDoc =0; + ActiveVp =0; + + Py_Return; +} + /* module functions */ -static PyObject * getActiveAssembly(PyObject *self, PyObject *args) -{ - if(ActiveAsmObject){ - +static PyObject* getActiveAssembly(PyObject* self, PyObject* args) +{ + if(ActiveAsmObject) { + return ActiveAsmObject->getPyObject(); } @@ -94,10 +104,15 @@ static PyObject * getActiveAssembly(PyObject *self, PyObject *args) /* registration table */ struct PyMethodDef AssemblyGui_Import_methods[] = { - {"setActiveAssembly" ,setActiveAssembly ,METH_VARARGS, - "setActiveAssembly(AssemblyObject) -- Set the Assembly object in work."}, - {"getActiveAssembly" ,getActiveAssembly ,METH_VARARGS, - "getActiveAssembly() -- Returns the Assembly object in work."}, + { "setActiveAssembly" ,setActiveAssembly ,METH_VARARGS, + "setActiveAssembly(AssemblyObject) -- Set the Assembly object in work." + }, + { "getActiveAssembly" ,getActiveAssembly ,METH_VARARGS, + "getActiveAssembly() -- Returns the Assembly object in work." + }, + { "clearActiveAssembly" ,clearActiveAssembly ,METH_VARARGS, + "clearActiveAssembly() -- Removes the current active Assembly as object in work" + }, {NULL, NULL} /* end of table marker */ }; diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 8cdb3fe5713f..301e569d6165 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -35,6 +35,8 @@ using namespace AssemblyGui; +extern Assembly::ItemAssembly* ActiveAsmObject; + PROPERTY_SOURCE(AssemblyGui::ViewProviderItemAssembly,AssemblyGui::ViewProviderItem) ViewProviderItemAssembly::ViewProviderItemAssembly() @@ -43,6 +45,8 @@ ViewProviderItemAssembly::ViewProviderItemAssembly() ViewProviderItemAssembly::~ViewProviderItemAssembly() { + if(getObject() == ActiveAsmObject) + Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.clearActiveAssembly()"); } bool ViewProviderItemAssembly::doubleClicked(void) From 9fdeef50fe85c5f3a1f388e532233901e15dfaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 05:59:16 +0200 Subject: [PATCH 230/664] update logging to be used with boost1.54 and make it a compile option --- src/Mod/Assembly/App/CMakeLists.txt | 2 ++ .../Assembly/App/opendcm/core/geometry.hpp | 4 ++++ src/Mod/Assembly/App/opendcm/core/logging.hpp | 21 +++++++++---------- .../App/opendcm/core/transformation.hpp | 16 +++++++------- .../App/opendcm/module3d/distance.hpp | 2 +- .../Assembly/App/opendcm/module3d/module.hpp | 10 ++++++--- .../Assembly/App/opendcm/module3d/solver.hpp | 15 ++++++++++--- .../App/opendcm/moduleShape3d/module.hpp | 4 ++++ src/Mod/Assembly/CMakeLists.txt | 7 +++++++ 9 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src/Mod/Assembly/App/CMakeLists.txt b/src/Mod/Assembly/App/CMakeLists.txt index c96dbc9fa611..bcbd962e490f 100644 --- a/src/Mod/Assembly/App/CMakeLists.txt +++ b/src/Mod/Assembly/App/CMakeLists.txt @@ -24,6 +24,8 @@ include_directories( set(Assembly_LIBS ${ODE_LIBRARIES} ${OCC_LIBRARIES} + ${Boost_LIBRARIES} + ${Boost_LOG_LIBRARY_RELEASE} Part FreeCADApp ) diff --git a/src/Mod/Assembly/App/opendcm/core/geometry.hpp b/src/Mod/Assembly/App/opendcm/core/geometry.hpp index d85852bcd018..eff183ec27d3 100644 --- a/src/Mod/Assembly/App/opendcm/core/geometry.hpp +++ b/src/Mod/Assembly/App/opendcm/core/geometry.hpp @@ -49,6 +49,10 @@ #include "logging.hpp" #include "transformation.hpp" +#ifdef USE_LOGGING +#include +#endif + namespace mpl = boost::mpl; namespace fusion = boost::fusion; diff --git a/src/Mod/Assembly/App/opendcm/core/logging.hpp b/src/Mod/Assembly/App/opendcm/core/logging.hpp index fd915a36fbd7..bef24ef9b193 100644 --- a/src/Mod/Assembly/App/opendcm/core/logging.hpp +++ b/src/Mod/Assembly/App/opendcm/core/logging.hpp @@ -22,24 +22,23 @@ #ifdef USE_LOGGING +#define BOOST_LOG_DYN_LINK + #include #include +#include +#include #include -#include -#include -#include #include #include -#include -#include +#include #include namespace logging = boost::log; namespace sinks = boost::log::sinks; namespace src = boost::log::sources; -namespace fmt = boost::log::formatters; -namespace flt = boost::log::filters; +namespace expr = boost::log::expressions; namespace attrs = boost::log::attributes; namespace keywords = boost::log::keywords; @@ -68,10 +67,10 @@ inline boost::shared_ptr< sink_t > init_log() { boost::shared_ptr< sink_t > sink(new sink_t(backend)); sink->set_formatter( - fmt::stream <<"[" << fmt::attr("Tag") <<"] " - << fmt::if_(flt::has_attr("ID")) [ - fmt::stream << "["<< fmt::attr< std::string >("ID")<<"] "] - << fmt::message() + expr::stream <<"[" << expr::attr("Tag") <<"] " + << expr::if_(expr::has_attr("ID")) [ + expr::stream << "["<< expr::attr< std::string >("ID")<<"] "] + << expr::smessage ); core->add_sink(sink); diff --git a/src/Mod/Assembly/App/opendcm/core/transformation.hpp b/src/Mod/Assembly/App/opendcm/core/transformation.hpp index 91b7057af113..26f17ded7646 100644 --- a/src/Mod/Assembly/App/opendcm/core/transformation.hpp +++ b/src/Mod/Assembly/App/opendcm/core/transformation.hpp @@ -267,23 +267,20 @@ class DiffTransform : public Transform { }; }; -}//detail -}//DCM - /*When you overload a binary operator as a member function of a class the overload is used * when the first operand is of the class type.For stream operators, the first operand * is the stream and not (usually) the custom class. */ -template -std::ostream& operator<<(std::ostream& os, const dcm::detail::Transform& t) { +template +std::basic_ostream& operator<<(std::basic_ostream& os, const dcm::detail::Transform& t) { os << "Rotation: " << t.rotation().coeffs().transpose() << std::endl << "Translation: " << t.translation().vector().transpose() < -std::ostream& operator<<(std::ostream& os, dcm::detail::DiffTransform& t) { +template +std::basic_ostream& operator<<(std::basic_ostream& os, dcm::detail::DiffTransform& t) { os << "Rotation: " << t.rotation().coeffs().transpose() << std::endl << "Translation: " << t.translation().vector().transpose() < { if(sspace == negative_directional) return result + sc_value; #ifdef USE_LOGGING - if(!boost::math::isfinite(res)) + if(!boost::math::isfinite(result)) BOOST_LOG(log) << "Unnormal residual detected: " << result; #endif return result; diff --git a/src/Mod/Assembly/App/opendcm/module3d/module.hpp b/src/Mod/Assembly/App/opendcm/module3d/module.hpp index bdd1e7cd5929..ba1642902c57 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/module.hpp @@ -140,6 +140,10 @@ struct Module3D { typedef typename mpl::push_front::type ExtTypeList; typedef typename boost::make_variant_over< ExtTypeList >::type Variant; +#ifdef USE_LOGGING + src::logger log; +#endif + struct cloner : boost::static_visitor { typedef typename boost::make_variant_over< ExtTypeList >::type Variant; @@ -314,9 +318,9 @@ struct Module3D { using inheriter_base::m_this; public: - using inheriter_base::createGeometry3D; - using inheriter_base::createConstraint3D; - + using inheriter_base::createGeometry3D; + using inheriter_base::createConstraint3D; + template Geom createGeometry3D(T geom, Identifier id); Geom createGeometry3D(Identifier id); diff --git a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp index 9a231abb84c0..1fc399fc6978 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/solver.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/solver.hpp @@ -52,6 +52,10 @@ struct MES : public Sys::Kernel::MappedEquationSystem { typedef typename Sys::Kernel::MappedEquationSystem Base; boost::shared_ptr m_cluster; + +#ifdef USE_LOGGING + src::logger log; +#endif MES(boost::shared_ptr cl, int par, int eqn); virtual void recalculate(); @@ -126,7 +130,9 @@ struct SystemSolver : public Job { template MES::MES(boost::shared_ptr cl, int par, int eqn) : Base(par, eqn), m_cluster(cl) { - +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("MES3D")); +#endif }; template @@ -160,6 +166,9 @@ void MES::recalculate() { template void MES::removeLocalGradientZeros() { +#ifdef USE_LOGGING + BOOST_LOG(log) << "remove local gradient zero"; +#endif //let the constraints treat the local zeros typedef typename Cluster::template object_iterator oiter; typedef typename boost::graph_traits::edge_iterator eiter; @@ -414,7 +423,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy bool done = false; if(!has_cycle) { #ifdef USE_LOGGING - BOOST_LOG(log)<< "non-cyclic system dedected" + BOOST_LOG(log)<< "non-cyclic system dedected"; #endif //cool, lets do uncylic. first all rotational constraints with rotational parameters mes.setAccess(rotation); @@ -447,7 +456,7 @@ void SystemSolver::solveCluster(boost::shared_ptr cluster, Sys& sy //not done already? try it the hard way! if(!done) { #ifdef USE_LOGGING - BOOST_LOG(log)<< "Full scale solver used" + BOOST_LOG(log)<< "Full scale solver used"; #endif Rescaler re(cluster, mes); re(); diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp index dc157c81d622..4517144e1e1c 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp @@ -265,6 +265,10 @@ struct ModuleShape3D { void recalc(boost::shared_ptr g); protected: +#ifdef USE_LOGGING + src::logger log; +#endif + typedef details::Geometry Base; typedef Object ObjBase; typedef typename mpl::push_front::type ExtTypeList; diff --git a/src/Mod/Assembly/CMakeLists.txt b/src/Mod/Assembly/CMakeLists.txt index ff46393ccd4f..0f3d8eecf3ba 100644 --- a/src/Mod/Assembly/CMakeLists.txt +++ b/src/Mod/Assembly/CMakeLists.txt @@ -1,4 +1,11 @@ +option(FREECAD_ASSEMBLY_SOLVER_LOGS "Generate extensive logs of the assembly solving process" OFF) + +if(FREECAD_ASSEMBLY_SOLVER_LOGS) + find_package(Boost COMPONENTS log REQUIRED) + add_definitions(-DUSE_LOGGING) +endif(FREECAD_ASSEMBLY_SOLVER_LOGS) + add_subdirectory(App) if(BUILD_GUI) add_subdirectory(Gui) From 0099bfd0fd78b58c3307e860a79f663aeae6aa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 06:00:04 +0200 Subject: [PATCH 231/664] fix failing angle constraint on bad starting position: treat LGZ before first error check --- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index 97b6a8021bab..f3d748cfc891 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -79,7 +79,7 @@ struct Dogleg { number_type tolg, tolx; Kernel* m_kernel; - Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20){ + Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20) { #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); @@ -182,6 +182,12 @@ struct Dogleg { << "residual: "<(); #endif + sys.removeLocalGradientZeros(); + +#ifdef USE_LOGGING + BOOST_LOG(log)<< "LGZ jacobi: "<(); +#endif number_type err = sys.Residual.norm(); @@ -232,9 +238,6 @@ struct Dogleg { number_type dF=0, dL=0; number_type rho; - if(iter==0) - sys.removeLocalGradientZeros(); - //get the update step calculateStep(g, sys.Jacobi, sys.Residual, h_dl, delta); @@ -535,7 +538,7 @@ struct Kernel : public PropertyOwner< mpl::vector > { bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { return ((p1+p2).squaredNorm() < getProperty()); } - + int solve(MappedEquationSystem& mes) { nothing n; return NonlinearSolver(this).solve(mes, n); @@ -545,7 +548,7 @@ struct Kernel : public PropertyOwner< mpl::vector > { int solve(MappedEquationSystem& mes, Functor& f) { return NonlinearSolver(this).solve(mes, f); }; - + typedef mpl::vector1 properties; }; From 932c4b5e11efe228cf822ef13406160dd54b53e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 17:07:24 +0200 Subject: [PATCH 232/664] fix perpendicular initial position issue and add better tooltips --- .../Assembly/App/opendcm/core/constraint.hpp | 12 +++-- src/Mod/Assembly/App/opendcm/core/kernel.hpp | 6 +-- .../Assembly/Gui/TaskAssemblyConstraints.ui | 53 ++++++++++++++++++- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index c9cc12259872..b4b857ff9c7b 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -632,12 +632,14 @@ template template< typename T > void Constraint::holder::LGZ::operator()(T& val) const { + typedef typename Sys::Kernel Kernel; + if(!val.enabled) return; //to treat local gradient zeros we calculate a approximate second derivative of the equations //only do that if neseccary: residual is not zero - if(val.m_residual(0) > 1e-7) { //TODO: use exact precission and scale value + if(!Kernel::isSame(val.m_residual(0),0, 1e-7)) { //TODO: use exact precission and scale value //rotations exist only in cluster if(first->getClusterMode() && !first->isClusterFixed()) { @@ -645,7 +647,7 @@ void Constraint::holder::LGZ::operat for(int i=0; i<3; i++) { //only treat if the gradient realy is zero - if(std::abs(val.m_diff_first_rot(i)) < 1e-7) { + if(Kernel::isSame(val.m_diff_first_rot(i), 0, 1e-7)) { //to get the approximated second derivative we need the slightly moved geometrie const typename Kernel::Vector p_old = first->m_parameter; @@ -658,7 +660,7 @@ void Constraint::holder::LGZ::operat first->m_parameter = p_old; //let's see if the initial LGZ was a real one - if(std::abs(res) > 1e-7) { + if(!Kernel::isSame(res, 0, 1e-7)) { //is a fake zero, let's correct it val.m_diff_first_rot(i) = res; @@ -672,7 +674,7 @@ void Constraint::holder::LGZ::operat for(int i=0; i<3; i++) { //only treat if the gradient realy is zero - if(std::abs(val.m_diff_second_rot(i)) < 1e-7) { + if(Kernel::isSame(val.m_diff_second_rot(i), 0, 1e-7)) { //to get the approximated second derivative we need the slightly moved geometrie const typename Kernel::Vector p_old = second->m_parameter; @@ -685,7 +687,7 @@ void Constraint::holder::LGZ::operat second->m_parameter = p_old; //let's see if the initial LGZ was a real one - if(std::abs(res) > 1e-7) { + if(!Kernel::isSame(res, 0, 1e-7)) { //is a fake zero, let's correct it val.m_diff_second_rot(i) = res; diff --git a/src/Mod/Assembly/App/opendcm/core/kernel.hpp b/src/Mod/Assembly/App/opendcm/core/kernel.hpp index f3d748cfc891..f6ecc59a9830 100644 --- a/src/Mod/Assembly/App/opendcm/core/kernel.hpp +++ b/src/Mod/Assembly/App/opendcm/core/kernel.hpp @@ -79,7 +79,7 @@ struct Dogleg { number_type tolg, tolx; Kernel* m_kernel; - Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20) { + Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20){ #ifdef USE_LOGGING log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); @@ -538,7 +538,7 @@ struct Kernel : public PropertyOwner< mpl::vector > { bool isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { return ((p1+p2).squaredNorm() < getProperty()); } - + int solve(MappedEquationSystem& mes) { nothing n; return NonlinearSolver(this).solve(mes, n); @@ -548,7 +548,7 @@ struct Kernel : public PropertyOwner< mpl::vector > { int solve(MappedEquationSystem& mes, Functor& f) { return NonlinearSolver(this).solve(mes, f); }; - + typedef mpl::vector1 properties; }; diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui index a4293a677ddf..45d69de56ead 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui @@ -18,6 +18,9 @@ + + <html><head/><body><p>The first geometry to which the constraint relates. Note that first and second geometry can be swapt. If you want to clear it, use the button to the right. If it is empty, just select any geometry in the 3D view and it will be added here.</p></body></html> + false @@ -31,6 +34,9 @@ + + <html><head/><body><p>Clear the first geometry</p></body></html> + ... @@ -49,6 +55,9 @@ + + <html><head/><body><p>The second geometry to which the constraint relates. Note that first and second geometry can be swapt. If you want to clear it, use the button to the right. If it is empty, just select any geometry in the 3D view and it will be added here.</p></body></html> + false @@ -62,6 +71,9 @@ + + <html><head/><body><p>Clear the second geometry</p></body></html> + ... @@ -105,6 +117,9 @@ 0 + + <html><head/><body><p>Setthe distance between first and second geometrie. Note that in many cases the shortes distance is used (e.g. line - line)</p></body></html> + Distance @@ -143,6 +158,9 @@ 0 + + <html><head/><body><p>Special constraint which is in general used to let the geometries be on each other. Therefore it's often the same as align, with the difference that it is also defined for points, as a point can lie on a plane. Note that this constraint has a special behaviour for cylinders. For example, a cylindrical surface can't be on a plane, only touch it. Therefore this is not valid. Furthermore point and line coincident with cylinders don't work on the cylinder surface, but on its center line. The reason for that it is, that this centerline would not be accessible with other constraints, but the surface coincident can be also achieved with the align constraint and value 0. At last specialty the cylinder cylinder constraint shall be mentioned: It works also on the cylinder centerlines and therefore makes them concentric. </p></body></html> + Coincident @@ -181,6 +199,9 @@ 0 + + <html><head/><body><p>Fixes the first geometry in its rotation and translation. Note that fix only works its the direct parrent assembly. If you stack assemblys, the parent assembly will not be fixed inside the other ones.</p></body></html> + Fix @@ -219,6 +240,9 @@ 0 + + <html><head/><body><p>Allows to set the orientation of the geometries normals in relation to each other. Possible values are parallel (means equal or opposite normals), equal normals, opposite normals or perpendicular ones. Note that for cylinders the base circles normal is used.</p></body></html> + Orientation @@ -257,6 +281,9 @@ 0 + + <html><head/><body><p>Adds a orientation and a distance constraint. Therefore this constraint is only valid where both of the individual constraints are, e.g. you can't align a point and a plane as point-plane orientation is invalid. Furthermore it can happen that this constraint is only valid for a certain orientation, e.g. plane - line has only a defined distance, when the orientation is perpendicular. The reason behind this is, that a non-perpendicular line would always cut the plane and therefore the shortest distance would always be 0. </p></body></html> + Align @@ -295,6 +322,9 @@ 0 + + <html><head/><body><p>Set the angle between the geometries normals</p></body></html> + Angle @@ -399,12 +429,15 @@ 0 + + 999999.000000000000000 + - + <html><head/><body><p>Use the full solution space. The nearest solution will be found.</p></body></html> ... @@ -441,6 +474,9 @@ 0 + + <html><head/><body><p>Positive solution space. Reduces the valid solutions to the positive domain, e.g. point over the plane at specified distance, not under. Or point outside a cylinder at specified distance, not inside.</p></body></html> + ... @@ -473,6 +509,9 @@ 0 + + <html><head/><body><p>Negative solution space. Reduces the valid solutions to the negative domain, e.g. point under the plane at specified distance, not over. Or point inside a cylinder at specified distance, not outside.</p></body></html> + ... @@ -527,6 +566,9 @@ 0 + + <html><head/><body><p>Makes the geometries normals parallel, that means they can point in the same or opposite direction. Note that for cylinders the base circles normal is used.</p></body></html> + Parallel @@ -562,6 +604,9 @@ 0 + + <html><head/><body><p>Makes the geometries normals point in the same direction. Note that for cylinders the base circles normal is used.</p></body></html> + Equal @@ -600,6 +645,9 @@ 0 + + <html><head/><body><p>Makes the geometries normals point in the opposite direction. Note that for cylinders the base cirles normal is used.</p></body></html> + Opposite @@ -635,6 +683,9 @@ 0 + + <html><head/><body><p>Makes the geometries normals perpendicular. Note that for cylinders the base cirles normal is used.</p></body></html> + false From dd1044a5e8750c0bb88e1e1cb890a9826d3d01f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 17:46:28 +0200 Subject: [PATCH 233/664] slightly better error reporting from app to gui --- src/Mod/Assembly/App/ItemAssembly.cpp | 34 +++++++++---------- src/Mod/Assembly/App/ItemAssembly.h | 3 ++ src/Mod/Assembly/Gui/ViewProvider.cpp | 2 +- src/Mod/Assembly/Gui/ViewProvider.h | 1 - src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 2 ++ src/Mod/Assembly/Gui/ViewProviderAssembly.h | 1 - 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 5ef714b337dd..6fcd123f3ccd 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -74,26 +74,24 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) { finish(boost::shared_ptr()); } - catch(dcm::solving_error& e) { - Base::Console().Error("Solver failed with error %i: %s\n", - *boost::get_error_info(e), - boost::get_error_info(e)->c_str()); + catch + (boost::exception& e) { + message.clear(); + message << "Solver exception " << *boost::get_error_info(e) + << "raised: " << boost::get_error_info(e)->c_str() << std::endl; + throw Base::Exception(message.str().c_str()); } - catch(dcm::creation_error& e) { - Base::Console().Error("Creation failed with error %i: %s\n", - *boost::get_error_info(e), - boost::get_error_info(e)->c_str()); + catch + (std::exception& e) { + message.clear(); + message << "Exception raised in assembly solver: " << e.what() << std::endl; + throw Base::Exception(message.str().c_str()); } - catch(boost::exception& e) { - Base::Console().Error("Solver exception raised: %i: %s\n", - *boost::get_error_info(e), - boost::get_error_info(e)->c_str()); - } - catch(std::exception& e) { - Base::Console().Error("Exception raised in assembly solver: %s\n", e.what()); - } - catch(...) { - Base::Console().Error("Unknown Exception raised in assembly solver during execution\n"); + catch + (...) { + message.clear(); + message << "Unknown Exception raised in assembly solver during execution" << std::endl; + throw Base::Exception(message.str().c_str()); }; this->touch(); return App::DocumentObject::StdReturn; diff --git a/src/Mod/Assembly/App/ItemAssembly.h b/src/Mod/Assembly/App/ItemAssembly.h index 37912d0fea72..d0b6e9f3f675 100644 --- a/src/Mod/Assembly/App/ItemAssembly.h +++ b/src/Mod/Assembly/App/ItemAssembly.h @@ -77,6 +77,9 @@ class AssemblyExport ItemAssembly : public Assembly::Item boost::shared_ptr m_solver; Base::Placement m_downstream_placement; + +private: + std::stringstream message; }; } //namespace Assembly diff --git a/src/Mod/Assembly/Gui/ViewProvider.cpp b/src/Mod/Assembly/Gui/ViewProvider.cpp index 5807f0493821..892c0ddea87d 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.cpp +++ b/src/Mod/Assembly/Gui/ViewProvider.cpp @@ -28,6 +28,7 @@ #endif #include "ViewProvider.h" +#include #include //#include @@ -54,4 +55,3 @@ bool ViewProviderItem::doubleClicked(void) return true; } - diff --git a/src/Mod/Assembly/Gui/ViewProvider.h b/src/Mod/Assembly/Gui/ViewProvider.h index 7cc1a3a7f9b7..d370ac55c447 100644 --- a/src/Mod/Assembly/Gui/ViewProvider.h +++ b/src/Mod/Assembly/Gui/ViewProvider.h @@ -45,7 +45,6 @@ class AssemblyGuiExport ViewProviderItem : public Gui::ViewProviderGeometryObjec // returns the root node where the children gets collected(3D) virtual SoGroup* getChildRoot(void) const {return pcChildren;} - virtual bool doubleClicked(void); private: /// group node for all children collected through claimChildren3D(), reused by all Assembly ViewProviders diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 301e569d6165..55d15ac5b661 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -25,11 +25,13 @@ #ifndef _PreComp_ # include +#include #endif #include "ViewProviderAssembly.h" #include #include +#include #include diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.h b/src/Mod/Assembly/Gui/ViewProviderAssembly.h index 1e30ef327a41..93462091bb30 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.h +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.h @@ -53,7 +53,6 @@ class AssemblyGuiExport ViewProviderItemAssembly : public AssemblyGui::ViewProvi virtual void setupContextMenu(QMenu* menu, QObject* receiver, const char* member); virtual bool setEdit(int ModNum); - }; From ad855d1cf56511ad75860652d3ede1550aea5455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 19:16:52 +0200 Subject: [PATCH 234/664] remove exeption on solver error --- src/Mod/Assembly/App/ItemAssembly.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index 6fcd123f3ccd..f73e531bb27a 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -79,19 +79,22 @@ App::DocumentObjectExecReturn* ItemAssembly::execute(void) { message.clear(); message << "Solver exception " << *boost::get_error_info(e) << "raised: " << boost::get_error_info(e)->c_str() << std::endl; - throw Base::Exception(message.str().c_str()); + //throw Base::Exception(message.str().c_str()); + Base::Console().Error(message.str().c_str()); } catch (std::exception& e) { message.clear(); message << "Exception raised in assembly solver: " << e.what() << std::endl; - throw Base::Exception(message.str().c_str()); + //throw Base::Exception(message.str().c_str()); + Base::Console().Error(message.str().c_str()); } catch (...) { message.clear(); message << "Unknown Exception raised in assembly solver during execution" << std::endl; - throw Base::Exception(message.str().c_str()); + //throw Base::Exception(message.str().c_str()); + Base::Console().Error(message.str().c_str()); }; this->touch(); return App::DocumentObject::StdReturn; From e9540eadccbb37056c7d534555c4cfe4e5467189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 19:22:24 +0200 Subject: [PATCH 235/664] let assembly part numbering use standart freecad sheme --- src/Mod/Assembly/AssemblyLib.py | 6 +++--- src/Mod/Assembly/Gui/Command.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mod/Assembly/AssemblyLib.py b/src/Mod/Assembly/AssemblyLib.py index b08eeb257f7d..fd05b7dcb7ee 100644 --- a/src/Mod/Assembly/AssemblyLib.py +++ b/src/Mod/Assembly/AssemblyLib.py @@ -66,11 +66,11 @@ def importAssembly(FileName,DestItem): for i in Part.read(FileName).Solids: - po = FreeCAD.activeDocument().addObject('Assembly::ItemPart','STP-Part_1') + po = FreeCAD.activeDocument().addObject('Assembly::ItemPart','STP-Part') DestItem.Items = DestItem.Items + [po] - bo = FreeCAD.activeDocument().addObject('PartDesign::Body','STP-Body_1') + bo = FreeCAD.activeDocument().addObject('PartDesign::Body','STP-Body') po.Model = bo - so = FreeCAD.activeDocument().addObject('PartDesign::Solid','STP-Solid_1') + so = FreeCAD.activeDocument().addObject('PartDesign::Solid','STP-Solid') bo.Model = so bo.Tip = so so.Shape = i diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index 29b255b89a0f..d711a7493fd8 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -137,7 +137,7 @@ void CmdAssemblyAddNewComponent::activated(int iMsg) } openCommand("Insert Component"); - std::string CompName = getUniqueObjectName("Product.0"); + std::string CompName = getUniqueObjectName("Product"); doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','%s')",CompName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); From bc8d2d2294ba0ce95991abebb19d4056f3d1a2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 24 Oct 2013 21:06:11 +0200 Subject: [PATCH 236/664] reduce solver calls and fix cylinder-cylinder coincident options --- src/Mod/Assembly/App/ItemAssembly.cpp | 1 + src/Mod/Assembly/App/opendcm/core/system.hpp | 3 +++ src/Mod/Assembly/Gui/CommandConstraints.cpp | 23 +++++++++++++------ .../Assembly/Gui/TaskAssemblyConstraints.cpp | 3 ++- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Mod/Assembly/App/ItemAssembly.cpp b/src/Mod/Assembly/App/ItemAssembly.cpp index f73e531bb27a..79067e1cde0e 100644 --- a/src/Mod/Assembly/App/ItemAssembly.cpp +++ b/src/Mod/Assembly/App/ItemAssembly.cpp @@ -57,6 +57,7 @@ short ItemAssembly::mustExecute() const { App::DocumentObjectExecReturn* ItemAssembly::execute(void) { + Base::Console().Message("Execute\n"); try { //create a solver and init all child assemblys with subsolvers diff --git a/src/Mod/Assembly/App/opendcm/core/system.hpp b/src/Mod/Assembly/App/opendcm/core/system.hpp index f3398a85cae5..c20cc27ee580 100644 --- a/src/Mod/Assembly/App/opendcm/core/system.hpp +++ b/src/Mod/Assembly/App/opendcm/core/system.hpp @@ -274,6 +274,9 @@ class System : public T1::template type< System >::inherit s->m_cluster = m_cluster->createCluster().first; s->m_storage = m_storage; s->m_cluster->template setProperty(details::subcluster); +#ifdef USE_LOGGING + stop_log(s->sink); +#endif return s; }; diff --git a/src/Mod/Assembly/Gui/CommandConstraints.cpp b/src/Mod/Assembly/Gui/CommandConstraints.cpp index 7f1541dd44fb..cba2be87457a 100644 --- a/src/Mod/Assembly/Gui/CommandConstraints.cpp +++ b/src/Mod/Assembly/Gui/CommandConstraints.cpp @@ -181,7 +181,7 @@ void CmdAssemblyConstraint::activated(int iMsg) doCommand(Doc, typestr2.str().c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); @@ -250,7 +250,7 @@ void CmdAssemblyConstraintDistance::activated(int iMsg) doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); @@ -313,10 +313,12 @@ void CmdAssemblyConstraintFix::activated(int iMsg) doCommand(Doc, "App.activeDocument().ActiveObject.First = %s", asSubLinkString(part.first, objs[0].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); + + Gui::Selection().clearCompleteSelection(); } @@ -380,11 +382,12 @@ void CmdAssemblyConstraintAngle::activated(int iMsg) doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); + Gui::Selection().clearCompleteSelection(); } @@ -448,10 +451,12 @@ void CmdAssemblyConstraintOrientation::activated(int iMsg) doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); + + Gui::Selection().clearCompleteSelection(); } /******************************************************************************************/ @@ -514,10 +519,12 @@ void CmdAssemblyConstraintCoincidence::activated(int iMsg) doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); + + Gui::Selection().clearCompleteSelection(); } /******************************************************************************************/ @@ -580,10 +587,12 @@ void CmdAssemblyConstraintAlignment::activated(int iMsg) doCommand(Doc, "App.activeDocument().ActiveObject.Second = %s", asSubLinkString(part2.first, objs[1].getSubNames()[0]).c_str()); doCommand(Doc, "App.activeDocument().%s.Constraints = App.activeDocument().%s.Constraints + [App.activeDocument().ActiveObject]", ConstGrp->getNameInDocument(), ConstGrp->getNameInDocument()); - updateActive(); + //updateActive(); doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", ConstrName.c_str()); commitCommand(); + + Gui::Selection().clearCompleteSelection(); } void CreateAssemblyConstraintCommands(void) diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp index 7e27153b00e3..e02feb512b73 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.cpp @@ -420,7 +420,8 @@ void TaskAssemblyConstraints::setPossibleOptions() { if(isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder) || isCombination(g1,g2, dcm::geometry::plane, dcm::geometry::plane) || - isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder)) { + isCombination(g1,g2, dcm::geometry::line, dcm::geometry::cylinder) || + isCombination(g1,g2, dcm::geometry::cylinder, dcm::geometry::cylinder)) { ui->parallel->setEnabled(true); ui->equal->setEnabled(true); ui->opposite->setEnabled(true); From ab4ca88fefd7253df29c6e2d7e334e5f8cdcb24e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Wed, 30 Oct 2013 17:30:03 +0100 Subject: [PATCH 237/664] placehoder text not supported in libpack qt version --- src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui index 45d69de56ead..df861e096d2c 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui @@ -27,9 +27,6 @@ true - - First constraint geometry - @@ -64,9 +61,6 @@ true - - Second constraint geometry - From 348f4c5476446dd5d414224b3210e09cf1b391a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Wed, 30 Oct 2013 20:48:47 +0100 Subject: [PATCH 238/664] make sure active assembly object extern variable is always the same type, as visual studio can't find it if derived classes are used --- src/Mod/Assembly/Gui/ViewProviderAssembly.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp index 55d15ac5b661..7dd53f5ef1b6 100644 --- a/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp +++ b/src/Mod/Assembly/Gui/ViewProviderAssembly.cpp @@ -37,7 +37,7 @@ using namespace AssemblyGui; -extern Assembly::ItemAssembly* ActiveAsmObject; +extern Assembly::Item* ActiveAsmObject; PROPERTY_SOURCE(AssemblyGui::ViewProviderItemAssembly,AssemblyGui::ViewProviderItem) From bd484ca7cafdbe5567e9b1d7e76aee0df2b9b2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Wed, 30 Oct 2013 21:11:55 +0100 Subject: [PATCH 239/664] suppress useless msvc warning --- src/Mod/Assembly/App/Solver.h | 8 ++++---- src/Mod/Assembly/CMakeLists.txt | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Mod/Assembly/App/Solver.h b/src/Mod/Assembly/App/Solver.h index 8867f5eee3c9..b330d714272f 100644 --- a/src/Mod/Assembly/App/Solver.h +++ b/src/Mod/Assembly/App/Solver.h @@ -23,6 +23,10 @@ #ifndef SOLVER_H #define SOLVER_H +#include "opendcm/core.hpp" +#include "opendcm/module3d.hpp" +#include "opendcm/modulepart.hpp" + #include #include @@ -30,10 +34,6 @@ #include #include -#include "opendcm/core.hpp" -#include "opendcm/module3d.hpp" -#include "opendcm/modulepart.hpp" - struct gp_pnt_accessor { template diff --git a/src/Mod/Assembly/CMakeLists.txt b/src/Mod/Assembly/CMakeLists.txt index 0f3d8eecf3ba..f4b5f8416021 100644 --- a/src/Mod/Assembly/CMakeLists.txt +++ b/src/Mod/Assembly/CMakeLists.txt @@ -6,6 +6,10 @@ if(FREECAD_ASSEMBLY_SOLVER_LOGS) add_definitions(-DUSE_LOGGING) endif(FREECAD_ASSEMBLY_SOLVER_LOGS) +if(MSVC) +add_definitions(/wd4503) +endif(MSVC) + add_subdirectory(App) if(BUILD_GUI) add_subdirectory(Gui) From 53189fd36f3d950273ae07b5341ea85e47c3ae05 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 31 Oct 2013 17:28:54 +0100 Subject: [PATCH 240/664] Cosmetic change in FemConstraint.cpp --- src/Mod/Fem/App/FemConstraint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Fem/App/FemConstraint.cpp b/src/Mod/Fem/App/FemConstraint.cpp index 6c4909f363b3..298f86488dca 100644 --- a/src/Mod/Fem/App/FemConstraint.cpp +++ b/src/Mod/Fem/App/FemConstraint.cpp @@ -298,7 +298,7 @@ const bool Constraint::getCylinder(double &radius, double &height, Base::Vector3 return false; App::DocumentObject* obj = Objects[0]; Part::Feature* feat = static_cast(obj); - Part::TopoShape toposhape = feat->Shape.getShape(); + const Part::TopoShape& toposhape = feat->Shape.getShape(); if (toposhape.isNull()) return false; TopoDS_Shape sh = toposhape.getSubShape(SubElements[0].c_str()); From 9851450174a0938a93a3fff548b8c305da5d2f8a Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 31 Oct 2013 17:29:26 +0100 Subject: [PATCH 241/664] Fixed bug in Body conversion code --- src/Mod/PartDesign/Gui/Workbench.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 4487571967a3..b4322061084d 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -272,9 +272,9 @@ void switchToDocument(const App::Document* doc) Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Angle = 0.0",Datum.c_str()); Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.addFeature(App.activeDocument().%s)", activeBody->getNameInDocument(), Datum.c_str()); - Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().%s.Support = (App.activeDocument().%s,['%s'])", sketch->getNameInDocument(), Datum.c_str(), side.c_str()); + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().recompute()"); // recompute the feature based on its references Gui::Selection().clearSelection(); if (oldTip != NULL) { From 9b0d55bed8793925c9c9454e98386bfc4e82ba3b Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Thu, 31 Oct 2013 17:45:43 +0100 Subject: [PATCH 242/664] Changes to test parts --- data/tests/PadTest.fcstd | Bin 43355 -> 52140 bytes data/tests/PocketTest.fcstd | Bin 43830 -> 50017 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/tests/PadTest.fcstd b/data/tests/PadTest.fcstd index 3fe36983efa5729ae3361301cd8c327a0ce8b464..62865209534d98b97652e94d0f288d5141679fb2 100644 GIT binary patch delta 29821 zcmY(~V{|4#*Dm1Lwr$(CZ9AFRPM+AdZBA?(6HaW~_L=v4&sk@E|8{k+TK%i5chz2sM`ey2=3oiF$YsOJ9B$i22VTNEBp=T z?9S(oH<&m>@0sZa_*ak_vaMta`Eu3?`>ZJe`5mTl=vsJ!m< z@B4fl@tNR{^T6J{at0avv{sER$_Rf_nOMkg_B!spv$-pj&6-hkx&ISRcedb}^f$0X z4gvj2NrOyXL#+~OkO}_>tSTk9`R9~D3Gmak_ZWC^*_U{A06FdLH+37^8?W(Q1u)lY zyPeC3(Y{)$F4SQvdL^x_OKfF)+E%?(9~eJ(vS=@`6X`A%T#7%;O-1# z*l?%$O%C-mZ66iR5Mvca9k8<_ z8=R*H6>1jObrId@S_HE&Ok(>ZMnOfiqHPSnmY*!F`E{mBxIE9;m>`>=GRrZ1>HLeX z@;!)hf-Fm^Oy19GYQ-ddoHK-Indv!~9;2bFOVQFb(ZgoLL}o=r&8^Bhxi0L`$s@wz z;M$c$u`7+E!F41hb^;Ds3B&r=Zvez9hi{(0WEmlL7%($jN#=TBHsLs==pjBq66L~L zp+s=A8<`0h3ZVgZ9w1EPIT+M^80a=46Pf_L9y3!iEj3Bi+)ub>W7AQHW4v=4m$rEr z-tZ>W#rAz)ca8Cy(|6!fQ21DKR-bVVN6_av`0B7|x5p-syTk~5*6T2m6abR)*IQUw z^{R`m1e3HOt8WvGbAsh-ze4ei+r%zl1Zpdf%mejN>6<(b{)Xn4*fUsfQqw*Ekozb4 zA{4UYG%63cxr9OIZ%qOGvp>p>nUzHY89hioqJsiJ?OF?VyGigo3x>mINj}b(h#!92 zG;@}RXOsHig7!k?Jj+hy)quf`OUjFGzvi9_#@CTfkZK=@XbwD73)O{1@UPp(SbR-? zcHk8-D_CQBVGt8N5R?MOU@!r)_yLu@6vd*{P z`Xz(_TFT^cZe1*1?=4{I8k!#^VfeJLEs~()9=Li7)tihca^7@-!uxO%vc~;?p503* zXK!QZDVjk`H2Hlwms~I`y->yPZC@fhvA*6K)#NPB4=s^xDrj_W^*1D%cAiN?)Hqq% zfo<6w;Kf7$AI@WBbwQ;eKnBl!%LpVbT2|sN)$gc!eU89dR01y^hyzA0tAw&lrq(r< zYo>VmzDl z6h@+Ru&sn0qb`qaZ3^$$(n1|sSxd+KYtjP`@bnm11@ESxFQ;Y{!(%)_A}bo0vMxM< znL>xYDepZnOF||2b+|^t-z8UKac7xH=r6h+Vmd8IGLC=G??kc`diB|^t%wSl+0d#c z0zLy7{e+<_>Fu8*h-6;Sussa3A8QL8g@a$x=pT8^l0fW4TZ6Dw5Kgogo2$`yFxe6b zh-cTX0{;_8e3F?EJFt$PWGK9DIwZ|0Fny1Xpx@G*3gvzM_OMX!g}d`T&=7JU#2Yhs z25of=898I}0f)PHW}AGfTwNRvN(U);z?SC$EEuf!>1f3KTnR0h!)=fL16O_U?`Aka zECT4wn$usR;}yAB7)*=(vsw2iruqO-UgCRI^jz4{wl+#T<+>D^H^!~qPF?BI zE>Fg+dnGYLhRBVlHf_BWoa;`Dzgl#}6`FZUO|7*#YK`ej5TSfh5Dr>hG@Beq5Ljg& zKL&@JUbTvBU9x~1Mc?3pX3um>P`jE}ujK`)=_1zTPTiT*BKZk{>6|H_qP-44ds^^A zmId{P@hPd^`JF3Ud~zPS)1d!F?|BzJ-S;X!V3$=xeXq5ME*?I&hp9ftvD-@z_4KE> z0S;C$$>-N+v}-t#Xf#`J5ou1oBCn6C!vq%#;t1!((ZbVkizyot(u_Eu$PgFYGw`)eU!}k_A}AeE!LzC zHjF88sYufH+1DY6Sp*A8Uh+D7=QEI?fgxcyrW%jO9QV2{R1s6sm+Hb|&70L9LL8!V zmbsRZhnzpR%(_`<4LV2O3%SwvAV`AzF`D}m!>wkC4tDln+bUv$4XXsem`M;aVt@Q% zbvtGs1n-m5i&95KZd=B+#_k!IY!VYmC}o+%*3`=+IebGzND=W7{^c^Bk&j2nPZSSZ zdz_ixbyVwvAfZS1hm0-P+)$)gB>Kyw;f!7$QW%ZF-TUpn5X-UN5=aSCjcC-*+UJ{#4m}PSLjC|wsflBAW13Y)y{m^RNiY-$)%3QJaHVHqC6e z0((C8!X(^$V|#DlobAatnt5P^`1T#VVT5{F4l`AnbX4;=4F&=1#K!Sy94UWxN+|j# zGuZ#lBupEyGq>!GY12R52D3MXXH7vGnPl)&5kyA=V$t=A7r=L><=UzijjxYgyCWKB z;Cd`(=`8LPH5939yE_|lxuWoUe?o5U5NBqT5{VGxvH%+;yBj*{z&{*ICox z!Gj%qX%=X?mA8US?3SfilB|8rB+Aj56p4Zx48z!oL@h>d%c-WRJ-TPd+@hu1Mc@v? zsuuAJ#Q8srLBGs9;mpjUcHhz8z#H|JTv>gZMejS=#D)VLz9vW@x_(jEWeLm2R{gmusNcuA)3H7URyiQ!KtM zY!~dnoWkQjUMbx+Mjf6>U9=hVpj1D)1q4J7Y<)DlAzA2+uJyI-9oMrIegv3{M3wmt z?@#iLc4`B7LMCK%!gII~kyO#?JD*9bq9#Mqr}zxtxo5Y=_4bJ*udv9Hg(t!T#;o&e z2;2rRpZ5A|lLW}p97!P3RYpYGK=m^#){RQ4mE1)|+LV(qEKDMDC@K=LC%Ga7G=_k@ z34Zj7vF~@UjnKBy)7y31jDCSni5tmm=lYkYQ`Z5O7Y`6N-!F=HXv!}_>&b(D0_9Qq zFv#aMDo$2)G_7%6&C$(Usd>5)-)qD|%Clsuv84T$er2;xwdc&$vQEAB_(~L%&M_oB z1f45eHT+wgVPNbL;azbAD5F@G3`M}tS}F?0kpXXFfvXgjeT*mn))Z2IZUx=?=IKxq zN(MmCbSTNi`|wt0u(>6}%S4ZSSs^XUc^@#*3rTR;b&?mb6iz2aF%4P$$g$%d$D1OJ zaFKWN$lne()~W^E7`IT1RO4D{**}ujipp;IJ3eCfe>hgWd>zR=vbaG3GhV0b%1k23+Qd%Nq?ym*Kx+rK#7ou{T*$*T!29q+Z1 zJo0)@X?T05?NBcwU#~W=Juli8OZEuN@cj(CN>$S zc@~bue6pwi45DMvSB{#n_q+o52KxS7HvMEjUGM(<@BKkjJM0Ju*nf5kO@RmmaR04} zaZ=#_Tk%r)0ROk@q+WseZzU;pRp$ie@iEgkTEJ9Z=3?fbSDPx$@$2XV*u^ZG1b;QM%p@a-sEmX~iyG5xeW z?x$NV96*U*!U(|g@SGcP3O^$=IG>tw#eeU>?((l0^|t@0H$1;f^23t9E$!qp*Iin1 zvd!+qes8U-sw(ay*3SBp%fB}&q5W1d+%T>g`(=O9d!A*n)3GblO2axu%qa`-WRrDx zTF}cbJMSz!KQ60Ze|KA)hVwF3jN_eEWQF(!B3%-H9|T-*++9lK7Z{i04`I68R!gpgr{B)BD!ZG~I>AtU z>BJP2N$}dks+xwQ?A0D6(j`RA}i0dy5;xT(+MjDLPKgE}kEt z9u-uBE$1j~41{xJTu1L3jikI$odkO{3)@+$RS}TH$~(NqJy-aeF^}65|rJXdg9+>5aO1rSqn%4nNB}tCJ>zZW%agGYW$qHa-n~=d*KR z;aD3<+VJ!2LlCg_`5Z3GAJj+HxpY+8wfw|~s9J2S9LU2gYO2#*F(5xzZPVFXmDP(s z)&QuJoZufScgm;&_TrlHgM_s9vImLd^f9olQ`cP@`ipqLH^Z(&tq(f6MGXFTE6-R1 zRi!7Zy7$*P%xSJ+X?$=HaKTm!PE{-ZMQi>?<=)UK1eJ%M{C>giJ-YhuF!cLvrlqgp zzYvAzam(jUSG2jymoit;o_l^&=QgvG98UnX;s_4)#YV{6yX(oSHkU2VrBwtwexMg* zwAOM--emjf{>Rmfu8;emd)1d*3{#Lidpw}V;E(1NY~Na;fWo@>Dv!(G(27>CS8B7O z>_7m-E^A)h=eKpv>8KwGq~c7TR;3JLU)gqT%4U-`xaxx2UWf9y7V8Ud>#lj?zFNTD z8L{rwOeFEedDMIR8*s|Sv_XsMMoUqajwc|X`Ke`a5a`q^gI7w#Y7w3{2maIpKx%}y z#O1yurHHNs#k~eqV4__RSs2PfBzcEmC+0;cR`TQ))Tyf_j~M0l2h42Rg3@}BgUhYl zhmHQjvcjLu2y#uqj}xW=my>QD8V2y;Z%Ub&yE~=!x&@_DLS!T}%(#90N#B@_8S)UA zt{~&dZg_GkiN=i8LkR31PVe@sUP_Ut2l32tq&aJC$m#Ul{#sWu8YQ}`O}^t!vUV9) zgSSoT{Neh1Ruk)sONi4k-6G&DBOemI_4IAZXj-O?~MUOsMK4c$^(B4y7WH@A0rzyy2gQw#JSpO?n$K;;%QL zphY7 zqU@r1|MgVD0CU4MH+fqMv`NdG3T4}m?&sEcU~MqKCm5eS=(gC}j)2W)IySZ}L&4Fc z(}SIb?Pe=5ve{NOJ5sCH(vEab^T71ZQ8JPl{Q6Y#sTD?8r&|fJb-b5*6|wotjOV?O zuCr(rH0wUdl?mXfvF}YseUKuN{=4O*9SDQHu$^t+!~Lp~vA61FR#Cq-H_dLK{B84I z=`58`fNih#3dfA&@7QBWq|{B5$d)W6a-JZuK^-*Qsu$tD?Xcx$s$eWOHVHG|1;>Ft zYYAzJF-l>oS@x^li+XbUSu0m`HyeScHg~FO>!QI+?ggOE$FC6=@~rw0;RC$Hu15mO zOWn;&u7%~L!rp62%g3^*07E*t;Kw@DT=Ol5bTG%sHC~Nj_#jjSa=NZYCm9P%XsNRE zJnTJzF4El~@3OMX3g@#@uwHuqck_l$Y)hLfh@hm3qs|^ZpYmQ!8;hRTkAN$h89qbu zbaT~RH5BlErC|4Fca&Y)^;NNiZJAky90M!rej2@o&)*n{lz!_I7<#iSVJ zAFO182yb1bM{VF5}F%l4!LKPKJ-6Mv2Tx#m7_I8atJ{_I1dVAW8>TMBsOq|n+ghfOR`5<1(Hhip}48S2%0J3*B*xw4#{XK6$I+|=EEVb0XgA^(nl~ zhZu4xU@=@$_j#}}Ns-opPUk6IAwOzV9iE^vxd${9^q?N1tm>0tLv1d#6e_(^mAHUx ziAs+=vEr>{VcP*-l#BCDQi;F6o7lY&6OfNF%Qn~!29f7jHEgz!v=OlA>P5sgCZ+1U zJ(pwBWu!%;*yTJqAd?*4r&)uX5o10VcBONj?Bz%qu!>Y`2AK4^62C93^K?Zd`45SW zq)KgYw9SXPZ{5#~m#EefN<=*&%`pL_4Ui9@WZA_8wjMeeeA_f~T4^zwxSrB8^^bGc zH9eY|u^_WuL-)<4WXwgHoFQ&l1a-z)!qa^59eHUC z&xUhn<|oHUi{s5MWlpo`kDa~fQgj_RGET#HG6cj7ks4>|zj;HW^&QPJ?}GvNhv=VN z7*vdv{Y*G=M`=#Gl43K8(LBY@yHd+nWgU66QkrXcE*nIVL!>N|Fv>;Y`y2&lx})B6 zuUhvnt1uLz&UiI0w!7~rGqQgptF=6>5 zOWV|Dkl%|5 zD>}_6dfsSNd+W)&L0`#Y8&n9Jv$jN)`%HR`kQF^yl!H?tFErj_eo8Y8XYGGG_c(4U zqm8wRL{y3^$3${sD#*pU4iWIe^YB#v@))QWL2Tk@mf~$2n{hPbMx+An0$k0>P`nFi zcG+X3{Grlg&K``n<}LQ1;1ZDh2I&xILt5WUnS-dCi)7H6jC1tCm) zWTd&o(@?M|QGDQy#c%Cg;f*)az47Oc^3@tbU=&SQU^FC;{H}ZIjL@-FfhKlWftlDf zQax~Ac=c7Spd5e^-7^C``B-TN>k{#T!8z&j_U7Q)a+Csy)MFim4+en}#!e|g=@!-p z*rjSwC15er+)ryjTRnM2zPIBzscDKi{|YxNUMN;FphXPE{?4=xN2G(SE?hHMZ)s*+ zr$%Db0Xy-uzgktl#iUTMVd8HlEqBI~c*f0xnVO_)erhxCZ3czbzQHFE(M^9l3DD0! znz8J7(7p!vrtxlcmy*xWpu>wx*R|aS6KVWTmxHF}d@epVc7`K)3$Uh{2SpTqKJ_`BJ@vDanT%b8or%RF~b1T4?$g5^B$^DCX(h>O9T#&Uk+PS6OzYMh$A^R8ZUjF$8~j?mjV#WNDh91i=c zX%GlIiRtZN@$jvm#cHA(Dl8)g)#~t@CVADOI>Y4&NLw z8ST0tbUaQ0!kA5U!F`-7kKma@op*4oVgj>K95Z1W*1Mpc_Q>Mmm4UtI!BT~B7CMNl zu5l%UMOVjX=;SVk7KLzVd*If@G#4=#2Mdb{<3Eb?0$r!J!Vde#O-kwxe^S&@K?A>+ z2~8O9w=BI|+Nj{rw`$FY{NC%-L3tuzBBYIwvi&nEXBU}<=H=dhSi-ZV`zO(}sCqB5 zNW^H1_0_QW;}R{kX5k#$AfBccJo6R<{o^b3S#`4hsQ1(SmCyfCQ+m&3KQUs7o>r;v z$}UEApP5yM!HYuPH#iov#OZt!YH*bg`UE1`(^vlFCQd{+%YnAo*`|1$>JALB$(Iu@ zj>kg=LZ(V&f3#*5`C!>4!21*kcIemhGU_r1S*}%w%`HDnEe%96BTN_&q+50U~ZQ))}UUg-gaVX7zJlQ&Y3aF)Eg<5(@;0CQ%)?HvK~ZhAtFNGL59nfrk1gw4IO8gQ?PiQU2x!8ylNDpY=w z!T3f`nyNlVwX0zaC?-%=lt?`*pw(=*`%g@S92x?#Cok6PGA&<&ykNML)FXz5w$kNf zp?t{BMuc0?cxe>&8W1AT&-2~J&)3%2%{n7D59jB1{m$31UD@ntjqmel0MzHb!{xPz`Vls zmPwb|S{p>j>G+CzFfh2PIMd$U|F>$6JfzLC}l z`ItD~)~6U2br2Kaj%7XguyV~cq0|w}r6ZLtTKGh-q4aGD=|pXR)KL#pZa%SaYwi=~ z6_JykbzzilhjkHarX3}Ep|+xkcPR%nBWLVd3?lwj!e%A@;iHLHnJ$aHL^;_JJwN0a zv|rw_nlbk3ut!Z}vgnm9iCnIjCeoDCFT3thvx_?V6GREv8(#`8SGf{$L-2rAu0w7Nb$=4B z{?XQ_u135F6~T?$PA0i2=TbF^;ZO*TnpEzIX?|s^!;BNTJL%T9>PMqgMG+&WKu2xC z26ooNJT?PJ;-pH@PoHg-JvJ?2u$-peHK)!^nOY1#Rc;OJjmT^N4diY`8-xu#c8>&K zV&^KR+9CE2Vn~q9&@G}2UADjfdipalgCKY@?>i+z{{;LSX2Gva7D1lai@oI~IsW{C9gb61CGV*mZ9=&37*b*Th0m5$(8==jQCj zzUR~g<~C^}Nb4`+M+de0?8tYm;rH{IN$>^W6nLwm3>TFinXv!zefU&yb?@B{E4Tgc zBI{zi7C9SuMmjtl77%ok7F`<4XSWN%DlS(QLtG#^fC-ikm<}>+3IN2>1omyvXW%cP ze11>)CX=&x1Sq35Qa^B=v25M2U#z8X=SvfS$@{Qv(@~xRS(>;BdKT=xlW#MpY_|Zo z)gE4Mgtxv8s$vwCUkUmHNiSb*iO9~gIoKwa9rR25j+W85Rxd*0CF@5?Okd~Q#|F=y z_8aIi7ylcq=$HjtIz)9$nz~7Qeq}gG*JaUQl4tGM7NMoztn=;0hc3x4(*oOty?p?N zO5Ch3SMe2Me+jG%ZRpJ}<+Gdy(;*AcJzvU~)vSHz;B-Ch(rtBHX`4xcMoV5>p}wpJ z^xN7RPB^Vz(FQmmn=Ihu5%)i50KLew_#7`S!nP3slfCPrrEN7wF2MbXIn~V5h=9}W zYZV7`8p?ay$uYudrQ2dA6?iZ83xrA!BD#qzRvwI7+bKzd0uX=M(v6_cfl4G97;>JL=y&nY4bd4ONyrZ^8<*TG&Eza0KWEP)>kVg=&S z*`(+%bIWa&107zPc~F}8@fRUt)ihRgfCZJ+kCjgTHTw-xqb}1< zc{R`|11(fm%LM`F#Ju-k|1PdIR2v1CsgDy5Vl}gWOKl8|+Fb~LA|VE_8tOn?cyqQo zPy&({+Q&O^Jich2yhA{)P1+Sb;nsN~P! zq5hfUdDxSOa2Sl#OG&;zyOI4-V8eUw+XJdG3M;p5*BsOq*POKF3J#MB{WCfn9pNa} z4-89+UUZFB83{wQ_aOzKoe6S|avB(M;2qMY=PXrDaHQR-Qk8hzMFN7pQvK4Kal^YG?aW>802o$gVjZV1+K>vB)_)D_Vg(9&V%+jua!8aV{Qoz-P zFeMatsNsGJFWAgrD1UGLk`?;h2 zys{IJS#83O-ml_JA`twqw5hX&8~N=NoZ;JKYMa{)J`*3nopMHP77KTlv&U)azz)vm z$-2l;)|AtMrvX=mtpP`0x5JqD1dnWR3|jNFs%p{xXhRk?Zq&eL#Fn>(QvD^K$ZOzV z@?t%+7nfL$Qo;EZv2m)z=RGrc7Q{$}A#b}Uo$GD1y%Ro-Xk_EV2ne^Pt|v}TJn*ng z9OTA1dGR#>Z+Z~BO*aOssMp#|x4QzAj+l`(^MjED1Hog@xL*K#L&g_%MsBclg7FC` z?5(jVPR8wCzn+H?ixya!MxR_4CqIJnq%wTXVh2{@^8{_F@6D&^y*UA@% zQn$wMO{zR5DXMcNV82M7<~82unIemkKsb|s`Yi(BEAu%?n8$9N?c8er)8Xb45?O&c z?b;lfA5>n~wnI?<+(e{G|3Uz}z*7~zhbDG00?^2i$YQhn3GJ*|Z}n`Z7qAU;#b zF+2MLWnS{AE-GFqFk+qAQ54yg^jEgdburzwJMoS6dvJX<4|^!(-&hHFwt$-|KMXM2 zr#bZsgGCPkA+lwtRN|k)mC;bgTG)%=&KCjbgGjTb(qCi<8624!U-J~7b@PWm=9bP2ea`@= z7Cd)MMC;V{Q6P|=Rm?XH;hdc_o36AFh|tMlAjNf}6ARPx?JF7~RK-0G+w3SWZnv3x z@15hi$SbFgbSo5yFW9|5mt>Q4pPOcM0cm;th!zxh(-dJr7pSsz#x!ilO4HDf7>}!b^XS$W$!yncfwxT*}uDiCd( zk$jqdZKJrf8T2fh5bAQtKFXkc_8y<`T}u(`$Vrk z)_I^7teOS6WlAA>p)ct{)S_2uxC%>Ua7}J|SYhjkBp@80F?c}z1C)`@rt{-;Y$W$8 zMtt`J|G2DWU|e}Kr)C(vkVE;KgDw@yVAmGCE-r^3?j+(kH^ zp?J7eS`FCNpxX9_(uPbf?dJpyY^hiL$Q-MKiJL0?~DUqq;hrt=uJPQzEk|G)A{kh&HATx|3p=XAF~t zP^*w&d4SV*>R7AOZJrGT@aaU^shAmvdUE^dPH-73DzbBGdse+%kpw9-Tm`FiV&dS& zzg&cb9ii6YX+bLxpuo{-pDU!17n?z`g)>q9asVXss4U>v$PTAD54cjFT)zc!f$BuE zemm^bg~tj^6;RWB{aG>gGV*qps9Vgpo6kjxEv>rQ&*;)hxPu}8!Zs*1o)vK+Pt4xV z5tDxT;{hxb?P3wc&Ba33Fxi8HLF&~|u^MfuoJlIS-a8!6f7h-0m-9$RJ0LIHQQjz& z4;}z}#rM!pmh3GDhN`-4BsVHv~_9$t)Lj)m<(F%ZF)P3B!5D&->b44Yg#C*pYqMuf5>Eds=4N3}>6X$yn zX%4z(NoS&K*ZgxsKBmoLIY6EL7pd^p?e^88_nN`*GrF(3C7!H^x7BbL145;_1Ey+U zF(nvi4<{!^!hYgg=3Tb);f)Ir(OGnG^geL;etJ*Ney83 z@^=@`%M09k+~mQo@?RBDta947ObBGfpl^<;xzQ%GFJf-HW3kI%!+y|a!MucISE4qe>@Mw(1!l+n7{3Y|-cAd^SZ|8s)JGxt(#BtglwAbBH(Vq(#(dKi`D^JHN$4 zw}^K0@4t?TrV49>{}@8VLjR9?*ipP%FS8F)P%G2>Ug zfR=%djXH>HNPxp`ks`KqC@7*x{d2DE4MGNJjqPFIRyHFH28NHJq2i;&x)tQkTlVJ4KrG$Dd)W0lL&kgW&l)|84g%Ph!lEqvUIM#e* ztMm_U9j)b+SS`00FHJ@8QOl{?W@ZPh>_OnzK>TSblSJCbqi-bN+9~Cu8gUk3;f|CN z?$r>%D||8~Bv7uf3)Zj*Rc1!gX>P!9BMo{Cu?x{TR}$6%kJ+>Knz+z_kfOSd9YoaKY~KjjEEXcQg5~!EU7o~h9stwB&|A#;u{?JW9b?C;j?|)`a3(9*V}+zd2v9)-jCr40!+R&?4zGLf2RdVo-9%m&aK6FqMCE4HK)JIB7hw)aL=B1}i*ur^tz; z6lJ(Ghm{l+$M;)HW0$g()vG*ctM(^;l_@Bin3gqDRA+j(ish~}w6<%C6{l6ymNhi! zUGnK>>0Oui787DoYUK2j%s6I1xI7Z&pvb${Z(Fvq>BTiYy_pToEHjao)7~(_WVwP(OmiLIOPtnc7j zT2<92b93S|XnLiZl^7ly5f7i*KfK!?lzmf%s0>Y4C5bc0OO61*B(TUZ1fr4afnqzF z<4QTz71uCmv?7^SXOJgT3K_BagF&_I{8}(z18l~8CW*l;V0ummdC0sI+5*{t6As@j`;q`BlAYCBT+)OrBAmX|!QX#YSLO%Ww zSwA*}-do%7H^sC*lmh>!Dgkz(o~d&uXW^OfSwCn%DumPUtz=K{xZnMkR5}*%}b7v(Et>e<8T0PNC=Wz*_zN19#>d zf?-8;vXm7hB*m3&)=FM+go=tbdfpKQgy2jKJ*!LS%V%>3Qm>*rvH|`I;|WQOdYgI_ zHJWtf=m6nQ>{Tlt^>uJ&_53J4goiWh>aFu*aNg?wLxN?#Kx8>(gywqMkW!QIy04a% z_(z+r@c>08QK4Fog3@bcwp_w-V_J&%U@82dG>$Lje9#&YV7;d=7&Q<37Ig%v&%kIE zYY-H$`_uQozfYC&Vy_SXGQu=Xr0z^8fOIku_>in|H=@PBN1!-p)k9_~wXRl~|2PrY zf1GF>m6XVRTFJ+%4BKQPCamqCHsZ+Pd`kyXBw^uz3<&&uCJZFnMkJPFe$erh$t12|9_a2kMn8au=6$c1PrYv_v zvY`mYj?Nt7|16BL?DisEMljNr%HMIwN7+h4%;p25!#?utS0BG}R9!adE-|~E8zi)9 zpG=M_1La z_#Y?Y`mYn=5+svZ0kqKBs`^dxzYm5y0AI&LFIVY!xwzloFE@aPp|+depX1q`(BRMN z^7`-3p`Y%LEGE5TQ%O2F$Q235!)DfuC>l+3*fpo84j;R1^6jRe|_F38M#)zj>`j)xdoRD zk&Ifj7CPVpribU0GkL0JAZOrqNh1srYMhyY2s56jGaF(#J4M0`iWll+iXNJj?hkV9efG~3J?;$1Bygv6a=`b0);dzl(JeXRC29x`Iyy4Pzb*VtgoHTOTq4X>4 zV`66mYkTU4Y^G(}iAJ>W<;pr0NCA`ItiW8Xq4TjYXirTG1?X2d`c7sBJkx~qCkzsZ zL(ox#Cnlx@2YsRC1zi_H-09SsBnpJ|RhHa=>CHD-OUm}?{IX%eV_1nEa^<9bRCOq$Y1MLL7~l@?TeT>Bs+qk!#wvEc zJ4eI0uJ`<<)W-MU1{F)>@14pT%hVFQQ=IEk^2xELE@=CcYWH@HqvNFW+YLb|J z+Hc9i4t*10C-@nvDvyZ#0@y>8V}>m=-L8q3sqExjeE+}2Z()&Gp`f)3F$hzLB(S`I zPxWWBTEp%C$3^Y7Va4N0j(g^#Lz{Yl8FRI?Mt`%k6V`RuuM~y);FQ{#gx^Wcc6e$w zc~%t0RH*;nK1{Q4K-h`S+m~HHSg2}=6yEy~DA|BBqSGa*O6?K#+JA6FhHJUGfbu_L^!KQe z>*kEG$ly{1_BrMqYU!ZR@)l4obGbS)xE18TLjrmZj-`$=PS zcgzZ-k{(Y+>m-#9kUMce{|81s{{^GA%~Syx`~QHEqAc)I1K^(+dF;H$Z4{wuH)Uy{ zJYT`jRiP?sN948se8#aGaC*SfgD-xXG|4ma9NU&;h1a;wZ13)()AZ6$xd!D9<+-Ym zqhDUf)7s~DGEb|1u`?ZrL%vDja7TD$jYWA?^>2}olqjz%O7g?Bzl>dTtG0UKLO>3?8E z7vP}$4~*>H)5vOlpyz0u@Pgzt^Rhw z5xZgd53_iNI2?3ajQ`_C#(inl|J(?msyyhwW_dpeihs>Ca5_sgGhc{GWWMxlL9lG8 zz`u2aanZCzUv<8?C4+`HJ1E_>hj1BF*p44s7P(g1K6rPl4eLPvnsXgPzc(Jz5>jo| zD7#n0+BoDTD>*kDW{`pJp=OX#5peL11W93B1q>BX=m#Sgw3PSd24#6>-NXX;D<@7n zWOAZ88VH1?L^)rSY*bC0USgo|*_q?Gc`{uATX(@qOMbl%Z=%Q2 z9>B;{JvDQsj~!KG_p*>6hrdnc$?Nq?yqMd7k6ZKVF@oQKTMcdqtY|6OJDDgg{5~%5 zpu4AKL_{xi1SVfQvH!vgi9QVwJitVq6|OTS`7-mCi;Asojco07MPh29IW_>4gEmjD zjCg;8M?-(P*00UHr5qhh>}s!ykctP_4_%RWvCiFG&6x9pq|8PwHU@S zJ4WeKhm9Q{+5=`-mvq#Aye+WrCq7PRKU+7G=eb+k%zDj;fv*)arS#>%6ZXQ&5@&Bn z6;i9A2@%LPIm*%RlycWwoQ2X3t?I_w2?@s|DU$rIXbea=^l=4 zV`AHOGSS47OzeqmCmnmDj&0kvZQHgpNxnR<9(=#MRQw^csG6qjRSjh2M@M!&G|$MiIkD;W?(?%xtyGSGIOxLZaxCK_A;w1 zw?;p6LvsWZBK~72SkHyu+7`qdXz=evJ8I~d#68by=HlasP&E>(-dSk4?R6c34`ZYR zoNkJ?XAn%^y4eFD-Sl&YrI zGcb}(EMkWLa&4GgwZIkD-e}2U!OENJ^L;`wkTN$UyEBtrp?VnZr*(g*d%^t|+4O99 zr2j=W<$RG%yWRS(fd6Kj0FoWN75c_T6ejVCUiWFgReqY=5Ov?&JSPs!UZ8GbPL zG+>J0MDvu`f55;O8c()l9?1zxIU!zxk1OYo*$h@stX%%twM$1!chCH;=jMuS2fFlk zy(90d6@4VF7v+{@StHm2rD7)XpZ0{@nE;HY?5p{aaVM$goFS^m=m4#zamoxoM{Nrd zglxO=T_y`7m>^7YIg>l7O!7VboL}u^BDl_l3BgmnhIzElwgqChhcz|S9)rmd!{fJ+Z_!eNssV-L zF#r~Ei)Vsz<3Vq&)((dz3nJ48l)<+@hlS$hz&x#HtL&p>uhM+<+#jRy z$gt26uLUMZIGNWHX|$zv3LG`za1+kOuRWW26n1qO(AGYtCH;qqAh!tAa5WJ#J9Je_ zP!PWzb_jWpZ)+(@XZ9ogFIxlNGqb9T;uztfp~DuzD#uASH6z?Dw;j-U!u$omV(WlC zAx4Z*45EO=zHyU0PY{=pq1U` zZz@2Z1bpT^3@PT^zv|e_%N(RN@O=il$@4RhA|kxA0Jz2iio|y;b;Zla`(kd%i;&}+ z*Y8QdzywK{5wt_P1e?JV;9LSPv_**LJF03I5F?QW)Eg+6C;&BIF)!u-1(PU2&49*9e1OT$3vdGMosTAn zteDkUa8tRQaAV!!QK4;Gv3UF^q$aIZsA_iK-*o6gOYWai0~dD}9^mPWHzI0#4EQ+f zp$B}z_hysFQWau1-W7?^*S-zn5J<8zTs=^FYBt!BW&!bfOq2Hp*%@?OhE}VPfVQo{ z=cC(qJcwPpT}1oGDwNt7TG%`TkTaRW(2#~PZ}tJ=(q;qY2s}6e7MnnT;0f2u zila#hl1QWkk`){$U(%FsrIIW>hEuvxnK6BWLdht#Y_wOFLTGdJHzzW;yta#>kG(y; zq=y|cHeTm!WOK$J_*N;wdQVYANaqP)M{*kIEl?vR1@b5wFct)SN)aVFA<%k&yJ~iK ze0<^@<*HnRZo!mJ;&d3ztzup8;g@TR0BWZG0!T;=?lP7HN0c~?nTE{Chx|lp9^&Cs z$co+o4{ipip8En*B+PW7e$OQP(&Lx-O(@BEu<}~{#J|bD(SRDbDA5jbHI0VUy@Fz#l zbsS4GcD7Ig^tg&_)mKrLs$^Tzn4dE2KM}W6a{2TZ^k` z@-DcRO0EUrxk*m?TWE=fCynGWw`~!32(a$W4@Yl}cWceICU<)Q+1tAj%|vs?$?JqoP7*#tb7q$V_b4Pb+jkx}8H?geA8%bzh^8sd79B_<*fn1_p0c-@|}pys_) z*K}*XF_XMG=Nm50SOP!j&+%tp2-lAU$*?v+iZ2h=QEsWEvn8fYwek}i^+Vm^Ae}&F zDFg1Xjv4FQoMQjLA^Ee@Qhet1F&H@s>J0O zHlE6s2s{`P!MLH+(p?ImCzEc2J0_HP^dmwq8YyHhS-aNvMtjwK4D-)G>gg*sdp>CB zt15QfPrY6wHe*-y=skBmdjF=aF(G^2fw^h5b(zn&46Pq5{WJJB ze(~Qa#$3fEe}igy=m9e57*N&Ny`*=Sv`6b*X&+W}9qFfTQW^SUO;kj0@!)%DkQ|Ph zY_ti{qf@CZh20z!cADj&XJ^)f&)ge-H{;=1o$o|7vT$NZ_GdvQS8cKgwn_F>s z9bpODWkEEsvqu;@ZA2hd+%@=SfK=EGmboD#3Jm*{fCfWKOa}l}e$;7rqRKlz!h2L$ zF&43R$#532ZI!&`FQ1C9a4{>{B^i~tJ?KGShT8~&f#+z{D z*0VI{;`J?a^8T2?d1pzZ3Yo;uG;bP_R!)~dO=;Pf&S+t4Az6oZ{+Rd{YD!s`^=aq# z8_Y&os`D?&(RV<-%QMPC@*_oZ_H0qt&z}nNtGOlGR2sPv#k z1G+eq%8I7|FjOf|a|&uRcTG4lkR)X+JulKUI5H`&)?OG42@w6aJKwHenA;nrAXMr| z;mw?%I6d}IxFq3x8SCWKeg?@7QGx!jy0>KE+dtvP)-eI^Zt(PX+Xnu#O5OPUF`Fxe zZ*r)@nCnbf>q${M@!KsjT3`#}Ptnx;)=m6#4aA)EDN#xWP96gFxjB@W>6^jW;kV5{ zy6&=*wMET5x)2~RAC#1`@}}T)B%J|jN*f5vS_QCW?-h?vGgnu}i%s=og}JRMXo^Z3 z6aBVYiwgki9xfFnoo=6Bhfjmn_~v1XDO9Y8M zCSea?BKjUF#7^+PzUSxNkYBSJ`f<)~5vsF=8u@-#M+Xh30Su}7Ih{p;%N{$Y2Mz;B)hNQ!*NbBfV zX7Mwvd12lo&`gVTraB?*eQy7Q12rER=0+w30U;s<`sNY>2s9zpRphWc+vuy|>FGDB zhi4h6Vf-B;QBzW#9ymz;B#j42dK^{v?lVSl<-ru7zPt@tmDm|&Rx>7Z1tEU_ zs|QhV8_Nm?0Qow+F$;Gin_Qk33I*Im%dG-v#1XOx;?$BxBpS40kumGG&ptMH5}hT! zg;()pOKn89HbMz$K@3C?B`ht15e=J}C4xN9DMlM-g*A9QoxnUOnGTfF$ zVGvYk>yIH)t{1MZ>tsVrW_eeO3vmxUyu*AEv42wUu0X4Jny!x)s!bZi5U3eCXNs8_ z8%Y>aau~GWAzVy@BYE4Me|+e4ev;7U!{hXJ9#1SD^Kbr>5C$4sf4JKAfOv$jt*yzI z-qRljK#7seQdcZGeX)_o?(@P&ulovGd6rOz%=3|8)2nSJ1Z-UBObv|aupsyoNt`~Q zeG?ejgQ$L2TbmlCEzCT4Xsp{?d%9skq6TqtRe0cGh?(`CK7EacbUzmPbUQy~s!A!d z1cnxSs)1JOprwML@y8hwGK-hVFnc^K`L#d*IJXif#&=3aGec=JLs4m;&M$pdx!9dL zFbs@|!H~Gh#noQkOLrMwpV{ne9|e6Y8dA*^E_d+&iC90rj{TVBl_=%0WqAC3Yqyvl zG7#zs_XVnCt-u)(Dxp4N8^E_*7sF0v?zhOa)8C>!JoLj zzri#IGu)8kd0czxIIGcEbdWVbB-oulzaJF#e}dLAI5=Ssr_np@tB9Wa?+Ym){CxdJ zrwZ$k4-_gMA^T-7@W z`7}N72}>QWFA=0RTvG)kHxeGaK5LEb#T?QyC_OLN${7X?(LT0}w9+v$@H`n17dl^$ z!*k!A$K&aEM-*^o&?=>YGfwHO$2*(0`ERb)&evmi>a^OGIWkOt;@FvAyDB+>_Ysco zhj74|O_g)DrQ@Vq+VNmC&UWwv;ME0K@$o)9Y^ij}NleNnOSwo4zxpp!qM%bAw;KL6 zl>LCE7@itFzo+L*gH?ZmVClK!KX8CmT`HH*swfce#sy!?I0)AwEsl$Tw6MROgl@43 z(ShPy?>CY&fojrk4p#5#I~xfA(`ms98T6G&>G$&ydgEwG4~V+!-bx_?G>mafoC!Z5 zsv=g}ZY^TW6QVvzbQ5u;)#u}2d7o-r>W{B#ueqYv+kJeKbKl5;XdE?H_$6^#P_SEf zRDp=}QwCzA_@R+tbKHidoP%i}Z27qyoHt{s3O7TS>t~atFSz5XkZ)tKN@ui5dUnNw zIc4xS6?^Yj*H>X6lfc8g|%Pz7h|h{Iw$H_y5G^yPGW!d?tYd^Zk33BGlRL^ z=?x6=|Ff_CI1dHYZ^_&`YCRWajUkncxTxrfEN6cY?D9n7Ej1au{|dE)^LbmJKRm6->Nf3t;O&WG zP(h}yuA}TD{Gdk@FfZyt^?1;U=x%nQ{`u}Ly7I>1oFevk;4i2GiE!O_+{miuEvZ8p zHIuEK;9IvAK+Yb9|DCxZIBa*Pi{N;uSG{hjKTCJ}zyU(RYeYdh>=DsV{(MRZovMRB zV2cQa#o19y(3*tkc#>FQVnQIfTxZEU%sIOnz^_|OJx8k#K-+4i*|xVes5s7?1N*dl ztx?rX?ETONhfkt3s;dB7Oo|!Ob#yVsu-$XuEXpnkftt#;blr8(N0_D4L2C0|Ueo(X zBpCg;PXXU|Hj{@rRf7;sr9}HfHxHD8 zifYN@0*L+-0J1z%3k&IX*=AJFs!!YzzfdF9&WyBG0ARjkXVp;1=cKV%;4<81)R+YgugU*Ga1IkPGfL zgol?rHgMeM(_pabkzr^@>6p6%y_J}ro~s@F7OR~bfE03y>t6|y`&|5ZUy98+mv5PG zUe9OF?^l93)e9yez8MInvS|86u&_n}l2Z4T>!ZbyQFt-TmgSmP-*aXMTrN7cwlx&) zri2+6Vf5ai({#>q6@(ny)vBq3Zc~{=<9_)fsv~Brdtsg^%pBuGuy0AXsz(@oo+<1A zc%8eN0DIbwqNfK7xT1!#wcW_yaHKY{Wkj1|BlmZ3Rp5He4|}4e(b3U)2M2|8Y@^-~ z$%C=27;iSaqJI?`LW9PZ9x@U{LXh`=6PMW!86-GJRHP8^&dLTb=%kvPX4G5>|R=&ffa00RF&0_ zom?khg3YGH;5r5ecVkf2r02RJvZ3(D;pO9tc1ePP7bO#Fv=~Js=P_=X-p|hu1VHY! zeA0aNYLxZSV&mGajbE`wo?NZ8epRw`Yc6@9|MqKi4h#PVi0xeOEMfDy3&f6uz?0^E zfyg9!Cjg)Jdr~PSO5S)IFwl@8HZTdkGA|*xvkd8%`89NKn`WwuB59$er=B*p+1laBrE8ymd0UPQ1os8mb#7$jrmC9u;23jno2oX@- z3-S$IBBGw((cts-fljoVVV7%d&jfOzN@uE4hs%tCwx?{&LL(UjiDR>KO{h&U$MHkY z%Vb;yb}CxgZI}>2sa;LN;hXglWR28e3~N8?w!auUxGgOzGP1($;Uy5{6rjtu`-b#O zn>P5_KL;iE0L|_oHXH|A{`@N;x?3jb+um?eM(rd~My6w<2FJuHMJqZ6px9+BGW~{f z^HEMAM=sU39Kwn&WE*G76yg9v*R9!4neCV*xhVV0@az2KocM?Y5!#jzGP#zX_C_2{ z@d%k6z~UWEPU2NwuITla0$?}96ajA}j7-J{i!@V>oLX$v3#MG59fYUij_$sg(J_O} zAYE@&=}?yk9qNoImKqu>GcPZa$>uZ75cB!!YK_A90Y6!!UATKu@%r2jU)vX|5!tzy z(Gts8uw-^eAriR>IQaYPQgDO>1v5FO544kci8%<^x%cKZpj;mU0cd!3P@66oQv+$b zpM1`8M;H8Q0Q2Q@DLr-dP#xFFpzwSa@|Q zV)K1!kL%WpjGx1=OCHdrw#>3wai&r_v&2T}mXC)A7I&05f^x{q<952hH{Q=Q8n;ePE|8deL&4?fu%6$YfnLwuurRFk#(!nn(AO0~ z`n!VVT?*VXa`fYB&PNr?KyUbA2tgO*#ojk%sOKPQbw;(AmrMy z#tb;)%YW*XgW@guAYjfL&NjJu|o1Y!Bdb$ZT63#K?YgRqW5cyq?96Yy>~D+NUOhv zu&dOnX>r$PIS~<_NMYItmToL~76t8GuB59;-J@!b<%%^nt0(8*If|m6pBxKW^PHTB z1!x39+&5?J7ECOu^XkiGRmH${b(L}gl<_d3ID!%q0OSJ$1MB|&KU7t%$X1Yj>cQ1W zDWhcTbFmfcq1kUlSjV=!?Y6h%3f&47lBp=R$}d;7HmY!lv~;!?)C+>E1}{2Aj2v6z z-0-_T6{tdG$tj*Hsn@Y*~O1J_{>za`fug+BL2fddPO)=bNG=_N}t8hVu zWWcIw&|Q!r-wj-$jH&xG#)_6r%Yzx`^5t!ukPII*i3x9(Kw4{acnyk@E{Td#Sd{@z zDCzBKZ@A#mmHYUsG<IY;)eM{5uSl8@oz1=IgUFbM+Y$g( zUBRwFGJQOzh>2rHzKOL_KSA%thfn)eG@vek(DwB%$v+_8UMm8WGsrLQ4#W@+k4Qm1 z8~dkll^i5;m)OFJ{mY)0v6Hp(%=_`-to;d4&Di)LY2R?L^{5Z(l2!Y|M35biS z1%gM0euITt9@+_@uwBF3?9R#!f>P$#nFTc+HzNPM^zw?m4)pl*@hq1^CM+^O#6z4N5>s0Pih)fG88l5-Pmc(+GgK1kf~r@$W1^gGu7gR z95p|SUGzzfx=d~Ih{2DMyoyQrq3y0Sb@;UR@R-?@zVv;*3{b~eT3r$9(168q=ROs8C2A=@H`l6{jvh^uM>dfhy!?Ig~~lA10t zSump5^036~U0d*eLkKRq_>ugjv+ z0z-r>r9QJUk_#*I05ksHSim&QY?>P9J{nRwP}R+h3+n=t)&QVfQ)YpNifBv~tpLqS*0RbhEm=VYZfs4$yCJ1Sk_WDFz z%u{ZjQ^UF!g7MPU2s%0D57K%zLoLxjt={mXr!r1FHHN*p99PzJ7f|W_aHh&L2}T?` z7D1rz6ctZr6V)aU3$3*f24~j>`q7cJ0sNipV9DRH4Z=<#)(Z8TVYSwulod00{Y(^__d>CKv_1)BXfh>HQX9bBwIlagk%sczPkEz5X_aT26aNtY>x zSnls~4^u>5wlTNM@M+MP zg3tWi6%~N=IKRa0&i8w+Ue{GwV7C6No8gtH_;{C!H~9ed%6^4($HWOTMnhU0+X zL)$%Erw<}8=`x5j_L^qDq51#VnY4l zk2&;UcVPwbM~)aRNb%3))?vT{m(s?phu^*ZwaY|%(}NPpw#t^NjzTAEo0>AHHweP# z*YztKN(uY&vt^249ydv0L)u`jZ$6Zi)`5e)Mo_a{UoDym7O%P)h=rYIrMnqgQGnt2 zW%cGY4+4s?)B}FJ;t62#@8ttSH?gNz*_|a}mHw?+-=|TcGjw1=?f#&FIefnTNG8Wf zh{rZsKhfKe(pN(`@|knKAa~eWX?)uI8#sY90+{;}WuV)sI59lh=9C7>e)Xqy611bd zEM8F4f&r`+pa31Zdl}v7SB~fTtOJb`!A^SH{-PUoR27F^L-Q#2lwy`>j-a%SXGT6! zgqh%%+}g_0Ed>gzG2A1Mfn&vl^52F0`n!WR2|edv0KYdfW3$(w`}bARSe_8gGI#Zra^4 zyi`gTU_;!s?glo5jh8ayMr80Dr80=4jVq`yzf2SYr?J-kNzk%5B@J`)8nNySdBCBo zYz_z&l{PTDXcxZt$x=ln(0LrWv(h!Us4|Y6durt~Z@r&URUyvnnsgdUO($sp9XB{P z6$RntgD462=5d__uXNBBH46jOCgs(M96q^rHs7-HLI0fDSip7Ybdbp|PBvNm#*co# zJw==ZxszPw+gNkcz9&P=5UDEVfFL(_O%EVc4g=J^Wh};XM2&k>eWR;Ej~cFGB0mn* zuJ`;QD#|q#cT{&Lw{gF#sV$%dCi*xW&^*Jv5Y;)7oJw&;I5D#LQ`GWZI%0`8sk&35 zDp#A?tXuore5z-SYw!KFA5rH+S3z=(CT6QI(O(r6m5xSNp~0TmtfxZ@D-SZ0d|E(3 zYz1;J^-f|?&mdxvo$BsND?f;L(weyIhN9TnDJc}^!4d+9Kp^ad|InaNF+~5of-;3q zmV>xBHgh7qObJ?FR3RaC6tY)B|GlhsrFPJVrF>4)fii)9>qhQ?51> zK*f;$(e;{lEHk_XTe!uD7}h}1@(E~81fSGMVI#rvMcl5?4A`tZg_<-d-H zu6=E*Z~Q?H6<_7)e&m`Zg|UICRsv0(mA2#UCeU%lxgs$PZS&D>F!v%IG}WbGhU+Pk z==fmo^n_3JXCH1j_2PE=srw0;--!{KrcbHHDyrucBQ$zj1-`)g9@!d5V15Qg{#oFkfmtfRbu@B1q)O$ zmDvFoEX#g9!Gzxmazx@N%ytsw#Ts@EvQe;ImpX-;hbT;hTk4`#NSjnq1ymP;73+A|5YcOOxN8uC|j9HL)=+7qaw?d&!w5djn8{fegS%=jd_38@f#h zQ(R-{$qYIU^PVtDtDD}bqCy}Fz1X)W=)ejZ|z+>I6L>hi-SU&#RPrSUFU8&-w$s@tE z>dHP%Y|Txsl!l5S##I2+RGj2K_Z6CvVHhD&d)eB*hg{LSG;}+sq62w;EO#f`4;n{ml5YT8rER`5--~D#I(h2H z6Dls)=zGdTj2NU({ez~D6G9XYY!6m^BjqTjh|usC%+cb0KcnAirh7hATZ<#<8QKcB z4uf3Cth0nJ;@FybTRzt@0%3Ap7A>?2xASwKha3~=b>H0uRuP?6%$v8xX49gGLRoC{ z)rp5^qd*F9e(C`_9-iVMyFqN1e6A@3sTAWx-oSf zf~k6zS@>vYrPVDgQ4KjUo~TT44E2mcl8==^kZ&D>S)Kz%_AdF*;1O6KO~BiJYO$^W zY{3lg=zlwkCld3do_{>pQQ(i73|S@~A>L^ zKi2>7iKb_%OE7okN)o^!5hjtwv8N$Quxfevl_wC)@#>4EpsDm||8fddn$6iJ22wOLkmZ1Wx{=C&V5`KWsTRXs?J~JUlon&^EuiatIfN}iBzP=^8Ut7#OXl}Md@Sz`s%Rtp(g}? zBf|_Re0W3O@x)b~Tx1gVB-J3?zYX2HSeoY2nWx#(AfnQSev&}5w6p|LEBQ}w?nWgW zQ|Hv|=mm$~QnNGVV4T+3fdD5`nYX=mA5bw49XXRcSn$5HaU)i)ZY*K469>MIlvjh4 z9W1qUB6%Q3FXJzH&2eOs5kJa*w4?;8v-1ONhscEr2`CGftuH_Z`;I0d1n8)`#;a<>XaD!K2`h8&@Fsm*2syGckUL;pQa6(1_qzfD=}1{NSR)e~>3uzUYAr`2eo}JJUD5+r?p) zv5M&*DQ1qto>Z4P3w zb<#6Iohjc$pRtY4S_QU7yU`nC$p&+!s4|)PScYuUxzC89roS8?tE^u=k7m$A{F3EY zvqP4lcM{jmVFJ<6@oFsURL&vNr#e_r-MAa=eWbmx6f>p}52NJJy)Ij2(Y5{qK#@V) z@e-WawjlAkWvOL`|B41+@(oUoiohtp#(cdoW+Ni8n0TFKm_@;+1#d%6YrtPFE->ue zzDR!Duiqw+}x)JOVVvXuwf{-;ZJC9)kbaT)( zVn$&!ZC}6y&JG4Xy=*cE`|^Lrki}-F(NC~<;CDfV-0(4Y_=P&RZCYq_HL4vtd>NC*&=S`sH{<%~cPi$vu{N zs%}&=Q$Q6rzw^~`mvmJ0Cw4T5`(4tI`2MSih_uRis!%HDwYSJ74>aEA%+o7yK*vM1Y_lI?#nrcTu~&`fw%hp&0l2?n9qkVrPj zd5h`q1i$yQ3UoK30qmja5hMC4BAhphoK<$rUs`({<+c#oh;)!6)Vjw;WvyVhB<$y% zW}*(P;yQgteL zz++c+8Ao>c&6jPqmsaK$1Ar8iUfJoB1-TD$sr6Czavi{#B<};)Z}1k@!7UZ%WqHh` zy4Kyzt95H`AiZ{h*qIHty0{p?+GS8t-XCK)!>7Q;knsBF>4&d5>%C*yktn{Eta$&G ztn}tMy@ywQ;b03_E*-D?16KTx=cDS7-e;Q2KZR^~GOmlO(c zCzttue|!V7I>$~1Bf*J(mD^J%++04Msn2piU!A?;I6bu9WpQ4fdcaBa~Um2J;X#eR8M+?+1 z`1arH`4-@T9stt{2#Ef%-v5cg)cvQAIdG|fKlg?L~@*1*WZZ~ukq|GFOFgMc9a+a6p2hYAV*YoGqFK(+oq z$NX~n7fdWH|1VJgOjZ3)XJ?>D5#fJ<_-A$!2nf!RZ|Ka-W2Yh{wjB(rjT zzEhJ9vbFdJpeO?ZiV6e-1PQbh-7d@vV>TZE0|bQP00ad4pR=M4CT@0S_OA4vcD6To zdM?>rkDdR}aQmNkGflD)w)SNgS>!fdxs!9sq`d8yIQ}>bUj;xomUH$0)FpsI27buf zwtEdBOKvLM)VZe)_xtnHmJ*C3;Lh=Rm&P1xAUo3m=G?cti#4tsnOODzy?mY=5DXv4 zTr5kRAJ6Dq)LPUMB;fo|fk8^W8Fg@D#$(KLwaEIQdfMy>!_4)IkYI!&^GYG)#gmSO zjzO@5WQrFrOdTMOnu$nhtnzs?{uaVu$$~G2-tByxifog{quwa1ouXU_+~wZ)gIp|Y z6?JF;uzLJI4iWpbhy+{}33EMdIC!xsQMQrZc%|z;0^-0ac0s}n2}9#)-apJ+xj736 z1oT7s1qu9K4->u<{4=K5dN?p8f@3$T!9?n1-x|{k{Y=Bg`EMN@3ubgOif#{o!)-6N zeN$BBlusd|{0V82sA;NH!HhEE03d3Y^4xuZH~jhc>|vvS+rpcwM4GwT&~)mVpEA9o z)7&V^@6~VwAm@ZyFysw*UCqf^SPzP?zTBoIJ_E@KEWuAnYLN+YxzL@1H*H;=nR)vF zi7kn`P@$%AbLkdt7osaAp1d2tj z0vr%497)jy7XtkZ|95n-*<2W(P$M@KFTV%=Ja~YL1%VB_#*?8zNm{N#U|kxzH{(A2ObA( z#yiCTlg$|@D!SLjG?Xy+VzfwK<^`VJsJ>(`(SaZSG$qtkRdFDD!VghcDsPesV7=`r zSkf!89EKsnUpH{q^`>}GF|-}9p|I-ZclR!3@Eq+X#&e~k*>a)Hn4OeMe;J;RXPXmM z9oa!HtOIKUj*NJOodD#AMS4%<6_W^=^vieL|^);dS!=tK0WK-P8mPn|y^35K@~2$2*%A?vOHIq8kJV zxe#P>Nwtp)G9+-)i8kG8Icn6GyqH_KUxBr8;&LG!$Z#evsO*{XWh^3Tts4MWW+ot! z+G5Ra6{sIqB6+O=z}3y_Z)1>=4Hy&N3P`mZmPM8t3gcL@81y3ck-SGdaS~V1Z7C3?)MqkeUCD{Zx# zY32&Z36psu=GxYMQBy7NDBw&uwU%IIYV`Vj5N-kQF%+Pwzft$;<#v-hG@8X=M2fCm z@?;{WATyynIG=WzLkO+0#tZ0`hVIxCvY-^LM6~5|^0mRrCUbI|4s&Gr5ate~WP5aq z&e%yWf6-uAGSiauq_Sk!tpkS98W^h!tm5-&o?WIhW&Z*AVemhG>t4yWmc#JtPI7n zjxaWH$y!rD0}Gf|-^-c>ucwxO+se45qHKT}eFn6|@p5pK*^F!B_-I#mwYN2vFTI@O zv~&g0GS1l}Z5BZiI?yIT z8kWJ;q{S#@){9k-^(+##mlv(A=@nyS#An{qBFeT<1sc!5&47~z+c4!tm~!w)H2ES; z!2p_~iPa~VD&!fw;iUAG7pi5Ug++v|vFsxp#w5ROaN*F0uQ;g6S$<>d%^ZN99(*M3 zDELt0YuWJo4of32ueB4eSD%SIL9FZrtixPI0D4?STaHiB^!1h2(mw8kaE2KW?9M5P zb4tFnNv7W;*J;kl%zRWhWKw@+09hfokAN?)-wMa)6uoq>aJd5X1}|2jMX8$NOWYrr z49p=ifm#rfX716SR**H`6{zed)S2~&l~k`Nx2wwpj$6FHEKlfoxy~cN&bQOm2ay`h z4Z)P@W^K=7BgBFq7QMM3E3t}^Zt|SRl(=-#@9+AO)kZ=RGm58Gb#icM)JT%^OaQCJ zqo*(4r9V;N%I$fBc2&N0wAZ&G=ojU;ZwuK_CIb~y#&Yw+Sp@pHiEXiZA~3OCv*t3lST#1)ZB zZ{HAoRKZ^T4lgwQOoV>bqiwsP8qg#1+k_g>Vhg=C-ELmPv)j~@yEP{(Fets&F{u-4-a=piUw4!xW$*LArlakq3&@=Eun~AFx@+*l&*Z}Z8%+O;v zJ9^>l%YBSXlw9s0kVtfGQ;Ch)EK#GE9b;e%3#v;~ZnKVUCR)g=y=j;~3P}3vNVKTZ zq8yrt$5rGEydq_~xRg}UyWd5-Ha6vs`V{!vMVF+J-s1ERqa~4{cY|n(5Wi zdE;*L+vFB?;;xkkM(d-P{R)WsRvGMTjA1LRc6C+@Q?ti2H-?(_U)72!+GJ*S%xBaN z!T&v4l(tXgTs0tvu3#PlD*pV2+fV;U&0MAbLj2zYd^0-i$RE)Ej`GcW@c6L*TLI&w z!2NHPN$CUpzZE9+8uTH2Qz{>Uci`*`1367c(;2^V;rLMZq5w$7JdP{8^1 zvcCPvbxr7V1oRK{;BDVA=KhuO@z$DM>TrKzoSoUO`}h7L!;>F{Pz=?_T3&8k{mMJ% zx8}aI-Y&NU`^-TmlRWoa2`k=p$Z*q{f9kHk>W`OQc=b37rqQGpswH2l^*QX*{H)Hf z(|MI;l#yk0Gg{_gz%etFK=FF)e|BOuI6X}c59pfd=Ck$b+N)Nu;BMdHY_2st zGL)GVZa=fXOe=**7p%^tyF>Xl0u<-x&BFJTh0?q4=AW5mhNU8{S=kmszGNI4Kdc&Q^&(R|78EV;l40QOfAQV@<@xV7*gLwJSG@P< z((luF0iaSd>$#jAk?yCDY1(`JIcYF;Qh()uX1mS?&}D`@^UpkZF=?ltVHULF3foI3 zXJCndGp~19t2yeyH0zTRCt{3Yq^DVmV$PwA!8{bJqLr(xtaS<9z2?EGT-^UN+k5BW zW;_rT7QKDnHz3ET1kC z19aM1Oz;htdueAud2!Ys0YO}P+5d^-kkG%LmD_7sVwQj6uBX$c(gT^CAp%>T$um-i zQSQ~sZoJwAKhHHNjSmh2E*S32%<9YE^4A?JJsLg-r)=&+cT#lxh@oB|g7$LI-gGju zPF7?qZguZ_PL;QDD}5E~xo1bc@iH~*2Dn=(iFTJ=ZGgPLJDRV2wc>S~-s<^?_mdb^mTdEX2GQrU``IbSzI(VxHnD%C4D z|MP?7zJkzpedTqXf%ZE?DBcchTgWK#p61vrWI1Awr7m=Ew9Wuxv(kREh|nzJ570Xr z7J1#w1rceR!Fq9e1ED-i?Y%tnKNn-Gz5jt4~bZ$Zt9BC3nQ9&>hj61~JjQHe_klcFuU7P zd9x^7IhS4CpJ(*^1iCYz*9BE(LTt`83~H`kK9T#I+kA=zGSqR;J10nl5(a`7vs zR@E_Bgm_a0+SUi^lqz!%EgQ4Hm|w_sh(Jgq9WBnbe*8z*ZH-HMmca29^3guC-0G}4 z=#a6lFTZ-hwlgHwC2n+`jhPCC_;*Du0C$X_{7IK}Teuvown!)3>ZaT+MMT(yKnZd3 zn-Kq-9!AcBA1}u%6YDs54Iiq_Zu( z*D*$1GAX*wE2iR;LqrPWlP*B|nIPVOF7ncu#{NRjB3TyI>S&9h#Gyg@Z@HfDR)AHA zlwY={>SdQ%QaK3+5gd~oPMh=+QCnTF4aH_Vxn07fm)-Q?Elx03lk@+TZtS-^YcjFQ70$j70<7D zcp&Z454RzUsJ)k;jlP4pmhjtPmc-i%=9Mnb&!>x}h&-zjo+S{VZ@CpgTUq0AUE1wl zBYNgIYMy1jeVDPZ4p7W}&gSXh$>Y&Iuc*lo>iB-&qvN?wYwXP#eIlg@cDQ4Xlk>P# zY0)>G(doW02Ah~>n3u`bjYD`*#;%^4*i~eLRy3k=Xqm`+uxqj+&hps}he$oomOVuQ z686uz*dCUT2nr$4_1wW4cC*giTo~qVOiTeAZ<*r?z>Q=>2i%V?G|8nc7;GKM192S1 z)Pr({;?v=$zzOY$Wor7{?Ps-~ITOvi6FbJWe$&>h1wcGLan@_Ka~uv)#CWY|R)&nC z!K@8E{b7KkT+e<()#_})sIe90+3LpOqo-tKJMj0d(6vbjZX0JK!pY%<>6=G)gALDn zF5P9#+Hcll1jwfWS7+ay{OzGgB)zons1XePV|7-xWeMMhYR>77g|+#_=w=hGk@DN+ zWQDs}E)kZE#xD{RMxc8K28miPO*%uIl)zoGz$})qo(8ip_+=MvL{AlSt|><3ojh1} z_;GGHJ+y9mJ;@5!PAitF6}LhL+ILwnRqCSE+KI0-3UDmB z5c!fs6XI!-y;?YIf%#e|(kgRO*}10`;ojf~$|tFIqq|eZuW(%1#OUq*$?1r0lEoN5 z-`RMR1^|EA%H4e2n&go2_$ZNI>eOkdYJiRuKzzXZ$~Vp%1L9#FJCb>Q+MDY)pA@B_ z!%W7H@YYd$j)U~?wQXlSW<=T_HYBudmbWX1T)-oF(YNGkhbTXgVBxb7F)KTZLVYlt zH7PqS0D9t6d8!L8Fcs*Nm?K-k)gwoX5Gz*H2K?QM9SSa{f-5{XsjsF*s5&*}w-pem zv%b}I6A{3I?$R#nhbzlJ*8VxdemXc%j@1&%Kn87RJ(V3B8=oatVg;ABr=Xb2qH}bu znU2)TTKflD==j0f}B?V&l_exuKKkVV1H*Gkb?fsPIx$Tck09;-`2-6`H6?NM1-zT1eDkNwkS>&idtgQhB`L*2%l(zK<^jwo#L@Iw9JzB*Th4XA6}7 zMe3I7y5Kz`k=hJR2sSxuf6M&VHZ*o37J{m>wvz%Ax=#(n#;pPA%xh-iNIpB&p z?ruR}p12WIi1b)jQhR7N;!;4VL_Jn10JzYY=ev~_M7p5?x8x73l=WaIBt$&&E1olq zR$;nY`_SVPc3a`uf?w^-x=gk4@R>JEf`0vN5E;c}XC0SyUu#GhYL3bhZM*R;+b*PN zH!LJI92HW2)iq3^RfUcHtLRbt2O%XMi^codV~0c^WT z_dbzg-{ip>!|Wz%uC;+M6~*P+P51=FF!nRN=WI7EZ<{HD5UGPpn@3CKPqHtpqApna| z>#a>tlgtLT%OGUSPlS=;4e?NR12Q7{G6)Daa9<3&mxhlY)QyIkOnWv5Wu*N}!`;so zeO$tDHyg{rL-bNrBvmu66Poe23YhmQ?t5@(6?CMLNxa=8G{X-Lu*lhAT`xDDRHAZDbB~!ET)!sClB#k5-q-;GaC&3@2CuZE6=94wO z6;8H`cozy#1_z-CP^8AP0ioIp&qq+RHP@k;xF%-e1FPC%_4_cU#IVx&`1|hr0&rfn z5;TLQ5{1}xd{Ff30#YrxhXY5G;7Qc*!(=`Io7HYaJ+hwlg%ZmUC)Y`FGPOANPl;Wa zX<)>pY+2s4ea$OWkgh!?bn;8})JE|_o%Ol&l} z!~w~kyd=ca?=9yX%;i@+;ud-dHKz5+BVC6R5-rr6ay$u`jz&SOLxGauy_!9W*`6HC zQO8C$67=d@uXsJ7fYik*!AM6_P|P6pCS@qhd!=U~aH2gA;^dstMRJm83_ewPE+*gX zaIbHvRTVlSDhBJZJQVrNiW(!|q+Lz)hkub-c&|!BIkhP!E%_e=&e^#|2BcmbNh=eO z;}FPWo4P{=0Z0OSE9nL0v5j!OhSpgqQH z`56+dk01xol>zF8(Dk!`81y@22@#}AvZ+BjwM$@VpE-h(yCe${^PU4LQ4zNQ!v*HN z`#x}5v(j@V!n>>mY(a{Z@`69-9O8yosAGW_jO_j@DbPq&thnx0g_@LZ7u0Zle$IQG zP)v9gB#&w80FNwn!z`(G@grc#aq4qI(nRR30ZrF#`6H0Wacru1?MQ(vuN$iKgr0b- z&bSI=Vi2>YdZ+L8e><~*v{OlYOI9^gCsPB$tQ$kb@J*QXHhx;7bnKNOh&)uGrj8Aj zPCQn=eN@ZIhM|RyP5qyIEjEL633z|PI%@F@>hRdJ0m=zk@*M?EMnK~x&&g2eRyX_D zC96=yp)fi;uB%WwJ^4fchp}wb)CHVN!p-uRa#ajy(F5^y+1g=pe`u!#9ptAAXEYZjeP zTDQJw0G|AlS$+qr=w@j#5v8Onx^Kb=v}-aI;mO#4=bW&A)pNiC$@IP7)bl1E2BrD3 zAGGFVs5Es`MicjAWeb}Sse-A& z`$3PPyV)B(fb`Rtbq%8gWTc=Qo*HUXH~u)YTjGcB3!BB~v^TfX%;W$Lqv0s>fVKeas+UX-B%g~*vD%~PXC`VPz zq%zo$4AJ&5WC*`oQ7ldS={;SYGN6q7%F@(_a-{p#wBWyrsfj zQ=nhZXj$aSrc*^J;jmeur_gui1B)R?&JxHYWb-X(nTRjS8EG%59O6}K3kM#<8j9Ee zOtcFTA@aD=g(g`_u=ht<044ObhBBV_9|67vGI#Y)E)la>sHBN@Mr8ff#%Lmyn1ppE znHx0~Iz<^H)@{5yF*<gu!Y4W)EGRgd^@z zA-V4WR-bfi0|B!P{3abS_Mf*Z#xb?JU}(uKnS7)dvF8!E31!D5z!4^V(abTU3A0OA zxIoHF43ER;HZU#B<Zid3Ahduhgmf8eBG>y|o6(8Ggmib0*Xv1G+ctC_>Dd&F>wNvAJ-rBWR|{MD;KYE@3SfaAZZ zpIMwk<+9dddZk^sqwr2Mx)1*DXe+e7))mv-vnRvPaaA8z0ume}yUk#F5>rH#(YEc0 zhhs#iWsYMZ!MPetZ>iuEZ#h%~tc}F{$o8Qf8e?3C9}|t%7>;UAl9t-uJCIvpOX2Y? zszd2)fGFpC1kAlLU}^(&fp6IuVG>ah&P+v}@kX9o5zE@kG8kgu4{g30<88 zt7%GKjCvKVhBthakN;s>SjQ}kQYk6%Rjnne=Z}I7E7AUBw8OwytI8Db4^72{cXsMZSJssN8>eMB1GJR?i&*jIR&6xbN+B7oJoky4NIRIERP8LF-6Sfz#!b$P9m+tMpmoBakEn+e{hv=L#(O-sUqtsf+1X zfv;+gt?Vq`PX=}6k<;X=3;*_EOFZmEAY)fQFm62!`oY7}@}7qSvkzV8!f(IEedQ2i z1JG6klB#8>sCBB=oe&|xBsoa7+YZ!)Jw zp}z@7)v1YnW~sj4|BnvN>>u9hxMX3K$s5ijV$dxiyA-^gcA+81dzn7RNjRbAati4u z)%>?-k2QT)HZac#Qz2UFh=0eZ-511wD?oa`ANR&Sx38c_)y1r+%m@Tyw;-P|H~%xn0qDDE zyLRNRwk5OK<8PUv$ZJ9*vHN`hk#yeJJ0*|u=?XEC8F(;F56oIB?^17H| zsZ(m0_{P}QRTtxX2R-XlisSqYO+Dcm{vi%#Yf6cR-fvRD?hA|XmmH@ z81~6AA`WS*hHA~9kL4qzJ&>t~09eg!Die9w$@KoXTvci8orc5vA#Amo`(3eS3NnTI z=?(RLLQIdorjmx+8UXvoBSx>@Lju3PK`}Zgud~$W?{=Vf_f?7#v!{;|B!d`&Krfn0K@^{PLc4r zKvZ>Y2v1G?E)`;Z1~qg3{S~$GuQYOg(Jv&{XClV(Z9Zh;w>3Cr^_d$h9l}rd?drSd zg2F_?L^?dnbmlc|JrNY$*!0{~TQeuOh>Y?xvo{@;kCS3A9O)69j8GbIffl-;rdQ?&lpb7-FC!y_xlp+!XL+`(XC2!M79UBzl^FhyTCW-(LoG{P7GS><_ zHtG(KZ@xoO%@|>oram}kYFkmv`r3%Mz6`D7wD^zV&;XFFeeA6<1nH{?zP1tM(RhGK zIa@c(tVrCMj@JdkbpArc&Iy@eT=u>rGA#ld*_>W?o#+n&pq#}w69=>1RWnm#-ga>|r@t?uQxwu{ra}nE^5zMX+5Psd0=Wv@6SpRtnJ`Bc7 zU>0CBn)@~cNFzNJKh0dUqQZ78GD9w3@dyouCuYoGGrz?~Zlc@9P<#>}3XR7$JOY1l z5o{>Q6Plr*dIHk>{(F6^9v5$dG!BwkL7BGU>MUj=Oc^+hK69{_skx$% z0tsEFDbd&d_6udt6rWj;SY(U*IWNjGJj17vXv0KPu5$;4ID$1$Sb%Ahr=R*9wEUxUxmC znFzE4;c!-lL*XDUGXtg#kg~P@x$gC{^cwNV-tp^KL}t)K!Lj7&zjkj7=ZnoK+>M-T zH|&Z%>J7V;d5n^jmx@q+vD_^iSUwg?(T9Qn@J4r5e5^?7|#- zxAa)qPEB#>0Fr-qk3J(1ahH1i#$Bh=j}un` z53F7yQ{hz;7V;BLvFmlh*Za1^3yBkh%gG;CV!3qyjQ-W2)xP*M!v+=z%VySaIVSG} zd0CTVAmE}RZndSkEBSg%EIaZdyOM#zw)t+x2md3_xWGHdAFJ5A0{*>u-+ODA(W=v6 zlWp1~=U_G7P#<2bmD?Pc3mh;Y)2zn(J6x7>Og3u3Vht`$s!UkJ;hWhs-bRsork$4#YI?tkx zd;IY)lRujF$Q1#rf`yV5FAXhSRA4_%Y$5`Jy4V5jXw0hemVx$EwI#JU?=2>PXl&Ks z%d-);sT!hHTGtdP@a{U=xteg+;kng7MmSj5%s2qTF2SUk$?eV?t01!6k)Ta(q$h{l z>cjcSeD&{Z$F2-3RPayey}1*z8@j(OGrFM6+&%;g3cNXr$lyyP83vPD)^I%R6as5J z`E?n|?fhhj2Uv^`u%B&T5M?KzCXV$F7b6OjS&u=Z^^U>MIL&ps=gXi_QRXle7qAYC z!5ce87kW5aa+X#54|3ubJqka1BjcEq_nLtcl@jevnNLM4m-vYGU3;AQgicne9Q%^mq~CFPOYcVQ@t! zvFP-3YMS-}7GF#1pUoomt)_OGw@KdZG!}4XGguyJQA_y}%Ohm-2iAcd!MO3RSai|} zZU{X;=!BsvLtGR`e~BxAD2`6S4|TI4mr^{x2J=_*ZsAiX)+s8SI5#x~&)9O%B$o?_ z_T+$!lji<74lkBR&McKw~M5Cy?nm_;jQ% zkn+l1$Nh9;2*FXB%4bzPK`QXeGpAVf18S~H7jq{O!4MuI-)mqaz4LyEzfw~+O zlp#pX?$C~eL=9c|;m87gV`~C%0$m@DOZ=bKj_9j#&ZrUZd+vwyk+6TTCm}f>-eVrL zp1LW5=-lLQ3q`#EZJ)3|G^)j&KHx+feW4a)?aY=*TeR?{hfC&787OZf!s}2SF&z-? zmn38{_8%he!?2n%rz{q$ub@dNNbkwZTjrByj4dSTtbu?BDY@+;IrGh|(rlnfOCQ1N z?``5If14s;YbMRoOx--7R-hLOD20ea3Z{ZQF*Mzi4mwakC6V+W%WFK29(s}hE2pgu z77g-KLml47(KkW{E4veLsx(bb!N9uZMnii4zNMrGqgz0b`9=yP!u9HI#{)gL3S=@_ zIJ}mdURJ(V1cs*b2wJgg>&{Q0yoaM5#UP`p=P`dLDW2Jwo77aC!UZ?9HsnZ%4v}55 zCO=Ti$`(D~_wkIIlAyB_(6@&&uyVt3?(BPf8~7a27~H5-Y%deShDoSs&~pQ9d$>p( z1m0H$qZ)iw*+M72CIr`^%Xu*@sL#au(Bxr)>ISxt4r&}^Y;5GLC_#8|6Y192 zN|o_QX8&so&A`!wjJbRhAq;3jd|%6WYK987i1!0zw|&}fL;sYBo3=~z<#Wb~2nz|t zcNPpNovai#T#H4&kr>ao3 z`wox}Hp%R-lox_FG$GalU^F08r$)HIgSV;`e^bYYbIo;a#Mtw9>a3ENPZaqlOlFAW z$_fBjdv*pH{O|`^e}dJC$g`$jo3JMTI>Oa#2IUs`$n?jhPjg2WI3?}$uz@ADqPEct zQVx@n6UioG4|dR4F0Ck68z0FdfFCa?+a?n~VGq%4Y)Owo`FK}!P7I0k-eDlcI9m~< zEb3Zb^X}H8V5cc~9t=o3J|-9%PAGds(P9C}L<+b<$fSHiuTzs&HFb#FQeet#xSG#A z{$kBb=R5#VEXZu1wZP?+E*$#cw?LMfVVrY+Y@_W%ENRvFqD{;j36IdEKUsRDhx1ZT zrHMIuxgwKJXPSWuMz~=9^TotU(>&3Ki%#s(RJ|T)u9!w5wlg>!%k$i&y3BU2r42;7d2+(km#BnVR&{Zl-ysAw|h;+c12?a`bv_a_F;#5+&4Rw}sP=48H zBh(67S26LQQ1)y;rH;SLJ1un7vV`>nk!R zR7ObXN2t&1og#;!y;Xhm9&^f^(sG(5V-u_P!Q<}@tqos910FnDUlT=L$6jH!hXkY8 zHH6f@Bb^Zmb%T=^#_2W;r1mP}?6&q3;K!NbP%M<3H*w41Wpu>k-|*V`E^Yy`c{!i| z)M9QD@!T~`{Fe%DDtO`X#cJ6CoVt<>ED;|_&mG!%OQWcCR#`OsEf2KWfDHS z`%Y%X<2JJ^hg=%=CvTGlma*xnG4I;tU+93;dD(a7FwU~Feb#eEqR6b`)!vE`2vb_S z*XHCFcJAtu9jvHoey1`cK5hV(eb51?N@tGw*ijzdu~{6feoykleVxNOeQ{sJ%}%aNfvHTV*e(wiVZvm(jaL! zHJ+hlJDG(&G}lTsi8-F?^)Z&YWiK{iSuu1CHnn>s)(6pKpNLfw>P@PHBb=N%t*;gAo+u1o~ygWOx z=PvD4?rNHug0Bpt9LwH4t)1oW790p!4NDd6I%ay`Q0XA0B{T{atyrbN2fQF3ZRbjMpX7FpZLelyAVTkJ6nthl06cMlR^0B3s`O zN5vS)FS4~1lw_>baWtdC%%;o4p*g*QQCX_!)fN{}34nF>*Hur6L_b(?!UoAy=8~)` zxkEyK;Ye`FVN{Ii5PW2-@fahfE@7Q+rG=AS#i&TXHdr?)b?Gd$?dI6AJQY_b>2jec znm965@GNC$@PuMRL7E#mo#ma15(#Lk7s%oD6c8kw*>e}65L>mRy*e_{Ilu83+*n*N z0<2IWe!#l(OwgpVYxx`6Zryjz(raX!TmXV(23gB1Q}5zYgL-ajWozLZxZ~f4z~!bp zC!&I6*v7_l*OSr0pEfGzHYaI6!|XEUsgLvZ^H7H?P+)-G6ASW~#T=&e;nR#C1dnCpei1NL#C z89+v~6{{4uUBt!TO|L#0P~g^ly1n30S#Bho1}R?0y1WRtpZHA9LY~uRC5yNd*drXx z+O1in%02jYgFS-VcjV@)`;WEmtFP>xov*p}Vfryvjr_ac-QG}QNgIr{ZWX;F;%1H-@CWGHMZzEVUqYikAQV`0Iky7$>Kuf1~Q}qJYyZ8$K9s%MCV%S2%l?Ml6bOsbj_?x~(u)**!yM zD{Nba`5N1&!}sqA!hk@>m0z2=e*d+W%YZz({T?xRJkw7sj@%=r5FNc?{eqV#n_wNp z%hRC370c|Hx2$NDM7|X5!y^%;6Kd|B!U(Hh-K7AOXmZ~LI650A|A-3?dmKPjCr_4vJ#ZqZZ$A|N91c!F7ex}W8z9! zx!5SRXfl`di?JU8qQLZ$LE7Zlx2X2#B%*StbhpzppE zWA-N0cl;}8pMudYPA4RM|7G~U!^Ux2k`6%RKtQz3w(g9`fOdtDq5*&MrNC#PI4G54 zrEn9=3Oy5J(?_~z(R8xr1K?xWg@6Nk%PO)46eaE_81vkbP{ zUv zOaVg?gS})DASfAk%n{L+JRB=IbBXV}u*PEBi{upEP)jy{&mkXqHw`6Q6jT zvjvZUFkhmp3I864KAF@SpoykhHDH|ob2RJ$_;)(|c9Wiy zi}UmIb_aMGZom7F8_n&7CVy9#*Z+JE|Mq-kaq1SkNYKJVtcgP%cd%qcNo$zFZg@p= zijJo*eI!vI*niikLTHyyy8OYvP&>Cce#vBI!14(_bw%ZwX7U)0>@LldzR{D=*ta9C zPIplUNU0F*A$v?Ady-H@=1_O+2nJz!W!U`JjIbI=Z>eDZ$Bd-^$BdZ!jj=AmPDlpp za=p#Sb&7OfortV2q-2R^)uDCLfE07Qe5Rkt(Y1j(fwoEhYew+@F(c*wpBa7q$BYdA zV@8YEgo`k82CX--w}1jjgLSJ4s5yh~BTA7I_CqToJ^0wwc1@uV1^7eded^-@6osjz z(u1j2#3w{<2DbK`4>{bcR8uWz(JM`jN)Q63^-Rc|jiGaKu&7ThtNE(ew?0l~2E5bw zG#8BF@B_$^c$db;c&Gg#mH8dFqMWG|8lv)e^p)nE0h>*a8o)lu=x-2Bmw|lDw%k;o>xcxxgOs9rL>iwCIjlG<7*zOm%wP}>c%^&R6@LjyI(?ZXt|TM32L;!>5VW5 zK4!cv#ibFW0ALz2L86zj+;8WZ9HfA;oFjXYqMFWhp61AkrZ6312J%{^J9s$S=Bfh3 z#a2p~LuR{p{=atA^&dMr`5!xS#&SuwZ>rrn{yLeNfJYFxT<{&1jTwqmw~`JggG>y| z75Jt0X<21(5Z~w^pJbPE-ew=xGNtUeXFf8rrw5!VQ_ENhFi$;E-B<}2x8}j8)@q`c zPFNMAOpc?LpD)rMGSl!UGp9iDnvcVD4G)R~)32!Fc?c+<6n?u*?z+xFAWH_aOXFeL zC1P)!-6BnSn0@D3E9TnCPT;-dkrr%O4NW@n9q-XZqW))^X>9z1LBode>@YsQ7;InR zFa`KK`_OSSYXneJ9S*`CcL?QDOOff^*YLY5aJJPGRviz69OCvRf>mnAi=HQv$a?P(UG7R24kxWUq&hUlt8 z8t~K}zd+Vy8ozizA>DJ7QhNMJb$^-kewcFmS7Mg9?l$bZ<=We}A2mKH-*1|C0M>l5 zR~P#pLSNkueq(kEMlR|r(vy9?z}jwyR4@xmulak8qgSW)g{7uh2DWV%Vi38p%TEdE zvllqHy}~o?Cz6RRiGWoXq1Ao8v;$OT6mSDsZ>xNJOzi z{@j;JReI}l_dN29NWxn)A)89$fKhzJ)ccXOV9!j?vL?SBL8W!o`XAjc>y`G-LXo|l zrpE3*w=~&;jOkfCX|)a^F0xMCsv^y4KFr0qL3Wd8Guuur3Rx5|Nk*0m@h!z0dUG_WTzHdQ)^?P^Yk;rgAN4zL1N6AD0t#v#5l-SC8ci#(Lw7ZeQ`cq zI|(`BFBjKy)XUeRa>8&xJW3h_^9|I}bGN^nQna+|P7gD^yeA*r+K{2ao_RQ&=(awS zxPF){G{z)Htj$}_25sa`^MJ)YyQ!r^KcuErf1i#51?bNOTQ=gthDj~(s_O7}dCcDB zj8~{cD@I3SV6k*_!-MaaM9@ciCjibAt&HZtXQM9Sv~l4Ile3*Gjtzn21z&X6W()QF z4nQL!iY9=Io^Zu{;?Jppr7--&kwIs~D&jL#=I#{=u^ostc9(ZpUeo%m3ca4lgE_Ej zcGEn50lloxqHsmOFkhiY(~fzXn$nMC+wR;kcIyb?L!;vpKg;ip(!r*4}HiEk*I+5gZrzgQkYUA>2UXnEGp^*2rxZBj-+6 z|Nh69EXlBW4w?@TCx_>0t0HSbi;UHXo;Ofw0BhUG@&|@MakJzxpvKecdO&<#a9xkc_v~CEZ>fgf3)0V{d`+51#mwGOjnQ(>l5F!tvHwpS*BuSl+Py~|LG(I|1VQx9 zC^6AV5W*#e2!n~<2??W5^m6nbgeW0O^fo%9Ly*>@pT@AN%93)rdc(TXMYH8tUgWnz`O1Q^inLOW?Xx7%t5mMM`^3?jn zYjrx3&y>^OxRWVFSSv%675%DM=K_NjRZUeINzG^z6?8#7TkFTdt}i=4LTjDim!R|n zp)6w*N5w3k`D^DZ4Btzo<3wN7nOM^gS;5v$!P7e4(qTF)m1<&%G1px!6u4K$KYkgo zmq{g!8xeJ?JNnUeGALA($8&MA$Crxj=yt;UN>w^3Y>Yv6 z%)&uBiYH_X%WXy5FBfIpRZ=O@)8l}Zm&Bp?9a#BaR=j2E7hHNZ1%A^X1q4eQ&;uiD*<`4UKig|AN@z&3ouU!Mzin5h&P-4z_uS zY6~X_obm5{NS%D|EA(K!F(4r}Az4ppXV@`HFVgwl(mf2$3T#r~p_Ih1RXeeSXQVB1VN|20N%33K#IG$>43+PEYId9gObYUsDXx)t%C5?52($ zjM|Yh6KebyIX`aQ+s4tf=8@+ri15p0T$Rag&>W&lx3{SrL>e$?xTShFi&p39?rLm2 zPCZk?qMLi4M8!#)!-P~>qWY!MHB-_bU%Ml6{r!aw0gXdjlTqDMh0H+AAZzwO8p@S~ z5eM}*xt)@GVQFTiRtHWZ-_)2_lk%)O79TySwAFV0N&BJu#i@g3e6W7_mKU<+K<5gzPsULbGEl}2cME4O7R&Ws?Rj$y zO0zR`{_*YUfM$Ij@e%d~G+WjOIEBNESehI0pnqYoh+kWISj)>;b~?itiIf3OuegZ7 zV8fj#Ld*9lh7bj^@W`V1mIR94wC=8)Rc3@*F@F%Ox_-PQ*TPfR)?Mi0O2chTtN-O? zqNZ2E7IxZ|yN2NiPx>6gxF_@v$yge$0H}CoR9M^?8C<(Rn5DtqW!Y*}?=6lygcoGR(S_P$8o&gD$dF8NE+^5WqI{xUscLWB#BO@?x}f}3M_DI(x=eel=Jtk(r` zR%Bps=oo%!zv%3}a4*|=7Y3P>fNS`%BLD_%LH~9i7L#(O-!OUnjAzjJe8(7aH$lT1 zzZ!(Thh;``4{VMNH=ZOc+mFmS!`Hhui_~=pajlO04U>I|;Cfy!7k`0U#SgSfjf!3cqkws@fw~a(3+?Y=~xZQJMnIRB0!ay zpu|926QK}2(aT08Xb=mqC*381##R?Gh>Vp30ZH6=)<9vB9BQn2lOV%*;ad%1R?K89 z0aE*UnB{|>KKMMJay-is#nJsq;@1*>2!2}lc<6VH&dt3|Z-VsF9Yv!>K^CUzXE?d* z`;P`!HC`chd|oAjxBcFz5>ja0^u!RG8aXgVJPM3AEgRf7%g*4RGq;WiK9k1+u zg%Eyp`lxH>k_{k|sfm-YG@gx$lUGK0C}%tq_DHTwsJMK#!Q8+DRVi z5nWO&BoZTF%2P+mO_Xwm#YkyZ>kFk1Na|Un7WcJjalz;M5K@#d9b*r3UuSm#q_-0- zBc%CVL~T|if4zo6RhrU8BKKhcFC`7{6v#+PAzF<_VG{tkR3-LJ==}rIty(YFLuu(g z>C!LYI!4WLDVP47GO=llymmt|keT`yN=KvXqf}u?aiQA~5^#eptgX2H-(rQ5kMl%A78vvk#Nmbv`~ouMQbWcod|BQ{zf_r zw+u5?O^c<~)k|>L80DLg1k$c4p8^Oyh(9mQVJ*CJu(R8i&6FszYT(2AA#sox%BV)R zcCBLSq6cJ9F!-Q_ZK1XWJ79$OR^AEffa3JXdT_dYQ9HMBSVXK|e#(scIF<#YMHNT6 zZ%Rup%p7>%$sW1>Av4X|=^omOMo`ijCd;l5r9z!J$ zUmBj}*w)|0?$;~Y9AbyA8F8peW^>_s`wZvlrk3cX;*D38-Na!@!`T-a7a;E*ZAqEP z3_d+TKhx`JQD+bPlI^5|b(BJjRHN#h0}* z_oBYc8Y736Q9g%Djze43OE~04@;f_Qn@`lbpIQ`E-+Gs`yRF}NJv7f1IB;Fq*EX6Y zRJZi(5BZ_DbzPG9#30bB84#Jyh?;Z#C`IMld`8bF?8O^p-%p9WEUj6)Q3do{MoDZQ zyvX$~q8f zIw)9K^y7lbmQ#M$!QjFdAn-Hg!71L!Rc1N(CeX|@m@i-ek4qL6)8ms>K*>Us5k4B~ zh5}YDJzYw(qWl(Nttbn=E1dE{r~-p?m5&OFb@x^2%`oy1TB#S(#bkvtZ-7A08J5A% zWqHYa)PPUXRT;)g-2)pPWoft_4|_(%gUyI80n$f3&1bRcd!=Mh6)nEOkNYc|me_jh z*l!Hp;{sg}dYy$?gr%{{g9ckT4=5-_}eo>QY({W62#wu_Z~CMHPjlQE%^ z6$NslqLDsLE|XOoJ+ckaZkc%`X}sucoswiA+G`!d>oIeD$7S;RDr!HmokOQI&uBwJ zu6b_zlTKvB@niY$B<1zdYN4o(^ZGVEpOLmlEek*TVZ(V zoIf|0HIuqQK!BjzMv>?VLUwoKm4X=9xAXcJrGrl|T-y=8Sb|c96SsxX7bDt|1a6|k zbGi0Jb1#OC+$^R-uc3MjtP1v8Z1(C%66i1q^UuTfW(uDg1`eFOe)AMKz0I}}b;`p? zW~@f|q48!KhRTs@kwQ!ZjH9dXlq({Y;Pff%{S_*i9*b%um6!V~ghjCP!ucVzenlP% zxh9U_cP_H}=BQfYOD;K=z1-$YX#5!1GbH^geGTA5YfOPOTn}ZJEBM;oeB+*0iAw~r z^Ft_%qJ%-olvFYWOvLFL-z!p=-^7%mgX zr&s>Z(jfe zQX|CV+TkfrZsOIXs$N{#!$pdV+}OrN&RktW(lV{Zim!jzGrB zob}HCAQG-)z2YJwEj`d7$>9RYFITyMxkMuq!xX79IF`?_NWXJ7y*y0?r;#ZWX^=S* zFoGzQ)phuQG;ci1itWK1-*s$N;ZWZqkqogs;x3?l%sP!Yk~;k0MSr@}MF!POC#L~R zPo%K(*Y-LzP$*hInL4uNvAm#jH4e5KWW%#Bhw5+F+&l6#y3u;}HIA&VF*c5TfOJL` z5mP4XNxgRj^vSEkQuIAZx5OIL;~65@$L1!T3@K2uWGBzyk=ZmI7xhIF}dpag_A3zD$|+}?PI6WGfH*~3Sru3K|!Z) z^au;$M!pHRP?Ua`hc}&VpU_QmQoEWwOhdiTsK%XoI!5vPVDA?I^#a>-dkslA> zz*a9Rw?E#fowB=QUo*Nh4;z(S8AS?4!A|8x^Dy;j9Tp1hWFfojtmBpGR@e~b?^kIy zN!_F0)$pgYp8X+naV|{?|%ipn@1lzGl%|GWu%@gF{ak5&Ff=Q4WdYa=)P zM`lizLgp?`x;OFg=?H#m?Ewp25Ik4ltPA?jw9sw{UIGB?h8q6>E_%>brH=;!Jv#@d z_zhU_>My|J|AySL=jv8={uvvAEHotI^{x?pRHH%Fr=dn}&6I%jg_xxW9Fg+0bVLM=^hxKnx z|LtzGfIyVL<={EM)XRqY!Rfy}h^jw*$UT1HBr5uEq<*e9{tT8$2Z7Yxt$)=&{PX^S zAm@~RK7>E{Rrx;xhI)Da$?|D0$)Om>;~7dNoPJ!Eu!accs1 zXi|Pnog2&7R_?wJqc`vE4`{)%jJL6d6{1JQL4XgX1ONB+%Mne+_{yZ90Y2WRYzk6Q zE3rr^rTK#PUe$Fx;isk!37KzX!SKGt!^LXtK0JYg%`;{PKIDEj8=T0Q0CfD{R|ijf zNv078F1|Rk7n08~mm?q1=O@E)bjT5*4*0;%xgN#LqssUa+?pZ0nVZU>r@<%<2Z_~jd+$L~(v`E}Q`nTu$=1?e;6|3Ov?{}!)*}$JT zKd$o!C3d8r>I>-ViRVP{i+757GK<2JyFh?9+ne1xsg~o;?pWk4gn<|7YRsi_P|CcM z3pSUa(gSu)D62VkyX)_V9a|nubE|SR+k>$hR@}*uYOMydwwfvn3N~vKUDs(I(%j8f ziyfC+_#rP*xZk#aQw zDT3x%u@+G^yOnOT9&s**fHaB=t;<{kAy~ILkexYn9Z^PC=ToCQSeQ@Xo$)ix%-j^H zgG%49_72Br+n+>mPjj{Rv3(nv&fqK~5xRY4fY*TI8AZx>KY10Q>q69912EC*4y;jv z|Am2YH+Lv1Enaui$SfB&P~qWN5|=?nkLGR8zqt5KYxy$M~zz*K_gIZEf6AjlI+0Vw!# z*fi~g8eoHFbZcYFW_3~aK#fq_+x4B$%ATc{EUzGNKTyTkQ>cH3=mVM9;tM6AIypG} zd0Q9ysO83Sw-G*{GN2Ox{?h(~td4<-?3ScGsub2;5e8z)njf91mp@KDC>ggG2&`M!{~P%s^zuI-|AU%xQ#@7n1IQ#}?>Oc~+kifs=O6+IDW``t z8#Ml)j~|WOXkO?<?R3KFaJE28u+a+XrdFHkY7og6NPfUEmjIRC;THhH2kxEU{G z$Hu7;n3r2-qNLcfI;(t_lDJ5l2^1`r-WxyxJ z>0gwwjx5ypbme9k;No>IwU0A*kp=fR@70Re?h)V@Ia_fBC1&SCV{iZDIRE~;dh9*JAUBu1Jy;N$+S>})(dHo zWLP0t<|0~N!W`1_&jF|AggWR7yyYn7;i@J0cT zgQDQKt8Rzpbb5k50NX8yb!hHYieTc?i{+SMCzWpk*Ot|F#YP8D|FoNP3b_uqdYdJc zI~HkzjqYZ2Ryi~`yqe4EIVA5Uy-S}M8dY%espXhf)UReZ9;BBth|^zvR^|6&6#AdRL&&SigD*h=KY>zuWZbX!Xw$qv=HeDMrnL{!8jMV`>s{eT)Nl!#i5NO9zUs^h4VLOdEyidUy}Zv-TV ziQv&(@zGS2z@AH<;?BlQY?8PN6qtK{G7CW;zOcyP{TZybfr$D8rw8z|ze`!u$?UaE z@iHvs1$V|$8JD{h=%^#)z^q-HRWtfeN>*Y>8=rmkko(^ai4^ue87_ss3v*94lv`4V zb`t6?I}T#kaxB|U@W}`_+13w3sD3_jq@Mh_=}Yb+z;YSXPGb?>SKf&H-EDG^Z?!@I+&oik@ zsK`h&&4xh@W^Q0>UHE-_dRs~5Q>u%qbi*T*H6BGCviGIym_B}Hh5)g&PGAvS)%)6)syrH{>5&&#$6Icj zLLXj_#tN@A)CrcqOJ8Z8n=mo&W#W|=tyC&YXvuHvit@7CN$r2>#|o``qZ&udXvoRIV#(#JMN`Wo{b${)Tn&khS;dWZ2J3B{e3Xlip(DsJ--g_&V-LwP(<~EUYWO6 zz{SU>Jsz$utZp-UMP(IYd{H~CWerSQ4LuyHVF?mPRyzN$HQl4HooDK<$^6Ad%{-ji zXo5Eu^vHRlQ2mq4Z@2{E&jd-5_34@Ts99q^O2J9v=BR+T2buF>Hga_p=Mv+0(}HgY zQJp@r#`b#74A+}o(@|Y6gP8jv&3Uvs;3dLa@`h3#hJZ80qYXpxC$q&-YQwL8e>_3s z!vt|Vk_sKvHw(9%?jtMVm)UglCv?P_IlCZNYN#T63nIRxQGL=GO0wiN&d1NFwB<~{ zmZ!2uZy0e*k_~666N=4GLE4>n4z^6J8NUUT{i*#xw2M851;Cx<1KqPi{Wg)+i>wy3CKLAlG1(`b0eaI8+} znNhJ0&0z^9Wd-$ml)OcSrTToU3>J2DA&F#5P_INY%Zar)dU5$c0rAKaw2XY@iuZyh zAKm;n+i4pp90H*uABT5-YL_-WV4DCbkHJ3Z&k1OEc+-hMGMu}?y&6Ww8cDCQiLhl2 zN|No+T1R4|Z=5NDp3GHHIv>NvIlFp;xg|x|!-A|wvKP#wm3<2Anws?R zv{u1>ATD%-@rU~(`%-jp+;TYbgxX!HV8?7a_q#rWs$K-CVa;#dNIBSiU@d$hN`$Hc z7Ux<+Jt>>Im9*++L3KXj+WB8_F@#se^}qibky={;J=yHpt`cbG$FejY&yKlQBU7Sy z4%T2jPjK&0Uc3QY@^F?ARtn4yt>Bn*8w7nYG)?u9vwO1T(AO!A;u~0JZBxjqm^)Si zq{s3fW;|3Gt+0Xz4>vL&0Fz(%!r>$wv-HnRtB)nA@0x?!nA=8bfZvNJsh~)X(g|>N zRv;3L$)19fDs$D@_*Cw18dvUzJw zfUIdhDU+EYj9GeMyH3hFTOwSgh%Fl*{~YA5G*WC_TQ`=jU;hdyK#WqRf6;BJB za_IMX{R8T^J?aPRQP>yha%JE**#FND8XMt;LBaorDKz>Z62SkTC9`ooo8VCqeVn4MoL}vp{q-i1)O}(IKiZsMW8r}BaEEwW+C4IJ?9)*-ZY-RuZ z&wlZgYY&&MtN73Pv1E%MsVSRY7m;<}hA_Ou>pnl-j%oC3bG{RwX&8VV+~F;kNG`?Y zFIv&6HDT5t>Yq8B{E`y(RGQwp3%WeleIqUv7nh%K{K}E$PfQQr&xhkWDjER;zL><< zM(k~3co-aMEY)Nr`}SPJh1NzwcZ#iIbsvAftoMl9-l4DL9%N z`zxpe``3iRalxIMi9C*xU2 z2h(vJ=yj}=P;W_+GmA$rXsf83QWRpi!#TRXOUSoV&B{+&M?J0xnHqV9{Dd)KcBD9r zLdGaF{4Sqhfl?)H9>Py@V^xA1T!3RKm*} z2atugM0GPxHU^B|F!9v2-k{9wR$uq0+G9aaniMj<>br{5z zW>(I2e=qXT4NHFRuaVn`&d_^+^8F)53)gFAN7ft46#!Kn`O3@vs4?lmk2kzTXldM4 zDT386x@|57F;=Zk9|s5MX1Q)1H(L*=8TRf%t|SN0!cC^xL2l|k zH6xSPHL|)*UU2K(qI~nUAXc_rpmh(g9JYHNBPdboIx`Qe=(+tC{Xo|<{{DdK|4S0D zD*R<&C87nv8fQudgzt(eFp385{$RS2ypU3nU;}aNKY&P*n46nenXw&jF1;*6Fy#YM zn$<^s7^yR_3oNUO5h18hSRH?vmyRl$dMr7WcQw$B#W!7wAi+fU8Dd7riVY>G zqM9x&J%%`3{|@3A1do-a=k^ltbDBQ2E4WGxp4Nxmo_`$&AtGnC6GZh6b)u|>vhj+e z*RCLCN1>z>FYbQt-hzwxiF}#sDUz&)M{+LC>79X_usJULlyIFnfVvBksV}vzjyhsW zSI}dgSl!_$+i6gmSX3f9B>6!o+_Py_b}oCwpaD;klrUZ|1lig>z1=Y_WqNG)8Z34| z?s+)fn9WH11GwigBKUwwN~3fGC;$9?4U3D`{++;h+m9I}F;-QVb5IOn1@Uy`#h@GU zr@??XAFT`Y#?foJ}YKZIj45Q!z?Cbd@WhNO3pz@lAWWCVYb#ZR zof?>NJIjnJHUwVNzsH%20vz7mJ~e7je-qkFJEJP6^#FV|#;*wJUK+mlO;c>6rwp5+ zOS5i};?zlHTHk`p3zYa>+R&h0>+ZZKHl?V@;BdV&_XFT{wQh$@>}!KS(%}zHOP%5D z3=mAJR5pnxPpa!s%YwFjo^lx;Ku{0ua+4iIl6M_)gl=I<`|7GqUrKiUr76g|Tz8R;djZ{Ynb?>7Z+zkWgYc`B0s@&~F`Z~66gCO9P#Wi* z*#(n=jc{YLS9+3NkmN@)@j6q=Zv+)~R6sc4No3}zZQmqeJ2Pl|oyOB9FGC7cWPcg$ zOP93oSUptOW~8d2n>7#0WP zc=aH^L;MnWf7s6Ld41>x6l)hgZh+6P%Gq53-|y+!-D%swfPHP@ z7_LPulx2=Ka;|8Hjv4*l84ZEK#RokKvD*j^fc$*`T4au?F5;9VuSAaE?7ic4;tF5( z{Kgg4zHe<`)cyRkpC+w{W?v-lJ0b$U^SN3be0nG&tYpd06m3BE)ox@wSRdqkDx7_R z$M>vbBXFYOkZ1^@2LcycB8rC`=)fDwfpCtszahHQI6zDD0gJdnAzBVJJ3Ij0y@~4* z-LkewArpTSJdMj&2z8?(Wt*t7uZ%nN>clx=dd8PV=(Xlu{asF`<@F)tCB5=Kyt+>X zBg2ktkG{THd$xi8xGH%^aBSOc+EC2FCcB(!rhA#ydDYGE=_Jea1UKyjFt%s7^Y5^% zgJDruQ_`0pWcL{^L5_~4wxp;3hOoDvcfKju_f)*MWyyTwK*q`i9WyZ$aq8Q2c%QC# zQ=+vKdE+eq=H(9LpuX@7ykD`G(4M^PQZ$I z>wWj=yU*~!`q4oQlAH+@!5$hIZ-O*J@Ku8=t}{$CdbCzR(HSoTM6`65KDz&Te;-sX zh4enVW9ObP8P;Vb#5`l5M%2rlabDba;*xGnX_-_1^Oz)+o5GgZDIy&TMufmE=^XoZ zg$t&WTmGw6!|ew~k;$})j&{{TM$$@u*_AhPUmmE;#bbnsQl$u-YxMK#V=E#*mgQ(+ z$Z*+&UHd$R@Z!iIFfhB)E6JIL{7$&bK*^3S{FfM#xEJ&=i_Vq*!t;?Zckfoc1;1Wm zttDDufv#myQWq$&=|zcF%(wl!AiT@4UUeDi-AP*82Op{1=-WE;_l z<1yyaM7b01>S80h3(-f-L>vf3g(f9Ukn#@{i?8Bvb?9{&(}E=m)9*9qs@^No8Vdt^ zGPyW__6huBHo9&ny`&-6*a_FLg!eHVTW7mXZB#;GY_#${`-cTX)r=j`9hS4s8b> z6jqb#5aok0Uxk((@Q+&ILd-qi2i96qJ9j~fI(NgwaRD(BEnl(g2z7+%w2_y;6xIxm zkYltqve=o~pBVTX3`e)a+eKG&u(B0;26%t-z&wvmh zhQh_>CLS)UZVz6U&QWqmY(Ip!#tIbxeoPJ}mMDQ|p_+sCtLU(APF*01A`E*rhuJ7y zc2;V(=2p{R-Tp2*!WmTNSsLmLoBw;gL09tRhP~@5K3&XZslU7u%89Ttg%I9O31hU=rcgpTP61uAI4ANSG=fn^Y(-(`cLNoy5!G&Qt2CS)Ey%_)#6s zEvma=fUEQ`8u90hT`f1at9=vpWGRn`t%Klx-b)d^uD~Pp-^o%w{;a*qHhxcFu9F|U z*TFkXXKTko81rLGYq0!iy=vp}QWnSNhNKk4X@7|VbKkFGPxo_(HqeRKDbOkXx4#o} z0`}3u*0dt6jg-m45%N?=zY%BtWe+<1T1WyMZm!em*^iTm5c~Ji)$T=gPu05@r>RPN zX@VZwUlMY6Uz7NnN|HQPU=uokTLfaNC>}q;o2KI5+R8H9TIi)voFoa^tDvpl0*Cs^ zerCk`QSYg0Md}a|k8w3q0h_)GH$fo6FNH3#bcN!RwlTDM*YHe4xM-rpc(QjyRp`0m zj6Y?s0%N}TX*$W0q?XCcr~cUx=#!9Gb_^|4KTQ_QfRIR+bXy3@Zd(WfjdWq)A+Fpx zF1Lae&!jW0w~ba&n%Tj%OH!uOgQZ%$KKKGX7zn~vLRu_M&hO1CaC;0?zp7C5t0Bo& z+6nZA*-x(Z5!U4bk#K+0Uh@Sasgswn!d{5Wdl^a@H~ejRQ*XX!PS1t{H((eG2u2u0 zRM(7@S=&xgkbjk49U|8N)L}I`soV7L-RY4MuCA2V(ovZ_gyWRL2BK+eig*!>Y^ZFS zxapPr>W3{0;c;P$H{SL7#NNEo-F}1X86uORTiIF-iRQ5F)fX#Ss)Bp{7Rq-}+E4II zL5DpYRk=<^nw$3om4;_5f2O%DKMO=}L8q}TD^MycVU#i%9PH@<0!@CxzT;FQ&L2>{ zQG!wH=`5RfP8}CTlVq&B5WBdhU14%#ToFRaR3VY#bIns&+3tMG!qFDGL;A}rr41$1 zF34A^{(`eIBp4r$Vta9g0&8wzjtDytJBI$;!$b~W+c#l#Q9r;?hw#1$a*eKdt_MvK z3-d(Q8k>~kOWeW-AlD%SWAutuzno?;z{}>9u2&SrE4)sM;JB#8w5V-EWfkce+$R7S zqHPUuT`IUryBNpj>ik4b=bN61$;jH4gy&E}7hV!nW(7R%!$u1+X&h)pGP&CeF_v*O z1#FqMIM|8s-h;kgX$Meby~tEb5v1IP+0oLTq8nOcd%J&(gOu57f1vZdF7R86;A&sJ zyT$Q?Y;(RL{(mtgtD+wD1LD75)0_qhjJ-y0?VoNP!!CnvZKT2V#K=a<6UFJq z>CEZn<7KG(Ex@eD208=NAynAGH|>k z5?K z`h7w&$+sZ2z4K32YJbR{@f1T#T-J-?z0)trKJ0Iub}wvnDSOZ|EY7U%PS0LMM*C=Y zQFdeBhoEGlq74}|`vwGcA9;~9SwNOOR5*%};}|O|_1L()MuRn?apqM8bp8UFsp4|IigEJ(#!H;`N~ie_4Tt9C1d)V+9$*|&+J_Ma zU0+_8xr>gv1$AuzW>Z4fT0-7=+>9}pek6&mmB-RZOL&AlS=82S5-w4msem5Z}E<~Bl+8)Z+7#k2|yH*@m5 zu8gu?SJTFh+Y5%;$WD3;0??JZin|N9MPBj6JTgXy&G(m9vqW`juz$$kw*^tmQrroK zzm#6;iTwjY@FM24u@Fi2(2dJ<%ry*wSA@!@BMjyhKGTXyivKI3p)|9+cP9ZY%rDzc z;c2?y7`lxa5xfFZel}^$#VCv1zfG@hR(t)2R1TG2J)L>7uH1yMHGt+<&Ikg>aFdbd z{w|&=uRrnF32QjlVEFtUPa-(8GRgx~-FJRHYn?2$8}f{gidpYZX~OQEz{=)Dw7aTyMa~>V=zmjic9vUEy*B_V9!)R&;<_X9leZA{8O1Yi| z-Mn0^QLh}P##8Wyfo0yQ2$Xt;WDu}5gS{RT;V*@<`B!3afr00jTyP#`Z8$oqi3w2F z(l&dqfsufxtnf%RO)JV2?*jisCq?r^EK;&!jWpd5KL>|M8b2FxxK{sf*imD7Y8mZV zyw;q!7bTynn8W|>3okowOdvlf3u&INV(yw=TnNKn6BqN3w35dZDPC(!c)&MG%f;{XCrZ7iieUv*4OylQVMp zX+eXYy0UvuKd_SCkoQ(?=J&5beo$)G7y~LnqR_aD(%U8bk95NnN~rbhea@ME{?D(^ zAwexF9Nr8)6Q6)zqdNOT{8CWozbK}&8f^n6N0U<;0Ey^$orYNlA5GLjrBO=9R3?ej zOQ?dFblA8K9zPR4P)2+Ze0-6?sW)OrMeq{O_{VX{*uH{-ZoZC0N*3>MF1`yzU##nk zTOa;8V?FE%Tl9MfkMH`Qt)$L#MiiU_K zv}dyHS;OF&`Mb=Oeiev+kOxc>|~xb#fs}pWxHD`LWsx8~czv+muokIa-|v(S?Z;J_&y9-KbhJZUJNNTJN$he z_`%Db)l~XANUK#LaOq^e>wcd?hT*pU`;E;S{YbTpHmFFq0M{y}u|vKgw0y__iRD^x zS>7Hz1&Y(o`QhMkw0PcHY_#W!Lzt1{Q?oln_4Ce@%Ow1(Nq>VxV&nb`>i_lxnFIRO;|lP+yaC{M{=B;W@+tNVgZWQ5nMmP6<T@sfjQRC)w-p1FzPZF0xPIK}@qc8o#eMBL z1|s2jY#H%{%lh`nt>))u)?bWTRh_haAFITkTn<|Vq@Mds?5G=#*4v){KHco7sEBzA z31Zt!&-phfMg6C|_KIockge6(&{e+CR_{@}Ec++eCO=lJ;_YY8#D@0H=6zp<)S z*Nv`v=8N^^kI^gYZ;RyliTiD7_mS%3J^i}Hbo&H9>Gm;y5qmyl)+R#enl7mGW%1F8 z`R|Q#6oR@O>8x5&u0Z=FJUKg6J@=K3KKB~<+4c)?eZQ|(cegD?`P}8aSChwgS}Bk* z5x-j-&>OMloLy#%m1loG6r+7C)OgYz4$C6{0cU0<9Re2&BPv$}YU$LJ~(+bzzj zvDWchx>P zW1P3;nr)IX0_#f~*qGcX%$)}zuHW4XsynK!q35>$gynn?@kdZ~F4fe$yjE&LA?N~I z%^f%!`8SXcKeI{rX@>sU><>n(Wpo|VaWV9sjgA4^z-CBi z*}}Xf9gqv-?(*B=@Z_!R`pCHAL^R8Pd{5qMjLeUEXf|(R~2yaNhR>>FwVqdTeUeglSWtR(Zaphdh zKidTrY>z`INFrZN@@QQy!~vl*ksF|4@Chf|2*hglhI?FHqX?oy31qv6f{?q z`F*3X`ZzL!r_$Z8#UQ%(j`gN>7X5=0t1wTUvdGna!ydJIu`CF z<+)3Q*_H-|WCAf=_4t92{q~*pV0c;958nE`MlR;vCm!6QERUg)T{k2Gy6Qu!&r)yL z45`9>lUuR19b%99B|?NxXb~P6x5$uv+&qby-*LH%>NUfkQ0StuSD=LH^>;(eR3Vs* zwB6)MzC@jwX3@~PdK$pN=JAFkffw(d_fV>pxZP&tOAS9qttj?RmOWgUlU)xF(+xWQaMg$dF@F)iGs)>chxhAy*VfN8Qq*^M>#eV z^CA~~+FK~WIqPS&CZTZ5!DjI#%Vg!8DPB!bvDV8b$ylC%xg&6|zr39ck*Uo9#Di^A z*-nqaSx1sia!L4KdqfaLeDSoR!4NUYGzjMF`-6wug>*7bMz`*|l}{8L1xLp`2M5bj zte8TQi*9i6%M_f&$E^Q@h?KRe)zxQdoA6ZjJd z_oqD5T3m~@*%eAm^y7~m%|hQE!`eJSlyS{(G&(L+2n0gfjOt20_Tb-(1hYmj(Rge z=ws}SmgXE?5@qBFOPin7{sveZVVOiq6+hU>a3CJ}Iivo7s)^R_NuV*A?5k9AB3u(- zmU=d^Vq*#6B2$me=!M7b6Mzzsov7>}EA+?l}~*%gG6m zK$(`vooE0Gn@8dcK;k+H`qUL-GB=}g=v-3fd!1@)2Ia&g<&GqTqiGg?yPhJ-!FBI+ zxRx?*1?CK6j$d6@@N#Z9t3DBG4I1hQ#x=Z1@GVu%krvZChu#aT8J)K{_Z?yT7V9tH zPSE}3QwBNgV#{t6f5=#C8PTM23u}M_pFnzI8h8WtDqL45?nPE?JY$}db%`>e;c3XM ztopg)e35-@;^EL0dX;R%h73+2v6mmo>p+j=4U*0#JL8WaJT1*}l4_+Y5>v^4^d#BJ zfAA5lLs#(#sumy2gj5?JN`tn^hQwXzEK80E`?D+#Li0aSryh*BzvfAug2NGXrO3M~aCYHcV zw-LN6IvDE|eYa`-$MFFiXmeqj2-p)G$DZ8aUq=ZarCu(73gS$a6g#LpdzObTBfg9OWK?Ag@lCYMe#5?1 z*(dl_o3{?Oj46p%3gJGeDUVMX%mm<$!rZ$@4(D8O@wYM#Cvwv{j5^ZrAaI)th8 z8lKW=iBBA)*+|lgJ&1C_sS}`l8tsU5zy{z9`4#uEn9H`blp8(fMEC3I zo#YKZ9u?sO0gH~A(!l(|3oup02`j)bL-Rl%dFJB;^AKgNhcscg885E#S1wHFlUyON z3}xz}&o8vWFyPlLrNQV>aDv9MD&M)iJBidUk?uW0gTwpr2H6VhG99pO#HumR#Ll!! zF#5vjTG}H8S9THCtNl_%2z*Hx)1;3Z@jo}%hLVHKDSLl|`4wX31t>AE7(OfiEAjdX zj?C0dsa)|60=&vu!cfgEz1tcIkuDnrp|ML*ZM%U6TS`DvmH##(;1nA2Gd1;B{9O=Z z@H|haJs+WhtQN|`fesVUbWQ?M2cJ33wEeTprwB6AR#p#$xAlE&S0M~}4YkpT3>obd zNq+fBpWlxQM)9Kj94N&w7mD`RNu)Az@nh*L%V2`$1#6v;2I)f2?*B()ZKg~$)k6cf z0zV~Pxu|f?=}oxYzhML>Pem`rOz}wrF>NEQZ}HDp{|A|9y~bhZEZBi?Zp`!#soLbs zdCnO!&QTYCL<|1y&<0ybbVd0`q0yO!vinVF~E9(n@g|3>L=VE0k{K+ zbhxrYC3u$>&0cE?3-#R!+;MB1ANy!1Nuw_M{3l!Gw29z@g28Sk~V>a;Y@LHxBf;*^#0dQUMIqYgG7PSMGRj&DVDOdO*Ay zp3Z3n;D-ke*`mO_U7&70$+wwO_g2rQDO=m~_*8UMb^*_?>tNr7gM~=<488e>&tBcN zq|P|pv?tbX2cz?cM9T&0Lt^ryE9y@*M}RbUw@6-xS^CvNP#0%|Es=xdIC5i8WJ@e> zUl(6rCrdGV9N$Fdq9F`lO)OMVItWyR2{Bp)F@nE*eeTP{_+=f@*&&=`+%=)Aq_68w zB>3pvHNbEh=Z~NopoMK6f)^m<`~Xc}n2wLKo`orlK2vF>3WC#=&3w7>%Q}Nb>KrjO zSA{^o3$iJSRnY`d zU1K;`rW6m95FtH1>7_{`Za{H%N>FB_y`nsAJ%A%3P2C*gn~m?|SgA!SF`?FDdfx4H zWDwlLd1Ti*v&km8WoNA_{IA7KYhx9*hy|Ii(k1XIV8675yJm)k^+J~x=Af{FcJCQJ zzZyOCP2-FXHagt-he}gEBnbtbi4HB>9~&Ar1^l0uzkQJUq}_hJ3m68Ts8>O0$;88y z&H;19p5#5REuAK}?(zA|wNv9U?8(KCM%yjq4&=kCC73ykn;?WuYZTNj)J}}#D&j@G zPU;FJDmEAVW2l`$#7N5_VwVD+O{m0M42ilg5U*NR6hBhSFt3aVrYBqU&14b;_VXDD zq&s5fUW4JN9X{jYJmSY>wPy88G@EG&^8o21v@R_3qiv?M)j9aTEi5Ct==5bFN~4*o z2zB-}Zc7(tf3J_7Wo)EMZUsM+tLIh8;XHox*I($W*Lc`r;2)*Pdm9Ue@d|Cww5;~v zAExL06;4J1{mjR}fWKu|@2UHjI*w1pZNwvqhYSn$)Dlhds}@$KQNzt^Q1;R<`Vug? zjgeG7>+|n66u1raV&q=<)e>==dfML=vd;1CjCJ24PSc45!`qu?_B}|G-Y_#B1DW9L zM2GHGtaW;9QBBcG;}j<<-6F1Ax7LKbFrT7da*%fJ`~*_*^5O=vLvguai9!s2gj8!Z z^@JV~1m+WWSwG>OauFx6=r)2GJP52`4wU0vUarhENo;QLYk$!!j=Qu=BtKE-x!i{q zJ%*M@cI2nXZz7D#!~jP2#P81H4hkXbZ*|8Ni4==7#Q0!hFcwl+)REGT5lOsb(M~HXSd-enhu|3j7EWAHQ+5WAzrhp&CxJRkG>ClA zZ^wdLFsY=dx)$PUE1W*WwW_J#)O`yM0YM!1jYy4|YY;;{d1ixq`Aci&0X8iXe}k?> zBl{#5ioajKI(t9wKA*2rvjQ-`zG82BzxFrXcfapSZwCCEm(MD5|GezF_fksEIT2-@ zK#%FGCJe-D7iDuV4soVeFaaU7Lq|5=7@}6A&O$fyNmA7jhGYA@g%bjp|G?j5=IxF( z!ziYu#<)>K>z1wpV9QujC#M z>`Qg3@ELY|=kWh(Aze>bh81RttV4(1)?<#ylSM?Z$3 zBq~!#g?`k*#2%pAt}k}rd@fE(H2qQKX;G6K?~hi1YgyceJOcS=c-ohTZZ4h-iL58K z?5Nh|xVBK2)$()}-3DGCdfpR|29u~w*xN3%|MQPBa(}ASaiER5G`kPMy$18OmC#ig z*k+bLTG(zmE9gmM0w)jyU5rN;iAY+zVLxUdY)eQ6IPx+w-yoT_XxX<2yw@!H*axf3 zU$rwY)$_~52Mw%oR<6VC-5gw-UF|bYKIC|AV+ChM(yaZH#~~<=YP2w4>wKqZCaEtz zC$Ezn5=3``b=VF4-l3~BZ#Tw#@Jf{F1#w?jE_9QcG=Bov|I?&?9RG-tF}5o4$mGkG zDcJ6%KH95lYKmLiEeOfET|k7F$>m~6?FP*P6|rqNxwublEe0djfHAiw2q-}(mPZR# z!qV~aR+rfJE3t8!2k94q7!AP?sMgF@|7~JKp+V5%{A?7L7h?j=^_Z6t-f7papWQWJ zIaATKLY(l2Bnp7AOTTb?Gs>q94N}hIQPbK7y`ruvG}?Hoz1)uo`)7`Lk0t|XBW^ON zAVyPHuTV_eYa}fU@j2)+z|L`ARvE7*t86Siyqr-4yTSJv?g~V-S9kdFpIkyk69X++ zc(Q~IIKg~A)V79Qf@Ewib7XahI-v+mB}B06KB|<@oxu7I3elU-KNiyacGvf%hwa_e z39huym!P0ZwWxZv&F)`}S2s@VBIHgHq!mthz*Tc24Vh8HNp3w#EWWr<=Vdi$?{OKq zC=yRgnsVCc7n{t=I4icP5DYrCw%x&{7l(-(!fcCUmePhdSZZ!h%jn=8e55De=Tj!y zQ}IE*J%G2R2nk)Lx|wbDjF)@{@m_=#ci&&?uxA61EW7jgkAS4FmKs)X&JiE*Y({4X zUh2b1MYp(;pY)cxg5~v6RGd1k(w#H_#^_gl>?vO)=gV zPDNdt{C>{jz^$SPjKy^<=Xo@yWw;h@=Xie~;SU*d z0mL{=W~J&)C3~c3lELfLp?FEFjruF8&0T(wROfR4FmDS-x^EA=jD`4f$^#Z!YY&xq zMJvX56-~eOZ}jYDr5FAM&raLEzGQJ+RE{>FYs|WXgofy_SJe!hT(@{-hS*1%-<%!D z|GN9IMTMU{sGoIh^q{-(T9%F{)a^1!0NAQeMnu_33h4QAXQs8Y9UG%aHVWSDY#ghc z@AgHc67EobVb-s?)bN|T2%MXa&%Mf1qw+b)QEo*NtY}@EQIATXbA-?dvKo*y-hg%E z|NS)^Q{ckbj#Hc1V;<-Jsf}}ZfP2FBTOnI_-H0n7-N|6}0*|&**{=3**}g`S6fiS! zBr+GSle^lcZg=^$t#aOWZ#&xKNtOKW$Ojn@V`WK&%fFh3`ZD9TC#XDG^>d#!U9`LT zt0dF7dKA;TA6vX7NWD?Ve#fGFi)1S*3dMgLOE~yl$AZI-PsP>*G*Gn9)VRNXRB<@e zB?D1_1Ba6-`#Hw>un;C!z2|0d9}p39BZM4;nYdvXE#7wt4LiiyVJDOP7rOsq?g`o7 zRFZHtXvBpz6s_;!(HBmdDSgYo==NFhgHMUo za|9qqP(P-l72T@bHMjjyo#kNUIX!x*$-6YYBz1=>Q9*-6JD>+W0dp9{yl^eh--|Ws zky)rYw+3h1cG|3_Zul|L!^=&opyOd4p#Jd&Q+NNRtmivW+*EI+{vn7w>nt{>FIj** zFs3I-GQSXy^PdCQR}2&MW&o%7=u~p#;EhMga)0G^U5rbXoDj?eW-9}3bT9-vcV!@g z7*8`R?Fhnt9(0%rxQ4}1seA)RJ+$9XOv_PR0PT{#;&-fw`mbo0Z*`n7rEEpJGIiNj zQrEiHQkULyaaqDeU}voP;R@u7ZoK$kL-Su7&RQoVH%@SpHrO$-wr>lh;NGHaT*R_H z_iw0Ow8uI%;v5=C@WT$ zZnjSwm!Q(}dfNgDxl(4$4{f zY|O-!p6IK@%r7oQ<#HL#?$6Uvzb$hmRLb=c%`6`Q=)HC6=lf;k&15?p(A-i37&!A> zbVfTr|GdEpSVU+tAtvhF+8*lBMLX8)qchv4+lX!Q)iQK$9Kz5kigOzkUGZg2i@I{e zp4YRd3ERZ%z<->`CJNM=Z@M%YE3JB>VIaoakmWp6*WPu$2O7o5tyk;+OUk)w^nv#~ zdD$`tw&W-NS{zc3m^IdvkmMflUY{CgAx1ZrMZ#>#krF5k3qX2fJW22}iD(Xol;26S z%x1C~P4#WH{5FCOcb*^~?F)4YdNnzNxqTjeO`GWx(3;qrw-pY*+{S1uqekPGKj(@h z$V{>f?Tk;x3L1TT34(TH%kS2;xtpjSiZn(8j7W~Vjv7@{f}{xh8u2!-2T|v$eqHT` zh+YoVJL~dw?Ws6QfSTZ^J)%laF-7nr6ahmESF-Nh?^4xXA$y3fi zuT4?(_SX*i+ZFVm)1j0(GjIf|^L*z3-`(bpa4q-OH#YIPQKDV$-XRcILrq8PQUOE* zr15h4r)k)Y1g%gw#hg;NS}`hU^J4rV#5s(X&~XJ(-jvDa7xj)GWFN=lDTBPS|EsO9 zfQdB9vc}z^ac$h)t#Nm2+}+(NXlUFEcXxMp*Tx%ncX#-i-G66iCR<4*?^fQqxq12W zRdU`r_p;(;sD)l!WQ~&OAYNIa3y!ov1c#wVpLvR}p8ZA%hh}&JZ|&XhC^j}`%Z~?` z#E}a#1FpKtydP_1(GF($XU5uW`#x!^DonbMu145vLC@C$D(9sIAHsYvu+A zbdE_kvW#I5c5N*G^3nzxWEqN+JUivBE;XqzfMOmKbgkdw73IOoG7LhzPu{Ljm<)xC zfaw;}AbcHU@E9v1x85q#Cd%KI#Fzvvv6j<2TW2sH`>kWG{UQV@GT_%RHssnAp>$WM z=2|Th>~V=A<&@^CW3J}iPE||Oovf?()Tclb93}zf^r-Bcz1X_qXD+xNcyVf%;7I^D zKrS?`AP6}mbeO_4S8w_AAPi3+cisD!I`w+J8GJTqhyq4pM&TZ2%(9!n>MiqR{21@u z^%{{X)+X`NGMn8+umu_699Om(IjE$^{+5H^zFeK%U|`TI&3Xbt!4wCKucUXvN&QVz zN^Q!MU1dXVc)L0-1*~Ou)ROt=bi}>@fRXsmtUN=Yi2!-vku5kTK^8L|-!&r1i**0; z_x&)pYR-AD-hEoM4ETK``HxHi zeR?r>>SYp)N2IN`Z0Ey@lb?$hU@P91pASSrOAHDrY8r<{B73s?=5ooI48~_bjD#3* z+P|vPQxq+k(PQet;phr-;CnREbJmsEEQu$QlifU8xK=6zB2|YAwPPGv+K!--pp#+B zayS9P%!JB))zutp)0t>LxGMXnh3C%VyAX&x)ZCdg{(2KJ1*d;FFSipXV4xMF&PdsD zjlRw#&+vBN?(~$d`2}CpwZ2P8W)A{5V?B*+=_I8atK3OGA5HR8M*R@_==$)6jfoWX z)ZI9A558d9qWMFtp+X#vzl39$3Q0Z~#{nLFv^Ja^Nu$H)eP5y)6Omer9MlHtk9@(j zpE-@ut1c#>BjAR4ynVNF$;SEwLu8~{Z*i7)>cq1+=`u*PR|Y=bF{`> zT6joaPH;Jqa?9YoU9A+?wqde}YBC;q0vbCSkwA@%P)C=U?Zu589sR;Ut~aEXn1XD5 zNnM@468ab{Nrf8?Ftre?$TsBhXc(fnSZ&fbh{uD4g|fCwGt7+tBHaM;kBtksQY63p zPML$POF^>4fWJeP@_bg2P`))W9%rSB9eq5Q+v%mYrBa;=?rux>R@PS8@~Tt5naC!c z32j9*I@@si+!tGj#1y9z*KbS|_Pz?OS$pnz#W&OFc2EE&t>Qgy6?z7Y41Kxyum6Df zDTrsvV4Pnug0_CJFKwKzQ_UtUnVp(K(ko1)6InNB1q~3mRJ#Ov+|2m`locOe`l?rB zCdJH`b~G++1-vq|eB!#d;-f(uWG=vz*@uUkKmSL6^8e*0*s4je7hjUZPEZgKB#`=Z zQy9?ywst<7ef$3_G>hK{s8vZn z3feggP|j;qB?>GF>Mv{%u-}8dOYF#)s8*Cqi;H(B2&tFsPIMU2->~xwK3K9SBH}Kf zVLHF*s~3waQ8(Dla&O%Bvt6%Z4ZSf{)An1l6N)ocz@{hHI4f3~f#wkU2^U$Vss_=< zw&h^x%r!`{XJ^A}Xvd^YX0v8DcM~2s^V0c8pe45chn-AvUg}u8z44~_+pvfPjo3A+iL>hKc zv^{%%dE0kA{t>Fyx1Ai4LoFuR|APbrp1!M-CZ8gQI$eit!a4t!@gO|WVtF)8y)z>^ zt@~-MHHnYH$S4;ZKD4+l_F8#K>VU+1hSeoWp6`*g5`ffEcTw%6b>Q`h;wXCjGo(Z z*g%8|WOqy)`Pgj;uzNo?o3bDQ%mf8U_E%_zQp(RaYLXu~x$$z*xCc?yxTCutRy4n% zF)f3S{nZ*KB+1crlL^pw#*EK}Mob@~nlK*5AwS(qMPSK+2v4BnT>g;rfg%*xt;w%= zgkuo&wN>!iB|$d^yqt4VE+*#*>YhzxGFJ6^nUPIT<==-9gaUhO2NFY?C3jR6#0u} zlI;hF%hbo}9DF~QbqVS6?(MGxd<ac zP4K`Eh%+5!#7{v+NGNjz81ndgPE>1KV~Uqs*)u z@|*kz4}(`cqFv|79JC^+veml4A|y_n`lz4zam$Mp%_LY7)%H!PLlb+lV#aQ~^YadA zW7-J?RkqNwHbZHYD&*4ol~@1-`Xg?y7RNTC9jvvBy#FUEPsApmC6<$)wA8oGHt?#9mToAt4~Y~H{@m`v_ZYLNxF8i zU|5NrqzgB%_k;&n`AEW%xw2x7Hc9AYCK@a>HigZ&R@W1VEX{egiH5Am*$1nij{7_f zl6duX#XM_Jh?8ApPL$GnyP?0t=|mMvZi?(oD%&Y?d3WI~jHTL^!y-TvtCXKUq>Jc^ z?Y{6Zyqi(pr?w%0tfA zT!>9b^&4i62}Mljd9}iX+YklD*%*ww^oKdQ#T;CS zI+eR^m~+|LU#lODnP}$>&%BY{nm7ICxB){I6*z`>nc-bT`J=s~HprzOUhs!A zt(zW_i$3=`7-DB>>Ikp~dyO zidCuNf{p!E8d@Ye4V5<$9Kytr@JIO<4nnUIZ0dI?`1!Nee#}(QEhy$Af5@Lo6DUEv8rT|~Ir4sN~v<=Wj$$U?c{PlKP3o2=XD8zrFt?cZv2 zNfa{ISf~LWJ3@N(5W*k${RGPRzyb>n4?aU4A*!$fCP5)Z6LismI&Pu(m1h_89RFt} zcnY-q`<7?^Z4LoN@<3cd43x&$#H6qk@<_f z&a|GtpIfh{FctzqI8TKY7WGd6V{A|;WAeeEWNKVuRpj4}`7Y?sY*4^h?4;NbqJ^?7 z^j(E!rSxAkpr(1&d?tN-BN zW8j)nF$A@GvO@EP&#OlwfBZ{x@EZToD>2j9~`dXI6M{E8rN)WilJ@63FE)|Dw z%Qx6&Gcj00o$ukxtBwuO5O%TCGTdRV{|y~kGiRVspoarRBZRW!SxGHa01w)F8>HMZ&_+~rNK7e1^yZK+hF?fm7UBK#b8q`NmrpBr z;*xXDHi_?0c*0z>G)TgM=cCGP1wFsK-kf!~%5@>V95p*T_o%I_P zdL#_5%KcgW9TYVIuy#R|O*Te5bh^0$+(BWe6xdq7{Ik_t*~eMGd6#pX2~Ro^cC*2F zt2PA`#OfQXg(mDQ+9BTZOl0mdJRSzPjswKS%)>~YiO0pzZYW#f3e=u+8lWV0v!6^V zuK6PDU_k>w{#G^VnYdxk!{a0snUl%;lbn6}(U+unr*EwNA&5^dM&DEh6gZ^p-!w)G zM!Ce&+vGwYQG^Cn&gdW-w10IHTMl%{VCOdZOV`fFh7AH$cilNb6O#VL4zU_iVQt6o ztADXWtED-PvQZTMx_?RX$mlScwTCYIg^yaJ2uuNL_-nFYBe&GZRtgk5W|=zHVJY9Y zxO?_k^Dw+2!WS4ZCCqL4p0RtEe)S1+mAP&veeBVUhYO9}c8>cU^^nm#MJxR|zsb7` zFBs-Oi_ML;a@iqkB0y@p5m0@r0$-qhCMG%wF+0nb2|I`0H6%qngpO6(Z*bqNaWa4% zg)Ik&&Ad*v=#6m zHIJ|yjJP#L75c}|I3;-ZBUmKwb-eJgLEVD6`4A;Z5e-i9ODB55k-z>O=5o20g;UV` zyU4EXS7*^4ByJvZ{`~=?+QLmQ5=hMP1at^{?nK)m%X%lasQ;`M?n{M*heDb~DEctkaR*sd|^>0rW&lMgQN z**`3NxTeJvCRuDn>EMFI6W%mc;D-mUFGux+aFC=~DDGvLY^XuMak`8>A>@D(!bKDR zG`A0^`IWwi7L`x!9x*{YG6|{#Xx>lY=q||8xC@%J6rdCvqnwm8B#!=IV`~}^^m{s$ zz&YiB(rA+MRYSn6enpx>ju!=p_ha1mtQBtuB7#-O^nFKYh?(V39$1*An}V4gh*m|x zdIXT)&(YH!l8lha{`GN8Z)l4!rRBt=pr!TcLV8V+M)gNJx#>;Hz8R% z5DuE5AExDZz}{Y8d>DLh&BqO3zFe$7&Q8Jl5w(Z6R^T<0`tzloj)S}RzSgIm-reSH zux=HJbO=Zcm(=fYnhZokWRjtYNY$G5!;0OyYo`Otka!Wv8rxQ^rv-gi7(&&^HJ)LQ zP9cphn+hAGBth-gQCgUbmt3mO7>u)HknEdE*;*e#QYzCQ z75#>V><%otfJ>n{o^!~#$rW1eI1#UbVQmM*e# z?OUA+t+G1`-Ik|0kWjEC#! zRnUZ=u%0di-5Uub@FywN5`W`d`)Cw;aeb|Q-mv-kcG4LoQ9T!-aD$~YOXBY~y3QZI z_ZR%}zk3KH{j-VivBU3E&HBSgdssk?Pafs6m1xuCk%34C1$>qTa+&N_cA3gORZ3lf z8Pyy}vh*@{WUmx^Huo(icf1(Ug5c`l>4CL@k^-lVD*|9F*qA5-mFyQb+;)UCIdtR! zXh^JG7}u(hJYYSMGDC9vC!7>Y9eHb3%5g(}hO-vG)O?ZS)NU`U-Uav3NB}^bv=p<> zdNw&oYyGPAHrU2*HaK}sS{7z_x6EpFFmv%0o%#Ab>tnUIJlMPQ$-_2mp<*v~I;6f_ zUY3LKt5Zp9h7|+}3up(4f_hBT@fsToUgrruf?fuE#DcLmV&zm^=BdUwiQ?|3TA?E> z#>WDV6yw;LYO>8@2%!fpW*mS??9ZWQ+M9joOS#Z|x({f!MK#hiX68@zmX0khdN~#w zCZ#Wr{mh%Q7@hb!2pz9ZQ+O7&!Tqny4y$ z-yv6GyEbG*yTbhjMQ`49`?TI=O9UAfwjPn(itZzK6)#OaK_kKTjh%!ftY>q3%$_e; z_w^9ej428YBVzAw2Dtbd=jR`ZOtB=WnJ zUqgkvX(F+~!}pM7j>Q93+W69N@4?`8^0bssU@c=%o3ZI7E-V(58s?-e2~VZ9%HyxTY+ zYa(OlM{2#YDBF3mQqU)s7HmsSI5Kp%haV6jSTC!;Ar(y-aQT8IaT;&w z)|i%*X>z{Y^D;@z6$~NiYM#;FHh5OQt;#r8(x`vRK~rn|5g03;{x*kfCFuN&{YSMc z{EU^|aYjo|jg>C1F0jmI1A#P)Lk00_K?C@^NOBX}&SKnt!EJV0YFuTXxq9OS@1~x& zfMza!bz%a*Rgsh`eouQ*UEVBv1Lf|}^Mn`}<;@(M#I4XcVdy5y0vFOEww}df0~vDr zjb$<9cKOoEdyNdE{6t`yuCw#eJW#{i=t>*ZFMVpTqs?W`(NEf974k0GMO6h~8{1r! ze2}39eG>-DdV@q|XB^YNC|*2e!P#eaGdvdmqZ;owT|UP zHY57lOFMItcE^UBAJ{H3ze#oJ{%4PdD=f4(q}o3L79(NL)?LB`-%JbfF) zU+4+1_2?U-g)yP1iyXafi;!OVm0q0WjFTSBvX1go@J&;a?o)I6M^_tGc}NrfHc37} zl(Ma+l7XCVe2fBW>jRM8U@9pRL7cj|Gl7FxlZ5ADr?D#kLlneiBB(nph>{MyXhji0mDmh>iKQ5i zt;*mJ4~;Rf#PadXZ(Q|rX^EBm6aJkHbS4-BWb=IUs+j(K(~wjeWm2afivu@+jvT_b zjaXj|^R~65c0WpgY}nHh{E8F7VaM9k(MM&ujciMu<3S~wM;C@Ru=Gal7mS6h&jC_M z!o6utmZpOf+#q<`1I*?!jfc1bbzMC3@hrSHNnRc-U00dx_Y}R{a*#jMrD#s z3=&dh^Oo{e{dauk(o zjXWnxJ9OM50SW{p#R%w-MGQzx?!ee(?3wCWM`>xdq)auAW;?$x z%*O^z!yPAuhdI9kT&@_PDYuMlwH)MikO>LXT2?N6Jd9U9BC8Nh!p2a+uV4ii=@X-Q z*hmICz8X=8s~zsVx8E)zFPw0{jKChdd6f)zEGIzhNMNA;q7V*BZd@^{{UiRTx4$2< zbqRn?l#jY=F~%jt<}X&@Br~Mv-Mtpz$S@SeHUM#zwn*eR2 zA1t3C9WqasxuV6hodD89dL^+pThs$xmyFNg~}-mpE7a(!BhNnNrfhfG?6v9 z$hMWRm=%4(Scr_PC?J$Zl1>D>3q3eF`4nK7q!IaiTAkgv1Nejg%6dfp6sc-;8enbt zxE@qxAayOEUmId0D*iX7pwvZ^nCteH?$wB8<~WX9j;q6&p2#;CQr5JyJiSv!K!HUcK`O&$*=YeS`lGaeAuKr6rQs5`!x35P4d-G4p?Y|W)2+n5;kc_$zU zdQA{V&8$u$lJUThvj71`d~YFY$`*nU<_i^`*p}B8-VDt82-aU$*|yq%n*^YyT}DqE z|-LP!FmIG#rW4_-#gq^Lmepv?yLvMXgqV6W0BuKp! zd})%FInMAREDPH>E#6=aO8CVvUWp-yqm~;kcR}uma1dtJz)8Yq&Yb`JDAX)4nFlbe zRA|YKn#`~Au4~x9fE`@xPy&*IGn+vBpY@TOew{57xAR2{5Z24cOz0V=yeIr9&gDEc z*o#vmi5U25=vzk<3+E)jN@ud?m>XIzD?0`1Kxn3+IF_M&&_q8o3)ae}cn&84adrv% z{Lp@u=CPUYcSx$y%LF)}YHdc{0THP?A)pO|P#s_i?i2^b0J#)T zYoeXloL04+vXuk83&Vn0;!sg>IOjq(R42rOU6LL&fn3UZy>AZseSB8p=Q(vNxM_J;NdmpBdUqa?J7CZ9vKapxm)k(Zv)RzF zitn3WJFUFd3XiXJmLlMrUwUszPM`M|{x2?tv zG-@_Cfr=zCFszgPG3aPN2V43SFT|_=cC+={Tl^Y#;&Y2z%B5W82pN1=@`Qx;S9{!- zCq4-^ElirTZ--)p)+4H=G36$Hi7!7*g3J5##u{Ng=RL_}%I5*YEeN4^m70VQ*GD<; zG|;4~H@h-a-(~75rT=WWZ+D9SdcZ^I`3X6H(pC_tJ~*GHDr?*Mr6N7fcGcvx@FBxIgn5-_o>m44dKhdE*a7lUAPMMw*NPJwSt#JILV9yPi~cYyBxHa zuktZkR-=6Byl7Xr|LFKoT*cYn=?xNJ;{;RR$Y><=l^OXp9Tj2qkIk^tZWcP)Qk7T| zY~mbUztwm0JLGT@h4Q2>^quwR?*IL#`1{pU`Y-iKVE`5gNB|a4yMPcN_tTsWUv^$k zU9%JFi3FJQ&cxyH~Z1M zn`kq`*?g+=uyuMOmHTT2v@tAFkeHN01OYihKyP#Gsa)qvNjv}RLf$l`nVN_dJmF6F+w<sgforP>VZoRo8o;ENG-{_BfhVp+8jcyeu+dO|5Mg1EI?mj;$#qj;TE zI$MGwKi~J=A#57%jaTGM#=Woy6ZT3PSREeOr*u?D9S3NC6705=S13dsbu}g=664$6 z7lUt?S$}{HuRRiuzbG`$nXJ0RtnjlozFH_2!Z13N%H6qUU=j5@-XUGC$kDmf951cZ zZ`PJ(^9c`{k!1m`%dTS$WC(|w@_0$bA^B8cd1;<#=xs9o)TsoQ;zDiy)=mDiELgDH z2zrDu%LWjdHyckoQxkXQ{Z4nV&MPyS-3*H;`6;H|djQLooiB)rt5|h`=JnDds11?D z?*f+Vd7gmh*Rkem$IF^LS32e!8sRdKT{?TOpT&bE|AtANUuXWyHmxDd32nku>m7^R zw7_}SJ~Zp+23Pw*>{)UsH?EwPYZCK}BhP9?jyzz+fso+>PlWa+R&If(K?%RvISq+T z&?F%ZSq`%;UO&369!t;5+U&43l=g>csxWCnLo1H>^>>a_(RXzWA3M7$qScn;d)VK< z3}6OXC^8X3;kpLy#XElOL}my>kLJP+2|P^{I5c|Q=yR-J8Nt>uphKP$v1k~ zXRZL0Ne(m+F$7wx+mbx}(|%wbLtxE}gA8_$p~ zPvxBy7}T?u60}Z_X+froBJar0KMj z6bnHln38H{^n#i{v5_cBR`;(Y8eW9@-z@>J4pp#)ZgZrJwA4K6kr^xdGV=amLn=Ul zRB5fDVGT&gF=NXCBnh5t`1MrN&#bxhrszRLvEpuVts0ntU*?Ml5DO}AJq6+0x`}zq z97~oTTRHYWyZNAXm(X=r*}w@N@p~)^5UaJtr8^0;dQY%$T>S#-2+?QbEtam%WO4y) zN8WU6nBgiA4fN=gai4s>ACTZXyN>||HCZaD@x6H4WMM~{P$GTLO2ItW!boty#Az`)3Cl(vef0rH3B0Z{DHfyu+SO;cL_IkaNU zL5~M0s42;pUbqiGKd`#Gy6uSiUH>J~5-4O>Z#IFA#IL(;F%*s?PbUn#!QO?*&?Zj) zRx<1^aZg33y0G#J2A7;=kwDH!H>1K7%qtg)k1;TJ+450O&3Jn3`J67J-vY#t0 zMD0n3zv_?1J!Pq}>87C06LUag?G)KEak{L>126F*Z-1+u8uB71UpPfMWSS#m3*+*> zhGZwv;bT^5VAeG*-)`m;20e(1pd-EjIrATb!|Sck!<=S!pyRW838+HBvTNC;nVyMo z3Kz#foCK5>K9WYfX_WPRf)f8K33|admg(cNOG{mdaiu>T+6T;(0a*b4ZsOhP1Kkj( zgu#nDW`Bw6CVo}PcA*^g+CEcpoaKfZF99`*8Dx2g9le@^nzTy3k+|RSb3H?zcU?o_ zunq`9TLEA>F&gnG$#%}ay*;B4+Bg5QSH|>B$qPY$L^Sk${8S7CP-2T2By1oScYJR_v+3Cx5_JfyOESS z^**jKUta%FDh5#f*r9P#(Aib*l#$`SHjt`(4_tIpUpfP57D^vC=slU1mM!ho z$?iVu%ajfL8mkWCY;(J1RNv9Oi~cLhtHg%u=SR1|v6v50%dY#S!(xk5aNCXNt_~(m z*2M>=Ro5BBO5Kx@Pxbr9;8$vB=7bc0^I8b68kths*Hxz1hoh0w{yG;XEz9NUArYRCoM+~5MOnYQvrpQdOL&Js^NBiWlv^*L{F*RztaVAW}4m{lh;~Qlu9ZM z<>j3cA2&b3RnQQ9;~nEUUuMd^_`ZvHF*}X3CjY5b@@Rh6iF<93Ea|DOZ}#S}t^5Qmt!hkv zlfvRiEM^5vZ!i#8CNGx;2J^?#ryO_L2VXs4x6$GjY@K?^OAz67HI681Y82a>9Ceui zJj0p+Z9{J|n2|#~F)s}0=eF&Yyw#!5#<>wBRBDBC%S4ra7az2I$_m6Qs(`Zk#quxDq-fH?tv#9cAkf^0k!3D@nsk zP%ndsfFzw5qf7n@cXtyWFAMi{@!_Awj9W?9%UNY%Kwv}Cz5mK-jp;&Zz*Caj@Bl7v z#VP=!59{FWP}Vcj7*843;;A+Trod0*`vkSEj)s%80e>Ksg|8oZQeK;skbCxo4H9mB&N7=oidTo%KzDRpirOLtF6xTH`pg1%!B_@s73v zL7SwcayK*<)t1p}4WbTPM{CNUcfZ{ep?<)xO{sJn6gLG-S1f<| z@}fOR!*xp5r-oO+UVfFb6*F3+8u|{YlQds^=C2x zzjfDs%e6AYv#YxL8rEqL(abYBn>G|6`+SSE&<+tf&TTOiDMRAUbRx4UyOi`p#I8QhAtUlAAo;MIh?@eP1zlVeLXo3TC%_y~zJ^Ox z_qr=C4ZvaRsAj5rDtq1qnUo}Zk0oG@Z`J+H{}<=GsY2?8oC~`AYWW-_Vu8(kWAb5L zMkD@)vN|XxditfEic{=?*oSUzB;sOlQ~9lBW71uTWgK0Kb0SJ`J&l7+R^vWUERlEPStY>u20yLIB@X3m%7SrM5x*U?BZ_24(#$x} z=R0G>`P)ybfFNEY{(@+<8_w@8?IO_A#UZ5JjAME3@;non4KVI9k?K$Vc3{P3fBTa{ zVs4)9U(%Kz5ZvKawY6w9j!$Muwinyzzx7d*`};V*Uu6Lgl5#er(QbbN?h{5$-1%QJ zQu$5dxKdAv+ZV^Wz&ZouY!Qk#_kJW5(}qo?#V`+Dg>J^r%Ne6!R)_n>ny9- zV>dH)8_l%#0R%o5!hDI~(dU zr@GG3iFhzMb`WzVJ*+1-LtZUk#Yx{(Q4FD<-w{^kTMy2OVU> zF0j44ec#7+QAAYVcHjfB1tk0PAQefkX{9=r=xf55FIiEc7RfuJN8^>!6y}TUjN|-K zI-Pl}gd5DrO-rg;GuvmB@gN`LR_dkP_(5{`_b#l(!0NMGu#Q6#aOfB9Q7!=29Uoii zXs6O^muf#et6V92N`z6SYkG|=f4mtQcRle|e#RTk&=5-5AU35b55hz1+Xfc_5;(c0E5UKRvziiAyF%AvcCIAMFXg ztZdCNxA^grbOKQjz$-0v%L_eogzQwo7HKH*&`tDhTA8ZJ6%zTo%o0G0i7I0W4?C996<`4@2L zKi~*k=1KVPmyM^)8q=)UJNKiTI8^*t5ifcMZ@c-Uh0pX(S+{STqNpVgVqMSJxU8v( zGV>lcqE|&ea?0$PfF(<^L%Dg*Vp{IFU3|T94=cg|S!(GMbuNxLs^RT-$H#OdO5c$0 zXTVY=X+G0U05ei)U!T;%+b(vlA2)$qqBOpg0xO>XFXUFpFxm8hDYA4}K~EqrEgP$BTLL{55vW8>g}RX zbuddkHx=*B(!+8)a|UcMQ1{#HWTnC2dh;$GJT=7>V0Tb)t0; z?>%*5L5m|L`ftaTnpRO*HK~~F0I=0RaYW6DL?e! zxSJaJ@PjpD`Bl$k^Pv8FryD%f(_h?7wPIv+Du6y;=_v!X99yeyWme=fw=cCR7^lUD z@^DW&0R;=em_m2F`z1w3$;jV+YmC{}n8fsP6e(!?@^vR+0C@q^3IfW0lP?>7qTW={ z_X#Ryd0T%h5gT(Dp`2*9+cH*Su4!7-9P2QjBZ-I-y;n7yPeWI@+Jn?-kyHlc?rvQc=nNDS(5wYA~#;<^2i>QKwjP&6)YNl_Jp zy_(t!WdihDC?)wbRH-q6of%Z^vABP@KETTl2cgrIDLm*`@34*Cfj*lb>#3IS`zppZ zx)A!&{sP7pown_qrGXuiU0aV)u8hJdHQ;NypNpTfYx#^^(p)Aw^h6Wwo#d*Y8!2CR zWDE({4PL+h$yR}76I%RtDbP{LHO!`6TP(MsVF@KbNgZr1OLb$pVAFZA8Clvgq_L7L z;*)V#uhb-Pt4B)~#b zF3P9%mvW3iFch?RR2C9E*xX1j)|*#f+NxvZ!s6r88>B-Q{CRb#s9e2pAtSVgwu^KG zsOH0$<{MZ=@tQ2m6tpu8`?}anQm@-WdW)T4_0!k0R9iNy{c0Gw(wqgYlhS5p<_Dye z>y2~Y{uEO&cTn{J%G$De6mar>SrLl+zlBR+k@l6Dd6PND&O!=1iM|~ zx@qnS)f{}49#;y*kA9>Xgj6C}q5Hxd_YGHf@QTV+LxHP07QAnEl4GH9GaXsc$)Q?M zBFw=A5v+O<<~VBdIz~IXP3`J{mQgh1aAZ#ai{ngTT_-nwPzJPmQvql41^}CV=Ykg^ ziDdy^hV@~>*j5L%ri~!u zU{Nl$naL5*5_+8RE|*7R_mk^yRuPDUYpA=kj0Nm%xstcn(-i=rAU!;NeF_jAFaKvo z3|_#6|{qQh*Aq3V{y4iz=d%YPfOE@D5Y_W$? z6W`%hHUr*jgOtcZsTOsFu;h6YBZnPCo^t)7&$*_c==l=`RRiSYJas;W^HTMr}-h9U)~Ro9d|P1njuz>U?9^5RG9L z4`@mA*f2jl)Fw#~cE-gc-4J;%WHX`qaoOLygC!LIjRy#}7wJ>*!vEZDc#l_wi+N&g4bQ{N>XBv<@$PEx zWCW{4%yN)r^^*012hdEigv!I6uRCXGCh`{NVPc3j9g5k|NQ>U`uvWN95)WiZUE(DK z3GDqdegYT6D%dZ%?s*Ad%r(QH+t_I4=Wjn`*jrlN%9FcoJs8t9k91!zq^CNO6fggM z7)R=`(So6}0i~`I2%KEtF4XCk4k?ezlvb0Kf6+8h7$tF{2gr%CIV{@VYrfan?U`m> ze+}nVi-V2K&sFEGNQ9QhIsqSz3G83Sd8Dov{sYdfD)z?~vTp5^(Wuhiol3V+PQpL~ z)Gn05zgk7tTsp<+A!}YS(tCW{^HSxWf|1F@p_E%Pr*P0kfuG6S<<5y5QCM2%H-3kR zbk-;kD4k~I4=^aYlz4W;xntBQQ}2R`{q^+7t3&tFIjJtsJhc)RH}Bi>Ze=g2pv5X3 z!GR%QyvZ!Ev!p&eF4&;^)7JWx#@zY+Ty28SNk5I~c2x4v%ElLb-?gb37o@7hiTlMh zTTa-=c;_6*Is)l)G-x;MDVhGelOIdG%|9v5rSa(^2H@$oECQ1|;zVN5HXrr6Q>O^Y zX^b!5N=*0RX$^M|++`EpnM@x*-rw&{v?U9dbBsUI=S_=y3WwW{l!9~;(-%%Yo{n`^ zfvgIqR~J~40kP*5((F7^Bxk?Jc3%wEeO)$8B2ALTuB5Fj@oc%aR?Y%l!$`FgEbzmW zSrwG@10Zk&&z{y3Zsv33j*#kZUQLWmCaxn4&M%GDbkVxY5m%P5++35W7yPEuD{mEm zg&9~q;{+1PsE-QN#IbPRHceZcBMdQ1b+D1NQ(V=-lUzAE$sH&f2PG&?W9H3lOw&9l#y&N+p>68$@w4-6|{g!l)m54*4Y;r(}PU4#pm`4Xuq z8albCSQt8(GBX%CIVj42f?R+(TO#c`7zl4RTARxi&{|RP_`Ue=eSAs+IkE8ov zQNe$1Yy#q!5)%LWbrJ{&_P;wT3wKOwxbv6~Tx3PC(`OnnAf1rdqfr@4Sivn})1V;Qz rOj7zES=j&2EbE;>&~hS7)GiPZ6cBMIQ&SNkQDRYhV^>>KJD2|lo>=_k delta 26927 zcmY&HRR! z))f$dk}N0~8W0c=6cDaco5)i)RFMxX5Rkh)5D?sdSuqC_H#;+XR|Zcz+iQFqm#oeQ zmq*(6p9LQa1`fqwR_R$XtHpCU=S+(84*7q`@u=Fkd;z@E@6R5gNQ{AASSW`{z5|Iu z8)fbqT@&+!|I%P@Fduw3-C}p6O!n!+@fHCswx|1V*F5QuADe1d1{$P67%_?ASw`V|?Z z<4G_pFIaz3eU`NBN`E4US+=lrMDJ4j5Jh~}U8{+~D22l&TS=^~os+@%*QeQ%#|y-` zhx%&|14bgLK-=A)p}*gnz5X))A}WYl3w&cfpB93Ma#7phG~ z=HlDaYbjGHrIo1}e{C=Z#(u=}gOz-2DlBlJc#}s_A1j>`svA`8-HPloRbjLpBoghq zTGDVJR|pYWZUthuOml?-4iQ>ir0Cybk}=_bf4R|G?!63m=wCZVQzv_ptZ^cBY;j^c zK`Pw@hfLilK%2O$Nf^8{+6Cx4{UjWNOQaW~&;hcFW&44r0$+3P9u$2Lw|=t> z#qHfjS7Ha0b$tY1lxSP}{JI(iGVSX00w7y@s4m+rcx-ssKqWa}}}%3vctQujHz3j+K0f_>5lD8qk#bHd38^ z6s4EQt<@F$asq`}Y5>Gac7qk2D{gpwTKY&EyhXc*c3t^sHt(l1Wu@maT!r^@w5qQ! zhjgPB(uc7_LXWwCN(C@dk=>Da!KK0c(?@~PTs5aM^z#vkgCnE%9*XM{ij#Q{SiXVg zXNfO91E#`?_wBQO4I#jmQh5Rr^z%4VrY5Z4;4hGbNJQgb(gPGq9{&JWZKHad5=qaS zbjm)JCnIWJ=gyIWN=FfFFw7UJ2pG2fpYCT}V*hV*=1p>MwF$^-cg3@WK(cE@^X&~x zcPLtLu`NPGeps1IGT!4N4GEkfmR0vMt}2zKCc`V|E6CPPD(iuvltQLIibhH60L`3> zARw$fk8I2@bbf!0@%bAS{7T&8>ZM5L8c`?xx!Gu z23#;YA5Xr~B6@z^i~={BfAZ@N*O?5@16#tM4QSAz7ljSzJ>)2{##K1HM9+Ac-Yqb4@bbxtIM`3?+Bhpd!LE9!DXAA^ zJqfHrF1mRK1UDC)Z%kfKy8I3H6U)2cp#Pw*`WQ*<7s2GwN;4S%Q9MJ#y;9(IERXi` zdB$-Yw2O2ioOhlQE}J z{;H?U()8iYx8+Mj)k7pVWS&c|M?FSA#jrBnrvu<83-3m3<30+f2b9vUW);&7d3a4? z$(;ViS~^7eN_e*kBe_)0NO`Do9S_BJvm=LNlU3&q(0Q&dQi( zBafjr{}H9~*tlNNIT6~Y+@s#cA59`{{F*d-_QgRISobVe!9O6eH6d-Sz%e5%+>zO0Jio$4$%tUVmqhrvN^RRE?G@f4%L_ z)A|MsS**y=)blURc}aG&3d6J1i)EI-1Xd!i0Q<39&^$5 zjPCv%;ba^yE-^aM{h~_ghh(+izl98rKB9^;OKiI5Nf*@hNxwtlC$MkYJ13<0;7&FR zzW)S zv(Z#G*7~VrbI7n(*O8N2=+_n8kS)t#O9#1d@?zW=%j(AEn;J_MS50dv)%{uAg_`RP ziZF{BZ_klYGW2^l@}d&A&6!re7IvS9jBrC6niw^Jv|7l{){1RCZ9qX=OORTYP)m#- z?P|)I-PNXR%A16p9L@N7ziT#feF<`Q?FysnI2$-oU4jk-NbmMNwq|8_xV`UsCvgV} zZ;%x%sk7E$jM$O0ouT;A-)>{tLVq|Kd=MW7Z$Cnup1$nKP}xAk>KI5g8;7?RB5d71 z_i|)_E?m6vDDi5lv*{>JdeI(%p2A7t%tV?_!(!7%%GHg%gu9B}}UBwB2gfzR#f=S{B!RA7)B$b{OPc?R91x|4?Y!=JUbfFKY3Jv( z!7gFk9?t^MckH%WB`d5Xwb!&3my8Ae)CY~Lja#9e5~W>;-{QJL#xWC_mjjZg73D*B z=Ch>@4#V~sALFU{skd~I)h!6irxhnaB#-AC#*U7pd|utJVC%4tZ)t(4A>RT`y$4lU zeyTG~Fi1XQ>eFvl-wht{ksGbolT(WlCA@Y12U>hx-g2;0!HDVARZSmmUbV&Nb+|i) zeVktp_8uhuN$q|IBXPA;xt%xdi!fx)#Vgl)yn^M=F!oloBCEUQ%0G@!R~&c%iWLj~ zG4^dE7(yOZ`MsygSD&xB190cH10rYjY+EIN+xdN$nxuxC!GR_UqkZ}d;lwcuPn++Nr^t@efnzYeGDR}t z3yUcWn^e12c^RExphcTMI&c4E@*h$RLH`=HR1{b`J9oOJW5GRAJe%trwJh&YcaGVh z;-+}@P_%}EdrLPE_znFQgZ(UThWvb{c|iU`{{Ops69(Kc2-yGL;+u962;lxF0>({) z|DPzE$_E(!e^;;F$9~OFfq+<&$Y_MYwX{-(&6BKY8h|B}@My6p9)qLlw(rk8H%UK> z5@_c^80g!cS1^r!|Dm{xG``bZO{sV4Z~r7|(=q@AIHNi)F`RNMzcs=%8-mS2DnIxg zykr0FDAm5S7Pq->1;(7Kt*(D!dKY5MUKySJ=EYIkNNYjE%yvOJL00vXAJo_PCtHyt zLjwk>3G_fgqX0qSu#hEJYEIQ(%f7eUvw6R7^WQ(CCd34U@W1cWp$DJ{D`1yRV(ck! zar6M+dQ~P4FP-d~c}f$puBrQ})#}&fb-YSG&Xmte9AD-Kk#sqh9g9no7+;;_%@Lo) z>7^^g=-f1w#0m-?iid><08zEKT8=f4^axoIk+#kCWhRH>>9@gQ0IA5+}QOgsib<;tSRcX zK0~V6AEk*Ve(nfjQvRVn73ZNf=E!x>tB3-xfM?NXTF&TpK~e$8M+RooDjvfj%fXe^ znV^5~*@1MP?d~I-UGi_`SWPZFSqDiW^thVXD8v2RW*#}#ub}j&Y+dmJ%AGa)*-$^} zz9ZO@-BK^cui(@DF$o&WK?tSVL->Ze9^1;As6Y>9Kl1UHSpO_ueEt9=wh~erk9i&Sf7rh;k2Hq77u$Pg4cVsxU zgxTTar-Z!$wJo|)`Pns#|7J_wG^64^1{-A8!m@qtz&wvcDNs7BZHU?<1pUBr|9%S# zzBk3b`-}NEaIVexD<*J=tY*&97Bj58RkQXT4+quJgCk{GPs>pN482AI<2HNI6`g?N zJZuF~a;5NWYJok&um5RRPqiLgv4;Iawi#W+j8Zq;)(fv^-$7Wt)~WME0q*MJp4mtQ z<$|Y*uaPEjM3Q4b;YL5YEujceX9AU$cu0GbKYC(ed&37>^ly$OGZOtCk=(;NCB%-FD|H6moo>gALzlt?c_?%9^4lv2?_~hk76mE4SEpol_s-Sl1#<; zkr8+n$)vJ$=SBqQVO zscD*wq7eIFlG>OjQL*m_OxYcsP9uu?YlGE~Ug8Fi*h=v=JoXRkefiyw`5`(%(2xt@ z1iR{2LKxS7J_F-FD=+jQ^JQ8UMvw4STIkG+%v#}mn&=$WPf49-_bObolpaa)Jz`#~ zuAlb(>V?z)Yg_m}1b3Aml#5pU08+5TxEB=BYXuo@(x+%xxI2cwYclR}<$a6CN>9FlbsKf*e z7aO4Ge%m#|G5N@I7{4^?2P{k;m!}9QzdT2b-KK~R?6&AD`QT8E3=fFaKJniF`?Aq= zKp_Fx#gTFeqU)^HS)2j}kg1l;VoMX~+ch#G?cHQw#DwEC!8%_RM39v{2AyHp8dJV_ zs5#a1N0EOvKw_$u>b$;6wt5qQrie)N#SM$@D@*+D(?%C6vDJ2Dj>}K0Ib*s z(@ex2O+kqQ{XF;Iju$@a#kYVpOPlX?O!I56v1Vw}61gsvtD$m|(Qhw%bbi(v>U}az zysfAw_1?5pM?IoY33r1;W*MWOhL54v3tmWjf14rcU<5#`Oe`;0vpN6f{u-ZdC(0Kj z`8MF5A7scmwI&)iT|A)&kl&P=REa4E{#J-#MI4^ zB_{UJqyB&bt(y{!$KFvL3LhY{l6SFzrC9NAaXZJqepcBTR)5}JF!)~?2y#8xcPW}G z96^Kbsr&fcDac^E5!-jGD-l}`7|H=jAODirEwdU)COIpAc(qwMz5WUR0kv5fN8FT& zD;a03%ez|9A&VjDl%>RQjKeqJ;6DxPHzGEF=FkCnyI`K$Ckn{e?Dlfz>>u(($*w_C zer-S#cN}sMlZ~6UrQ0#8fN=l;A8a7XiD0imn%P9ltHI0_kHLUa<$^z`&EO=$X*@t@ zI@*U*a!60@)AI94qljw#dJrOd>L($R3UPwvJ3k6_oH#N$-}SEz?z$C8HEACA;bkqE za;gAi=SN(ak$@Fk_N&zifxaNuYA-q3Xm#zR1s<#xKSU5LH6g1WePtMH zH_L+B`=8FAl_E&eYtN;6EcJDI&J8ll4NrjP+d9wN86>Ll@8RZgaTrSk-w@G}hGBM6 zNuvdS-OnK^UhhOJ=?c^)h6<0(sjL*9eZ}xSp-yj_e)aXXUjH~#8iY~h#8Qft5Tv$c z#SQRql9?`g9Rr)ZLI$=1K#$-xT6wz2yNPt_-9|G5jx>ByEZf-a`fh_xsiT2FgB(CJ zyoMjyN{~FMq(4&=DaXh;AYOUdK-?;=4yY@ZNeYuu1*j_s5-Osf*NI0#VO9!pic`+7 z6f=g>(13@U!=b4o58-z$#$=VQ_ZVPnMj&}SB4;05)S`|8OEwl#DvKSzh>-^+D66w9 zL1Yzgn03Hd(^IyzvzpvSo;NxzK>!NnxT2-&a>^Aq>$MT9IVg`}B;T<}yWvlThXH)EqY5M8=y)3|mCpEUSq2?W)r2@JWzvoYv1H zozHbOGtZvbZ_fG!;98a34%X0*^WNc>MU&YWw{$ZeVKJ#!4^qq_H<(4Gxd51B`l<)V z?P$zxj&h-oiZ$Hd#4Tb#umttdEB9o=qXCpLA*?00xhM%SMZ_8}<3g4yZdSYqC~LHv zCQmM-6!oJKHo*DkO`zhs%L=vJa3VuHl}4nOy5@|oDQjo>)YHPK+v89E^I&w~)#i_J z6{?TDO&?3SZiy+)OzjJ05`YzMQ9sJz701ba%-9F+nTGlNcaUj&hE3X{qdOCmC0}^K zOxRQJ3ZAMfS)o82l|?o`5J0AY$CTwvnDOG-S_JaM*5vATTUs70Q61FF1%4b_#hW|fIDcdhK^(F3tF zRELfbW;kz`vQxDJ+x@|lx99lQ!)Hum^s9Qu+&(PhsA|J&es;8MR7Kw8s?V07w$JHi z$ZW3vZp}xZ@Hs7<7yvEM#6%;xUF}%{Xw%Ashu}ftDsY<%iHwPnn<$g*Kq%`W8;TSk zGOYH&h)sB^-D@PkjDeq2uWP^n{7=s?C(R5r)ix!5v4!img$+M1i3{{W3y8Hs*Serx z4u96tG2DAGTh1ZeoxQ%!C2yT-%1M3}CY(l!-KuTNn1KS4F+jtjXiJ0XcuHw(j0!7KZ7yoNE6<=vNCS8S#0eXuUKaaE4lN9$xar0(thh&F| zOPNci$8zU8&$vNWI%{*ubqg^0?wQj5)k|iQ>Z?RigKs7262>bkLX;v-)3IuvNU!h2 z;vjTy)MgT74`5UD4z?}4eE2#B!?k}lhCN#+ce+wcb;{+@a?m%y>s@~t)4 zdz)V`g%drF5who_^k}~e#e4`Y572Q4b0HPyCZsi~0GQu*{##Tg{CgAm<%iyKjUM=+ z6ue+rkrTf;Wzk)QQcp*g?ev=%)m+(EPOy-o<=EBsqyU8!A}I4Z#-iQ4b+wsiv1WLC5)chJq};NS zA@P}E1`sA=s-C9y7=BU1QR5I>q)arxDIk)?~C^_!L1&B5zx+tIUZT zzv3gha~8&+v&C{R@6=WsxM_8@o>1(hU}&gR0n~5E_g`oJv+;_zb%-07Ne<|T4GIxK zv)6SZ-?joW5j85Bwh9FKORs=ywx&e2yrTn*dVZ_CmVxZ(CmgR--co^#=(P|qnkrHv zk9?K^96BHzDtn@(LiLwWwnIZeNb(e#jJdmbr>d{46j5bOrM$TyN~9pOmna4v@$&;A z7NAabWz)5eraQbiX;j(gY+rbK#0sZJZ^eUJyJ&v z{i+9bg}qWB4!xdCWGc8%MBn@%uv4Sq52~Wblys`CZeV3=JL174nC(l!{=39U*ESSrCac;U=ukZ!s%cRJ5QWc zWG3ha&}(tt;Nj)ampI zqv|GNObu&Tdg&*BgZGF=#U~bz)wst6om=t|x`ubMe!t8#SYD8sx7CSd**YPfL*d~u z$CsOv?~Q-m>?TOG z2Qv3!bp{dG7CO|-&Dl1oN22q5<2dodZWdAEE2k?;G34}(D!wtb5r@{5ua=_G$oi$& z;Wp;|=&YrNHgoC8nx2md#j>rTWBSa%L8`Z9&Mm{bnG+?MWZ-<03uAgI(SNl2m;cB< zP@}!b16IO^UK53stv90f&7>R9XE9LLI5xCdtux8S8PHm>R2#Qw3IdJ5v88FkHzrc4 zQ;|eOXmrwa7Q{99%~h%AJGEs|#Cs!9P->WL{Hi32fljGl!p{8y4MvbeUWGs-joIpr>B+$> z016;g1E3S~+syQ&@51R)hT{*tP)5u3y3b#!1j7GBt{lOYcfDVqYL|;G`kW(^!WPF9 zT5w0#xieV=JCFGiOaw=AZ#KDov4glpCP;4!!2v`%m(hX1Yq_TR(E;Lwk|T_KjOGr& zJOMd`pHKZp8P}_zySJ+i%C+Ovcq(2nV2O7s3c6p0h5(|zr_XORXe&pl=us3(H{|wS z5d2KcY`O_aAkw%fJ>3SV%Ch{rPcv zH5wMU1>Y!I=~6ubw>>_wQ*XOw=wY!ih5ObO7s^Y-SavE(+LV*8oPv@@O!*rOplht2 zdDJ2XBRgN4iez^P5(2Cp{#l|KA;N~Au-$}?gNiezM#O?R*N%S#hT4E??ziC_f8x{n zlCYAK;NZ%}two)oJ5IJl`dgKan!+q07Z`b^Cr2q+*=NnbjA~ArER`U1e{^~|TqEn! zaptP|^K0mWzLv#5ac&*H$~n_r3)cz)Cr@TKE+U zoq>!o-o+c)4GbI#&v#%slRB`92BagL6d%$&vJzG~+f+3niienCCZ<-N-xCxa&BkOA zuNO&ETEt+}&sO+-FT(69D80l4)5$uYd7&mgK?dDNydNQ#prZ^za6HBrJY{8Ypqyf7 zPU-p^UtQN=W^ON@oW?>PK!VC_zKwr}MKF7F`!SkS{2WZuYTGN)Vvzc=R|PbOMj;HG z*8_*LN!kJDky*xWxr}Ig<#6aQr$;hE(e{tcsQvr+-QzKbxsC&iP1%O!+i?~;a?hw= zA(49^q%=uh0>*<@BofcBwg{`6XDR>`pbz^`erxGdGVC3+K^^S`fXjGd$j#Cq1?=}W zWbB(BgOmJqXOpp50vben{(CDR7h6blc@6ivrta%j%cO9`!(dgf6l`KM&77 zsoiLnF1ZZNMRBnAj6~`Q5L|0wlP?66%jf2)637#lt@ukXXQL=w%#-i zMlwdQL=l3P*B5Km$0gvW?iKKLTLF9ee!lL0?QawA<|!C_KV;SUzdzT_?E1eQ zhTjT){nVWrtp2+Ggzx?wzVGgQpO1Q^)$M+tZyWS}o_8S%X8$}7I_!Q&3i|W39Rex@ za*8zY0el*Wf|T&Zf}UG@!4L$T=?Vubd5nv0XQ$>@9}PH{9oM@C7x&pcSn_u&Ig0CD z7nfYE^4oBJIvVQB^E>hJ=Ddrl{#ew*jL$9jBi`93?l)DnR;@8My5lPNImd>of*g}4 z8*J*U@amkLe#3CSOz=Zr#gLLM>a*W>y)8H&waRDQKQr zgS6J&JDVR3YRV72>lW*(gy-DThPu&&Xf`Ylkvm%B^$w|T(z^jPrl^pp!o7d41B6dD2jE;-76<;=eTEUxk&>L}pkZM?daZz+@B= zsYWD!vr;k~G&RhRVLvfWCfdYK_chepq;&<|HGNkLWb9V|#Z-h>jM^CW*`TbLe9{s2 z1X-QXth&%%)teoUpwp6Z3phB#vsCg{tx8eOE=1eCKAXQgW-jcpl1(bnTwiJ~oX!~> z8rSVqwthY(QLVD^@YX1+`}sOF*x~&5d9M4q7%5S!x9x#SSPGHF{h~RkK;e4R*?RF| zUS8FEVX+7g=TN@sZhz5`bqSoOylRKVwybe_qYbaV8SAz=`yFCJ4Okp5f7jz|!SB^r zUcRQ%KniOzSiZCKyQX0uWjyJ{uav1Q_ny-W#r(I(;Ad_z^1QW#HRgsjS|C!UV8`xZ z0!p5aE80D^+IyZA^*iEJn^loovtZ2hqLvCVGIL~W-`?l9tI(|8<^~VkxrsQRL|7t; zY?ijMj4lXxzQ{L<26X+=5aoUH(}+nrp&wb(vUVdythBELc8Jp~Cg8yn%;G`4J-Ni| zA-h6~CRaq)Ii1>D!Z94csIAz*j@2BqUGl!(8M$PWe~VDxWn<5gZ!G*<_>aTU5FB=D zTgfBG^Iy_{h;ZsjH2E|~7_aml>wfIaR24q$kx@LEL-KVF8~|EzRW+V?edSyDNrPTg z5XpJ@J3{PH)_h4X(l@NaLECr#&(*gl(%1tzx_Jk-<9F;7c*2%CvP0SW$wuMZNXKPa z1I~p}07HCqK1%y8R#foY0{VSKt(b4UWg^e}_mEuT7lOaP=s5en+khx3NHfZ(GnQ3U_ zx0-{03doSYF_eJ4o?&}V`Y2+ZzKk9kP2g-bab$k8<8%)Qc8T$?vw{43Q~ip^XdzYl zd{nhuV^FiKi89i~M z8q9jM6XxhvG+kEUDtKn{ppX9-&M|vdLr^Erzn>DGN~v~bUW`GbZo>Nf%%?UaZOIq@ ztbcTU6-JZ;&Lhvs4oYE;6ArBUJ16Q_`tSLIbWGW|D_PIn3qAAiU`jn2EI}oV*ojhiA7RqX=!S*t;b27yqrJBQ6L>8MjICUoh29uC}p=_p&Cz_vjd^PL1 zf7xVE*J|#rpTF;|uOA=EoXR(q+ANinX5(LA*69sU=H_W=F_q$2hyOCx_4^AE$+c+Q zRsFz+S%cT7cv_2W-sRnLO2Ca~=H(Lz0ifb+NA}WI6ek$pN$~Wfc!llkhUZ#vWqZ*@ z*tHVS`;utrnJ=Fjb#UxwbaSbJvMFu739yXVos}2I!P)}n-3V5mTDA=Wmn_WRHxX}g zODQXzv)usQ0U8}(ro89%+0a!BhR}8Q| zL*KFlF{jhDelG3bK0IKHbEg0WwFD&rU(cYuXWkO+6CF}5ptXGf^*g4>%sG{iuVq^( z{4Vwwsao;K9-CfVoTDmSKU39m2Q;s6sh|NluY$Huj61nx%_oJa^WFh5F1jy^(Zm>$#nlcDYadfZDvtUP7v1>_&uVqI(xNo834H zM8L>xyCbyo71cFY;pk_CW>dl#W~Y_9v_|NoZmzt+3?nGJ2MWFS6G&(h0(4t$w7vAl zGU;dUd!1oTQ3HiT#pLO+AR7^b;^>_N2hK60Vj|XHw~2~6d%^zn@hwEN_<3mr^p1N!l5s`-hi?>qi&`Hcvc53R*} zgH(bZ-HA^boM1vZi2lLY28`PL;YIR>06CLDffA8D!H5l;gSgh5c}j{a>scX_GGG2- zq7Nhe^u&!bb4lkKGE5jDfWYmC;y2uMbIT1MMe8@kB2_0u6I9JJAdAb#lbP!2H%DD-+1TSt+_V#o?d!Uxg2QZzLdeX&7tVO*W zkbrlDXGO<9m!|77c&t1cU1kWhBwDxG;>SX8!`sTRE$_A~Mtzuf-!d!obD-IJ5a&*C zgL{S1rNeAVUt~!EQ{7%LzT;@gk3~phHVb7y5v?c+b%n~5TsBast!)%s2snj1Uzkx> zLC9{63F24c#JJN<13EDO7Q`AGhIN#r(WUO{`U>Z}H#fzY1l1ow)Z@0{JDq}w_|bSM z_>r5C)bv%_yWL7U-##F`jXvHsvhv>CP7i*afAtLJFqeNN_H_PA2Cp}x)mk$!KG$y; z{VP8(yBMx_V5w0R1l6b6BE3Rq^U41>h&XKCvwy3sI4njo2OM%4{n$6Gx!{+bzLa>f zgoEF3DTtR5pVC2j!x+B7=73j8Y2hVZTZTsX!&wwekQNe7>quz`D+OcKqiLSlj<0Z_ zSMRvo|2KkNzWy;Ki@68lXOpLewND>SJbriRx~wrcIdz8~u&^-t15U1t%AAnW(hO)C zu91F~E~F4TU|!&7fgfbO_3$00wn-S6DlT&;kOVHuTf@xFmQblvLx)_6wO*KadW%4x zEL=n~$bfIDtyn0T(V?tl!g@IqJ=#vSs49zdo4QU>izw2z-WlctY^npXT^3FZ{|m)8 zXBQ+G$?%bO0(fBr?vOd$IgThpIiXG{@L)iNBMblukU(b{qb7zBhAiM?R4Y<~3}M}j z=K$5P{phq%@8ni1?hy|2Oo}Ga#^LNQ8BD=p6`nkj0CJ|F*|9fJpi1=y>m~>c0Co(o zr?-Ta$d>p_pc#3e=UzQ4aWJC2zAkV~;Ur6?v8^;hGC+B+1Yh7%+OGNx81F-MGY}-6 zs+U6q(2RUs3droJ)dc~8l)jM3xDoC#=26oFgJ*jGgNL&$#`)`52mxKPsgTb!4FycT z3^#QM5rGx|m+o#{ZfX8fAd{R{TNx(kLTMz7L^%GBUNKOrQ4@A)7f4Fnl3{~gB&^}7 zJK_5#G%|>eF~(moW03EHijCeXNF>UAD}MEFz|sL+IkS=t3iw|HB?v5aR0t!BJ&sP~ zfV4tZO?|T(I+)OP4YU5tKyE9y4e4+5+aexKT-$u;l2EFVVuO~3yttKqMa_zM3{!9JdKnp zw74L*ZiFxF7tVUdfZXbyk0?aZhC43!!#;xTejk7|=M?#yoA=|m9RpQda_W)?Aorh- zQC@TV(?Je}2AkjSEe6Li!x2R3w;Us0I?uOlrt5^Kl(d(RjG+3~?${}(Rni|h6@iV} z)G&_e;+Tl{LXLJMPGrlsKayz}r>Yjtqv;EsbjFbA^ZTkO1p!EZMT?SyjTNmqngw&Q z{96a{bPMI3bI9tbnd){)`klJF0I)o!hJ(pOe?~Hi!-?kb_(jGo%_YS+PQ{TzA1gP| z0wC-x;JVz`GD~3+I|q-;k|on>_^5y(pfpnbEE$lq#4Yh^ydqa760T-=^iy7Z&AHo= z*z!{0dM(KXAhbeoDp;VdY)NJ)5@&$tBxNU|KG%-I46Vw@_fM`iRTpKd0bxoiGBrj9 z7LW#8G%FDaEGdi`-gUYi8U?rV9h)_e9Mi~cn;UBJ-FDciFD)PyaA31E+xb0)Zxwd2 zRZUYO9dRCI`9!Xm;g+5zv$AD=;yHSuioGlH!@zyP%GV zdVRgKt9xGPm%ynirUTS$09PyhNQd6*8>}xqQ_Cq@mqrtLGb?`0Halot>HFmK(9=nd zK1ljjX&AkzE!jvle};AqJx{(H3IlE=9o_F{rl5BMg6Gfz(XtKJp83 z-gL>wMmvp+#Nt`cvuMf0T2fd4eGwR4K{7IZvImqEm$Y;B>j_CqfXX`<#d+(haxMSz*jliD~)u9o7}$Db71+$?d) z4ztDFwYUR>_|~ZF7Kc&KQc5qS<6t2`btpKfuY3w)^_Q75qzpp(3^HWMKtPXOkswpRG%87lUuuLye10oNGZ{79)pg9KE$=zEUkj8^dp-;fJUGf zKcEe|%T-$pO7wk@7OROrlw==>kj$t0A@`W4c(ys`UVPsXz|rMM1IgRf!df%m>aLjj zZ^D&DuU5Il4~A;{i`nYC;XJ{<+-%WZv@!9Ja7}0IM;AFe$*5JJy5pjFyxB!+6i68a z2SsASSVecdLNLUDEUeSf7vbi6&S0H#kf1kf&Z&0}IsARDHZyZzjrN@@u#_khZw9z2 zOQUB!U~!KHV7nnET;2!BruqUxAt&8x+8&!kqKcWP^_xrxf<3BBA zb~l{VrfQKB@N*B?{Z6G5o=kAeB`5NcSB42UPw+eesG;tfS1w@HB4sq)XVf^=yzoJO z5$Hv3Repui^+xB>xe}}9*P-2-`-eI%{2j^`b%K)HW+@Nhap~Cl0-15RmlIr+GBe+h z2y=+0Qr_;H5xT8Jib%6xC6;ueUqM1>p%s5B`MiBcHRnyt!!AJqYle~!oSQ~(g6d`4 zcP?-Pa8XcJM_+49$(OQ)3|zO;)p21T2f0omZr)KT&X@AnRLu+a*os|p4x7kMC+lvV zbsO^T+9_cW{f5TE$t3(y@P}e*kEjH#@H}iUG2(W(e#CWxHbs2)17}X^(Io8akU2p2 zS4QejlR63ZRhMS>#eV$5d}A$iT>-kC4U856*mEKg`lvpO5f!0^nmiaBt8&L{)KS8P z8aLchkel)m%aC8mnx5^wW!u#$&~){2o~mSFD~9LHpV$61r^kGz^tbovk@l{f%JZd(`lgMx6i`p>l(yQOJarz$YreeO(XS-!42lDeZjCRKkjYcZo`ya?vy%SX_zBtRr&qay@pPod)Ug z(()Ew*Z*UM0BKZ}?&SXI@|6;BB|B`g%hj2Ohon@-!MA+FO|uI7BF#-i8KSs9w*Dj5 zcl-AwWLsZTVKg0ymt7=Bb&IA9_Njxa#gG z?TnPV?Rb+3?d2&qH+^2KDYqh&uMQ%NaRfsI;iFVLad66vGZ|r6bdVHaQJ2C|>gIpK z*S9e9WgQzto-&*&YKN+OlJ>4_F7e9T1W?$7|ARV|i(x)Qz&u^vf^DV^|Ig$%nqN{f z{5Qh>CxiUxE9j29BzeZwr0F!{)pjx`ZcL{!g}Hr0Q1w>JIwOJ2p$7#VM~t5 zwNZlhweY#iD>q+>y8G`Z<&HLBQNCg2FuG;$FNw}TrB)56L$kg;vc1GeM4$iP`~g3D zHe61EidN>pequwGhP^e=@&gkdc}POs7~J$3pV5x{`H)!v&ED(2BQZ%AV(>oLu}9kB zf@7!XkQ4kZPU3&8<@nXa7i_4lI{sqBga>yZQDeG#vF5nN!o~hXRmkoZ;sU1HP!J0r zyr1t#06*%t@q*;0>(G7=i4~z)#y*{Sj86zL80a16IjVX#8g@uQq-3#wbccO79MRZq zGMJw=SnUgl;Ic<87esc#P(aArH(e1c+7}rb7l4sy+CQpsIka&zWh<{mx5JQd-zevU zcsQ~=EXq&o8{@`&Ice5bg;nLza9uFhqPW9o=r+pbOjG&;v`uxv?*tY8FY?wa$$3v6 zCy-PA3>s;2_X|TIyPlJpJ+mL5S!03yWFzS)x=R6I=Fh@_{rDd$C_{Oq1;?Tutz?e}sE`=l68JO@Vm zGzsp@uB$fD0tq8dxyjCINtL0DOlwIKEYGE4=#~=%3Sk31jA9moo=8oc{P4@09c|uh zNwP~4;{qGN?59HyjVAvp+87NZ#nLKFJp=*TECY?vJiy^A)crsr@7wOAt za=A1{{yVf6zqPCoRh$I}@-+o^vez1RvKM|!DFxz%gr|%-vC~AW!JJsYfg|9Wr`jdK zqa&2G6>fC2)$g1*sD~IQJAr)H%MW@7-GzRY1h;AwW#Xm$ryhyMCa)@al}Ba30UA)? z<;os0`*E^X*km`#3yYGY@Jn!km+8;JGqAX{#-WT_x|mM;LxMwS?{2ske#qP0#|@3t zCVn|6io8fJ8b4I=PHqz4YAQxGOpa>7Xd!dR#(?O_M3GT5dhlx4%_Y57{e`df(*bV| zZ^0~<#+jUTz>QXmZwIZw(!Rwk+Y4wpS1q`FwU#%5482_y&U?o)N1PaN850$%vc<}Z zUGZ-m z%3w|I*>fpT8^ysc1dq%JHpUVUgXtDV&<~uDZI~7-T$=u^)rlc>glp9?D!o;XqtGr_ zBhByn9xU~=5RYlWon+>ufhQ~cc@1ZZh(po=;^(nMI&ZDXjz^oh{IVMwHe8AWW%e_9 z^=k(;mWKKKBBcW9Aa0B zj96|=7|ajvQ-qIIP-Q&0^hTC(Dv!ftZfLK=$`m@peH?GHC(1MM)$j!O_6h1IXJJT4 zXLfhinlJWZAFZ{N9GOe$mMtD9KhZq6JthM;5bWnG62g@^w?p6Rc?|e-Al?AYgzU2O zuud&2QXIFZg<$_`1Z}xe|Kc!6?7qL&K~JE6M|~`o9Oj`2#f&uTQiCc5-1GQX#nx(D zd{H$W6&8wL*9kfBe&mIh*_SEU`R7TB2%9t-SuQY3V7C)xJa*Wui{!s|G}GD6sG6*! z+;y&!g^z6mGd$5~odrM>{URu@MGfw{!Z;Tt0U4#y$?eKxBLaI*DJ!=z{_3E(^m1mPCd{j+fq8DXImSt$EV!p2mR?=e(g?D%6rRW)`5ICI>M4yVKMTzUlSq z(K@C$LcG((KN#e0zVYBnCXBRSAXUoXI`>yAZj&@-0hi2^PO>7>vXEd9X*P`wOiFpA zCuySTd5y~-#sATCazCde1Ac}^%)?{$2&oprvn7(yR2O7$2wKvezsT-I1Zo%*^DA&` z&v|FDfjLuoToBMahEjm#X|UYmqe%hna-M5xw#~5*K-c)wXyEF3^uOA=%BVQ9t&0Q+ z?hxDw5-hkh?(XjH?$Stbr*U@=?!n#N-3c081ANSz_ukB#_5G>Ux9V8+svmWC?XyqX zlAr5&m#SqU(X%ih9RAMj1l6OF@NEPEqC8lD-*BG*ynIwWHYwSGC6^HcP?j3z)=*Xd zQsd$v&BochH1|WB^)r~b;)8B$BAI;cW=J8Uex&+P)|r)E7=#KeXK@+`_*j{MN`h_~ z0d{Us?*r@AP%jKYWw{sKGKc&$i+bG)A7+Zr9HnNo7E>~$N zf#9oqu5&L0Gr-?%6bWH#hD@Q?M|Z9s^37Sf1pTn$tZRzS(?LyJ%d@DJ_Yg>=1r-qu zqB5a;ZOXGPd7A>S@}HFkZW7&g`BMtZDE5R1^%;R`<*QDC*JFs;Q|G(_-h zjT8^7+suFIwzzfu~HE;wK(LmDLRvpJ< z%A$3&H+gLzjd-aZu*uXMV&6NKbFdLyZd)k`mWjj+b?w+>^ximQLqtaBvmzgsfJXMk zFXj=yVzk8~py_QX;w4ajN&TdlNgAKc7;}^Qz%$VJrAXHcXv4|J#p^iSNJ!{M_MH?m zWZ)1XHGlFz@A3YG6YT?FCl4hyxR`%&gNHP16r0D)i^ur^!Vpy~#9Qux^eC1GhLhd$ zqsVvZ0B8)|)`VtpG?~ln5~3EyG3$P$VDp1gPql|5YAx5IZSb-*U_Fo1$?In@sz3`@ zifCIc6c8Rius;*O1#d?iPJ^kG;~YzadAj=1vFX+&Ny`T*uT^6+hr%&n_-BJzBuh&H zy?E&cn&lu$1x5KaaJwQ?unV*H z1gX1dGK}2HbXl5{zSvV6H$Uh`(g&}FL`O*Elvu%c*d5Gly%3)_@Hq00 z0<{w9bwQ@A5^axE`i3>tfQ&46Yp_nL{0WM1*N0?3?YA_mU$?dx79&=5x3vLDR0rcR z4O()7J4mf+tpYrcM;(0BC0;(;i)Vued39Eo>BwwE?Xq$mLwXJpgJ3HZZs4V9M!T#3 zA))+-gMy=+^zr;%o~6A`)D#i?&;Cv|Gt7VgvN!Mkv(vL}V6J!LovK1z2e8CL1%7$< z=P4IC3uohwV}jx$J~NA@qsd#pvre#vZak`XC{Cu**Lp%S`2lb;ZucT7wk6X12#9BW zxxe3h+h4uso6~cY*Liq;=czmu|Jr!DILq!pE}q1CCp6s5zO_9QXauBvUFDJD2eevt zQ4P^3ZKB`#la~L)1}8kw_FA;G0ZJl0@HV2g7rx?1Q{XccVtSIjV>5e)#=b$0Gm&#` zCmdNKxRnV)uUD?uUpYDlzP?P6%==qpV|RQh6K;plx^F8-gt0zx%@j;vs93q$bCn9G z1NN9xw;GB?jR30Q1eNri3tLGq3c-`%%X>N5NW6^j;G6=NNey;g)05Qjfsq4wPVP%o zV%=e`^A@^MZ$~EOqE>1@@_+bgrAOcq#9G5tyNp2Wbxx%M%DGBQIStsCWWBGj>TORC zAg2Mm;Z6LmVv$XAW516l6&9B{Zm%#ATl$OQ?0Iiu_Xq;T%OljfG z_Ve&cUtC`M-mw`B*-P}|6-R9(7#DfF(@)R8_gyaeLsfb%lS8_wMZ|mgsWITcbhKOM zQ$1!_00Vn)^z!*I|&4VRrqwR7NF+h`)9^ngTVs2|fk>M_x4@_0Qo(f1{6mgXs6^ zVXv_>QyQ^dTD7}O~rJpQOe5fDwrM|G@eo1eW?rmg}yk2q= zo#slV3`F=GKuSF-(-?@JEdXWcOQ2>8m7LwtXx4t25>~_aa+i*NA~l^&@0x;sxOAj^ z9{#pe&O%~;8U>uaJW{T|q=UHDlG}Thr2_j@nNY0PKfcsGMuvC7p%?kx?R4Q9vEV4i z_xgEunM>_cP*!)r;a3eEXVk1gG#~OwHXt6C8O-@nkU<9PT-@(V4*^LeI79&ZkGHNI zhXam*aalf@j&(mur@(#ALB!&sDN- zkD2gdDMWLk>*1d_=ps!Q%$xQ%fSxeF%s4|~ix%qDCrXSHcJCYfQHcD=-o&q#A{+a4 z{IxgZ4S*G}nf-R!L+M%Z%3Ui*Cn?g&eDe%@EytaK5UfTqv@_m8lk+TkdG^C>(H1vH zwfCpaj}z-t^528!RUX!)XB#Zt)4q7gnOVWs?b`+BsG3H+l$I|W0?0gBJHuY7Q*wn< z1htTY_AnlzmPe%ftMPGT8bjULM%}qsux*A+v4H(`%WY7s0CK4K*3^i-RkF$n$?9WG zy#Al9i$~G9Cr83Mc|vE!>_X+YCV z@PKTsy~S%WM!0?C?iBA-+3!7A7nwGxz+7dG>u$4|0MGIl8TS6WD2625*$5kWlG{Oz z64ih`mK@2FLJmsuSwllQ{c;h;c>p?Y1Or-W9FqummHy|ro=_}i3u{-iK%PN!6fx*N zOA{+6h;4X@-S*uk4%Y2D%j-;hdSPidW*{-uQkw?wOhFl63lKY7+(w8qKHABewS+mW zuhMtZmnWBI#|ai%(;h~`Y0AMr%DFM|btA(bvclgWwSo9C>TNXg!M!`s1r;%6Mc zlyOBy|d|NWR#y+{W@SM{y_0+ z%ep3wVaFa~l!Ji}j;j8$Qd5nX(ck6ISI`dUmTQ*%Jh>@W+QWY?ojxg|a&SobK1h>I zr6jVFMRq7n-v_dAa-|}YVous^3v=D$ArGfj5hmn?>eTIpOo{`}LUHMZ<9{hn$^|L_&?{e2Ib^aCjFQX2NdLbTW7mlSB#UeWg=3zX^#<6pV$i&3raI}en((E$yR zx}~eJfq(1hZIg6ryPmUlFIN8+lx%1lW+DmSINmqkE++1v^=kp6fGZXaFe?{Is(5lt z&M#>%WTw?wTRCXfhv>7_gX1J3giPo-f=LCg$cQBPrU?kpuP0YvWHXe`Iw*sDXL($ zF}oA#p0I#6O=qLXtHdWqymM7FcvSO`*{KBdp-FR=T!`4RNs?6bQ;yPc>!vWWV`%t* zbX+se?e-b3*e&f6Lf5H>F4HiC+*ZMn3NZHwEG1DAO~&}N7VPku-|u=2@u$}k!T#(T z9oR_Gm+YNEHpF+7L5XoUS|9tA$cBBS$cD>^BFUwiqGR3qLJ#gpKizP4yli*DxDDNT zA34`8R3k>W#oM*FePfYyKd_oElZ027G!5P9jl$7P*EZ=$a=_@23SG`G7a&PuAGG4| za&4>2sXuxkLMY$zqVxv#;9)wHSBLk{7*oHJlA_4*3|S@d4`mxQ3xylSV~j&1f0m|# zrHI2gpn?sz4hU6eqY_u-&i;jf!N_ObEo@j%$lgh{HULv*EZ>_Ck%v_~!;D(@t%i8o zC2V&TW8Hx9EJb1~e!?YO;p#hLwxM>X8amE1k#{Eo_;?5-WM={p(*_%eK-Q&SQIK-M zECTuMIG52j!Im_8KpzdQ7wzgIUvnO0`1_H~Qc0d7=N%auluj|@)Qc3EW|^smO@F{) zMu=mv&0+eq5MEyNlZpGtby(I$XQ=jCp_>h~69T{V)qzDk03$9=JIEK34Lezht{1v& zFxfVhSYkmkTL2Tdz!>(k`ocqP@`%!P zdc(wVy?q3nFzp^EwR&UA&{m7eTs6E3IQ)EQ5YeUufEDDaVx!F=HcN@5*v+ud@*euk3ZB7eZ&}X4%{)Vl^%4E7E?n*0v`sS zt&x!ox)GCZnPcLOX67|=nyZLgP4IOp5O8!id9?-d)*Q>vO3{Om7yOsG@H~3s{NJ!# zC|Pj)i`r3|FIjE4PivkWgadAU93%~i4h75L_^u(S+@)r6U~hUn3q`E(2@0o z7DSGEKHEh%;~d9=gznM(_*6NOd?_BU`#*tA)cSFa7>ZOV-ZxqQ`eOEupgi7=cP`gU zhG7HoUw+E-7>ebM%Tb|)q7X_N7eSZ=pf;*>XZt2?5EmLTH>QOKA34BZJ|?+!gvoVx;ln-{uM~3Xs|8-*blX$ex6KC5s+ngQF){iu)OshF@`8iM z4u(BtZFP^utk~kC%W`XK{TX$*DOC@VtvyZ3rIbpOY2_aMTd3&JYJ6P+M;El{I?6$W zbd%%|Xvi*pwvJ?teRt65y#Xb{KI!ion3EMPLvBo#=+bH9W_WJlgm3+%rlSu&IAFZM zmbmq!46ZyfectS=oI7Ju+lAqVq)=*zEJ$epnPiPvj{1wCgY&`wCZ~B7Hh85v7tfT)oVp{Uy}@i%T&x9{DQQ z*LncZny}={NXUkEiyu3YDwy#_|ELQRC?zhd{v~|FZ2>d$tAJa(i=uspAim3@0Ars$ z^Kgs)jAKIvxs(EthY=sQ0d**Hsw6x{Q>GJP{+7^MJJnLrcdw+{J)@m(;WA1VsjbVq zjpNgI2~t{7`*U2pO@rh8>_fL~KQe!ira9+yM4>Rl)*Q2AWiz>OVY50AlAK_P zsgLK9-r%W6euaEL)wNu1&YR>O9&0(#kHd^d>QrTDw1P)UYFC%e2Yx!KtRA6%r7m&? zg~1eJF-g??IZ~4^k8z?$MlY5X7ihA1jioVwzdX@cgCWnX8SQA70)7^sp_Uyops(8% z{i~PxD1WI%tdv2ZDI<&-G*lC8-BDzWlAu}V^_W7&qHo!(ynvPam ze?4#DUVx^w!(}3wgEyUFdy1k~w44z$5u?H-4ptMwcC9$~$Qm!XT`t`$46NKcn3Sjy ziZYC#u*)0w5!Kq=-sxyO-;X1_d%cm0D}-SS;nhkUK8PU+zd-1UgnZ{SKZX^v2mY34 zs;nUO5d&tRq08O@V{QK$9`JW+^#y005z_2$>550|w~;|>RjuIy3m8L3Nb{B$UN@l( zeFw^t3O$}74$*@(i`uz5_}LvN`JQ=W=$FY-{5h*p91Djdr76C4ii)Ui4Jp~fk2hd0 zzHLe9;S(Xtavl6tk#3`U!cOKDQ~AbDirZZ#IN(i;u^HOx%nl?t3qZXr&jxdjnKO?w z0E9c$!aI(%uLn%-r=)5IB-u6XM@Mz4yRI7axuXepJL1^BI4b6Wn@X54DV;3;fsE9ZP&{;Og|=i_sk3^ZEHJ?3 zf8jDwksva5-my?m0;XC;FuczD53K2Yss?!>T4Y$2w(g}WcEWB_oU(O&^{hw{G3A6! z4Cw#V$omulhL3+jmi7gYL+Xrj2|m^yB}3Krjd+93Wnk)4ngh{DG%TAW!|XQ^h!cr~ z*b${!2G@P43iY?jFJ&cBu4~pbb#sC9`40IEgA&Zm&4%)~&Oi$E^D{q%ZqAwqa`K&I z+A>c~w4FsObu z5%M<2!Tr=^QBT1!nOr=}k)iXExR0a@cwOYXo=?nOg)@0E(^gw#o>Exy&}IiF`@iT=a)jna#5{LDC+$S+Ej#4kcllb z*AhzcZ~)axAPxFM@v$;5ToGOArxBK}LPb|3BYVYhvxzp5Xya+I+ez2U)<<0RxmiRl zg5K=f?Ijqq4`IZ?f)9C$!{GTIT_gosq!X^OvwCj(AE^{Mk_6GdSxZz>nR1(-yc|0rdQbt_OG`ms zuDol9VBe;H2MhU|ueW?aqd@dwMP2TeII&s@8|~go+TT8tonucEW|0?;UC#JN$;R?D zL9uAdhuQWbOHDXNph+_2aH7}>I$*GLZJkDa&8O_1?ITvyrq7+{pbmLU*Ts|h%z5ji z!@5H1S;-k}vKzOc7628JV?qvd9$PxKzKA`XDw+XH71n>{U_YXsY%^Z^0;2eWKA%ucCs)N{+{i= z2M>q&I=#vTal2O|vrmQz2x17UpZqvyiHeKnH&fC+6UW>2aPi>s0c@Lfhjb6`Fd5GWId}Z3Y2RHtNjuxDFwt>qZ9c z7oXXm!ib|zRg2upT$;3Q(nM7hrleYM*LWJUji$#ci|_eJW;NBNTVJhg+cO1mMSnvKqTv+LK!8JahY>%=8S8TaxTQJ zSu)l-q2fOAT{0ON*zWt6Bo|4iV>$Zqg8oYWu^A%1?g@} zF7cLtI|YDGWs0x-bL!}zU(uC{adv4~#KKisngMDefwIZ9Db8hms-<65M;aZA$P>U` zNXxgp5#%eYnMD)hajUu+o4rn=lA5$;YC2#5Y#3uH({ljow421UHwQuv*x^{OMflf` zd6bzT)fvSraP)mSzMC_k<;bXttpQ|A`l_w&Qs%0w+qOWk8A3{AvHJ;;YdnV%5*5sLoVCq>b2`7VR7Gv^Rp5?C=P43bj20~wK+J3>EU?WO zvJ`l8DU3H_VLOc^w`-En?9Q38StAsoh=5_geP5bQ{uzy8WnzWUU>B7y-c8}Sy=~4n z1rkTr6N#f!({Sb?Pr_YqjB}}aRbtLSj@0Yiw235Q4^WoINK4_^lkPrk_{ZeVmZ)-D zRe00c@8x=%-_?hSOoshWVDK!rbE%$7FO5{%RUuOwg5lQ( zggH}#URK7!D*OFpi%vDkdYYmOpuce9n($Vlie%{wbNeL1jo>XkGusV+S_6{Fv$gTi)YBV-xlx#VpSo6Rmw8d>& zv58?eSdIJ*UEH%7D%})I)1sV{zX`{XE?RZs9`n_JmFvkDDpq9APAw&kgPWE4DZJ)O z(|pi(xm5nmvLQT`E<%@4#0og2*lm`0oeP`=RSx_O@Zy9`#J9qkzF))>z!=X+?-qpO zn|(I9gYw|Lt+sU*p+sfa^0LT)c{r;ovo!{jD;bqpPo?>Cv*G&&-jTXc$>L)J67S2Dy+{8pif;4Nb-p(a}RQh zYQgqA==oa|Wi;=bD3cDMfVW%s!KXjCX7?N4v2yS}adokMeU&%P=!kLYj%3TLSLt0z zhG@l>Vy9`$rHb{L;*z`HRD{$Q#K4L88dkMMVr_M%re>A)+8FYN;}s4q-ouX{&uYH! zy|#$0lWgP}r@A=3pphq{DT&m&a7ro`%APRnshX6@u0r$76Z$$W0JBcPLn9gzG-lJR zK65KW37QKR!jW+`1~Hei_%kP#@z!%CUE64uKciiZyCpYkcAA$Z?HcA&R^FPeE7w7! zDWlglyBgbbSyIq_SI7^uV7Az=oL7iJGaDA5fBfR9K7@2EO-5m3k`~9sv9D*$vfpHy zdt;S>>|W<8A0Mku9zt?RWzFs(aUP_Dbp1HM5o#-n-$SHkf9<+ z;mZp}VZkEhsZtH8t=`%8C#<2q2M)zvqE17S#{LeXj6@fPd~^y3N+>vavM3}yktq}O zv6H5Juw6zOpQD$R({xMVx#38k2H)19V{A2?<*#R*Rqa37|J;Q>vp~PBPl%mWzXu}O z4v7EkGogb~XmWj1YLV0GJ=|d-J|?80K!q?lnXEF#@aZ}^CaZpq$UOL^6xe1J`VwkB zZ}NS9?{!?UQk|IN+A9*8)Ki30hdKX}(JtX~*i3z>NI1Y~IksNw^0q)P*!EKdP<58I z*0owHq}M{YGG+2XblG8;HHxsXNNp1;$2R8_iwOI|m{Q1_1SWm43C$4`i zquv+k!za|NJ9Z~*PT!vqEx@;@_{t-5x;<`D_V;Lcn`>nCOM~>z-Ih=%XrZlPGvAO?Js>TFKgUz!5tZ& zvE&#WTvBvg5$DFA-dZ5FJSN0FbKy8`qnkpAzPDjjM|@$D14oyPQJ~kN)Ypy@%K~6N zBolpQiYiI>W&AZk1D!{-QQR+w_}%FHqs?@+Q0a2J8i{lCYG77Jag^9k3iN4&c5Oh^)?^5THFHu-u9t2 zVg=zROB5*^C}@>4l`{pUGa0yC@C-!Vj-p_xR>}TiHj1>K3U^SrBqWPM9+T@y9Y@OV zjD$En94V2YZ)B3(z%G7BB@3g)E3|Cl4;f<(y*FkUDn!TB1vCJl6JwWsiU1Qn{Ybjt zoOT<$jZaRV)cB<;20mpex~@%4{xqkk<%9AV^#`AT?w19G^VbyK5}8BH`+6-*uVDtV z82_i&>h_>jFaV^mzmtgn*TIinW*ipZp)R}4%&i77L}0SFdHbfXCzu})xP@oB&E%== zCDK-(qY45ibAYv&U-K12gb*3PL;BGm;?;ZajKM-#6VeNxRBOe~Djr3)*!?yy=*aMY zLno&H@OnBE@ShUP1j73YEkF?%BFf#mezAu7)VwT58?Z-9cf;fn?!Go z`N~>xTFes1*);WLdK|iEGnEFW?V)K)ajbnLq3&09xcI2Q598$N4tBS?TD@thF%Dk6 z$#xlK49KYE<`mm#*OB<}d`1m9MSI1Tz&{b^7TxW;$_@#SFSNv&0t>4R_)zKne1@w0 z2FdRNHV*_>=JV{xRL<`V5N#637s!v%&F6FC%9F|(MZ_qPnus=gw0(A-jWEUTR209Y zC}Kj#G3w_5{qjPIta0Hl^ka4%zJO1tk%~Sx1TRLDFKw&udKNC6X(SN*iIW!|Tdj%K zf7307>Bh9Pz-c^>4L+v^QAvKuH+ZG>LGa8cz7>d)DkBkX`i{>AL(2C|$j=stMMlTbw6t*)MtSB^u{IJ}l&i|f zZxIOsb7hp-8qFLpe{2K)whMe`5P(7aaR39s6cVC9g8lDhP<z1)r|^B|jJ$!Pvy!=iy$QXc zqrJQoI0OddUxR71k}*2&-i;*Lz`&6HRq~&QdVgC`O$PzdAHm_WPsHsI!N3%`{%I2n zI_n_#GaFJTE;ucSx|2Zb510RHVXOSprHuM-6|ww(CH+?(3j3eF+@RdfKTGnu`R%cN0+j5$UhDfPWgPXMur)p5LF^QO_ji;T2=e;dnnbejf1|MczfpV(L6?8?f~YM7 a(e)Bx9lSfEfQdSqm Date: Fri, 1 Nov 2013 10:29:47 +0100 Subject: [PATCH 243/664] treat multiple assignment operator warning on msvc --- .../App/opendcm/core/clustergraph.hpp | 89 +++++--- .../Assembly/App/opendcm/core/equations.hpp | 15 +- src/Mod/Assembly/App/opendcm/core/object.hpp | 67 ++++-- .../App/opendcm/module3d/alignment.hpp | 2 +- .../App/opendcm/module3d/coincident.hpp | 4 +- .../Assembly/App/opendcm/module3d/module.hpp | 6 + .../App/opendcm/moduleShape3d/fixed.hpp | 1 - .../App/opendcm/moduleShape3d/generator.hpp | 122 ++++++----- .../App/opendcm/moduleShape3d/module.hpp | 207 +++++++++++++++--- .../App/opendcm/moduleState/module.hpp | 1 - 10 files changed, 372 insertions(+), 142 deletions(-) diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index ed653a05c0bf..44b6ac6bf2fe 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -173,6 +173,11 @@ struct IDgen { }; }; +/** + * @brief Exception thrown from the graph at any occuring error + **/ +struct cluster_error : virtual boost::exception {}; + /** * @brief Pointer type to share a common ID generator @ref IDgen **/ @@ -467,7 +472,8 @@ public boost::noncopyable, * @param g the parent cluster graph **/ ClusterGraph(boost::shared_ptr g) : m_parent(g), m_id(new details::IDgen) { - if(g) m_id = g->m_id; + if(g) + m_id = g->m_id; }; ~ClusterGraph() {}; @@ -741,7 +747,7 @@ public boost::noncopyable, return (*it.first).first; } - return LocalVertex(); + throw details::cluster_error() << boost::errinfo_errno(12) << error_message("Cluster is not part of this graph"); }; /** @@ -785,7 +791,7 @@ public boost::noncopyable, typename ClusterMap::iterator it = m_clusters.find(v); if(it == m_clusters.end()) - return; //TODO:throw + throw details::cluster_error() << boost::errinfo_errno(11) << error_message("Cluster is not part of this graph"); std::pair > res = *it; @@ -908,9 +914,11 @@ public boost::noncopyable, boost::tie(e, done) = boost::edge(source, target, *this); //if done=true the edge alredy existed - if(!done) boost::tie(e, done) = boost::add_edge(source, target, *this); + if(!done) + boost::tie(e, done) = boost::add_edge(source, target, *this); - if(!done) return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + if(!done) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false); //init the bundle corecctly for new edge GlobalEdge global = { fusion::at_c<0> ((*this) [source]), fusion::at_c<0> ((*this) [target]), m_id->generate() }; @@ -948,7 +956,8 @@ public boost::noncopyable, boost::tie(v2, d2) = getContainingVertex(target); //if one vertex is not accessible from here this function fails - if(!(d1 && d2)) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + if(!(d1 && d2)) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here if(v1 == v2 && isCluster(v1)) { @@ -960,9 +969,11 @@ public boost::noncopyable, //check if we already have that Local edge boost::tie(e, d3) = boost::edge(v1, v2, *this); - if(!d3) boost::tie(e, d3) = boost::add_edge(v1, v2, *this); + if(!d3) + boost::tie(e, d3) = boost::add_edge(v1, v2, *this); - if(!d3) return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + if(!d3) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); //init the bundle corectly for new edge GlobalEdge global = { source, target, m_id->generate() }; @@ -1111,11 +1122,14 @@ public boost::noncopyable, bool operator()(edge_bundle_single& e) { bool res; + //this predicate can be used to compare the edge itself or the vertives it connects. See + //if we are a relevant edge if(isEdge) res = (edge == fusion::at_c<1> (e)); else res = (vert == fusion::at_c<1> (e).source) || (vert == fusion::at_c<1> (e).target); + //we are a hit, invoke the functor. if(res || vert < 0) func(fusion::at_c<1> (e)); @@ -1133,8 +1147,11 @@ public boost::noncopyable, std::pair res = getContainingVertex(v); + //we don't throw, as this function gets invoked recursivly and it may happen that the + //vertex to remove is only in the top layers, not the button ones if(!res.second) - return; //TODO:throw + return; + //iterate over every edge that connects to the global vertex or the cluster in which it is in std::vector re; //remove edges @@ -1180,6 +1197,9 @@ public boost::noncopyable, **/ template void removeVertex(LocalVertex id, Functor& f) { + //it is important to delete the global vertex, not the only local one as it's possible that + //we are in a subcluster and there are connections to the global vertex in the parent. They + //need to be deleted too. removeVertex(getGlobalVertex(id), f); }; //no default template arguments for template functions allowed before c++0x, so a little workaround @@ -1271,7 +1291,8 @@ public boost::noncopyable, typename boost::enable_if < boost::is_same::type>, result_type >::type operator()(bundle& p) { - if(Type::value) fusion::for_each(fusion::at_c<2> (p), details::clear_ptr()); + if(Type::value) + fusion::for_each(fusion::at_c<2> (p), details::clear_ptr()); return object_extractor()(p); } @@ -1287,7 +1308,8 @@ public boost::noncopyable, for(edge_single_iterator it = ebsv.begin(); it != ebsv.end(); it++) { if(global_extractor()(*it) == m_key) { - if(Type::value) fusion::for_each(fusion::at_c<0> (*it), details::clear_ptr()); + if(Type::value) + fusion::for_each(fusion::at_c<0> (*it), details::clear_ptr()); e = it; break; @@ -1301,7 +1323,8 @@ public boost::noncopyable, template typename boost::enable_if < mpl::and_ < boost::is_same::type>, boost::is_same > , result_type >::type operator()(bundle& p) { - if(Type::value) fusion::for_each(fusion::at_c<0> (fusion::at_c<1> (p).front()), details::clear_ptr()); + if(Type::value) + fusion::for_each(fusion::at_c<0> (fusion::at_c<1> (p).front()), details::clear_ptr()); return object_extractor()(fusion::at_c<1> (p).front()); } @@ -1637,7 +1660,8 @@ public boost::noncopyable, bool done; boost::tie(e, done) = boost::edge(target, Cluster, *this); - if(!done) boost::tie(e, done) = boost::add_edge(target, Cluster, *this); + if(!done) + boost::tie(e, done) = boost::add_edge(target, Cluster, *this); //if(!done) TODO: throw @@ -1680,7 +1704,8 @@ public boost::noncopyable, bool done; boost::tie(e, done) = boost::edge(nv, res.first, *cg); - if(!done) boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); + if(!done) + boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); //if(!done) TODO: throw @@ -1747,8 +1772,10 @@ public boost::noncopyable, GlobalVertex target; //a bit cumbersome to allow cluster moving - if(parent()->getContainingVertex(global.source).first == nv) target = global.target; - else if(parent()->getContainingVertex(global.target).first == nv) target = global.source; + if(parent()->getContainingVertex(global.source).first == nv) + target = global.target; + else if(parent()->getContainingVertex(global.target).first == nv) + target = global.source; else { i++; continue; @@ -1761,7 +1788,8 @@ public boost::noncopyable, bool done; boost::tie(e, done) = boost::edge(nv, res.first, *parent()); - if(!done) boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); + if(!done) + boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); //if(!done) TODO: throw @@ -1771,14 +1799,16 @@ public boost::noncopyable, } //see if we should destroy this edge (no global edges remain in local one) - if(vec.empty()) edge_vec.push_back(*it.first); + if(vec.empty()) + edge_vec.push_back(*it.first); } //create a edge between new vertex and this cluster and add all global edges from within this cluster it = boost::out_edges(v, *this); LocalEdge e; - if(it.first != it.second) e = boost::add_edge(nv, this_v, *parent()).first; + if(it.first != it.second) + e = boost::add_edge(nv, this_v, *parent()).first; for(; it.first != it.second; it.first++) { std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); @@ -1834,7 +1864,8 @@ public boost::noncopyable, for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { std::pair res = ((*it).second)->getContainingVertex(id); - if(res.second) return std::make_pair((*it).first, true); + if(res.second) + return std::make_pair((*it).first, true); } } @@ -1850,11 +1881,13 @@ public boost::noncopyable, bool done; boost::tie(v, done) = getContainingVertex(id); - if(!done) return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); + if(!done) + return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); if(isCluster(v) && (getGlobalVertex(v) != id)) return m_clusters[v]->getContainingVertexGraph(id); - else return fusion::make_vector(v, sp_base::shared_from_this(), true); + else + return fusion::make_vector(v, sp_base::shared_from_this(), true); }; /* Searches the global edge in all local edges of this graph, and returns the local @@ -1868,7 +1901,8 @@ public boost::noncopyable, boost::tie(v1, d1) = getContainingVertex(id.source, true); boost::tie(v2, d2) = getContainingVertex(id.target, true); - if(!((d1 && d2) && (v1 != v2))) return std::make_pair(LocalEdge(), false); + if(!((d1 && d2) && (v1 != v2))) + return std::make_pair(LocalEdge(), false); return boost::edge(v1, v2, *this); }; @@ -1883,9 +1917,11 @@ public boost::noncopyable, boost::tie(v1, d1) = getContainingVertex(id.source, true); boost::tie(v2, d2) = getContainingVertex(id.target, true); - if(!(d1 && d2)) return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); + if(!(d1 && d2)) + return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); - if(v1 == v2) return m_clusters[v1]->getContainingEdgeGraph(id); + if(v1 == v2) + return m_clusters[v1]->getContainingEdgeGraph(id); return fusion::make_vector(boost::edge(v1, v2, *this).first, this, true); }; @@ -1935,7 +1971,8 @@ public boost::noncopyable, //TODO:Throw } - if((v1 == v2) && isCluster(v1)) return m_clusters[v1]->apply_to_bundle(k, f); + if((v1 == v2) && isCluster(v1)) + return m_clusters[v1]->apply_to_bundle(k, f); else { LocalEdge e; bool done; diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index f04218e110a6..bc34e6d45fa8 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -232,8 +232,10 @@ struct Equation : public EQ { typename boost::enable_if, Derived&>::type operator=(const T& val) { return operator()(val); }; - //assign complete equation - Derived& operator=(const Derived& eq) { + //assign complete equation (we need to override the operator= in the derived class anyway as it + //is automaticly created by the compiler, so we use a different name here to avoid duplicate + //operator= warning on msvc) + Derived& assign(const Derived& eq) { //we only copy the values which were set and are therefore valid option_copy oc(values); @@ -303,7 +305,7 @@ struct print_pair { template typename boost::enable_if, std::basic_ostream&>::type -operator << (std::basic_ostream & stream, const Eq& equation) +operator << (std::basic_ostream& stream, const Eq& equation) { print_pair pr; pr.stream = &stream; @@ -323,7 +325,7 @@ struct Distance : public Equation //override needed ass assignmend operator is always created by the compiler //and we need to ensure that our custom one is used Distance& operator=(const Distance& d) { - return Equation::operator=(d); + return Equation::assign(d); }; void setDefault() { @@ -397,7 +399,7 @@ struct Orientation : public Equation { //override needed ass assignmend operator is always created by the compiler //and we need to ensure that our custom one is used Orientation& operator=(const Orientation& d) { - return Equation::operator=(d); + return Equation::assign(d); }; void setDefault() { @@ -455,6 +457,7 @@ struct Orientation : public Equation { struct Angle : public Equation, true> { using Equation::operator=; + Angle() : Equation() { setDefault(); }; @@ -462,7 +465,7 @@ struct Angle : public Equation, true> //override needed ass assignmend operator is always created by the compiler //and we need to ensure that our custom one is used Angle& operator=(const Angle& d) { - return Equation::operator=(d); + return Equation::assign(d); }; void setDefault() { diff --git a/src/Mod/Assembly/App/opendcm/core/object.hpp b/src/Mod/Assembly/App/opendcm/core/object.hpp index 29c70663a9f8..99ac0ac1393c 100644 --- a/src/Mod/Assembly/App/opendcm/core/object.hpp +++ b/src/Mod/Assembly/App/opendcm/core/object.hpp @@ -21,7 +21,7 @@ #define GCM_OBJECT_H #include -#include +#include #include #include @@ -44,7 +44,6 @@ #include #include -#include #include "property.hpp" @@ -54,7 +53,7 @@ namespace fusion = boost::fusion; /* Preprocessor implementation of emit signal. As we need many overloads with diffrent number of * templated parameters we use boost preprocessor to do the hard repetive work. The definition and - * implementation are definded first as they need to be known before usage + * implementation are definded first as they need to be known before usage * */ #define EMIT_ARGUMENTS(z, n, data) \ BOOST_PP_CAT(data, n) @@ -78,12 +77,14 @@ namespace fusion = boost::fusion; BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ ) \ { \ - typedef typename mpl::find::type iterator; \ - typedef typename mpl::distance::type, iterator>::type distance; \ - typedef typename fusion::result_of::value_at::type list_type; \ - list_type& list = fusion::at(m_signals); \ - for (typename list_type::iterator it=list.begin(); it != list.end(); it++) \ - (*it)(BOOST_PP_ENUM(n, EMIT_ARGUMENTS, arg)); \ + if(m_emit_signals) {\ + typedef typename mpl::find::type iterator; \ + typedef typename mpl::distance::type, iterator>::type distance; \ + typedef typename fusion::result_of::value_at::type map_type; \ + map_type& map = fusion::at(m_signals); \ + for (typename map_type::iterator it=map.begin(); it != map.end(); it++) \ + (it->second)(BOOST_PP_ENUM(n, EMIT_ARGUMENTS, arg)); \ + }\ }; namespace dcm { @@ -98,10 +99,12 @@ namespace dcm { //few standart signal names struct remove {}; -typedef boost::any Connection; +typedef int Connection; template struct SignalOwner { + + SignalOwner(); /** * @brief Connects a slot to a specified signal. @@ -130,9 +133,21 @@ struct SignalOwner { template void disconnectSignal(Connection c); + + /** + * @brief Enable or disable signal emittion + * + * If you want to supress all signals emitted by a object you can do this by calling this function. + * All calls to emitSignal() will be blocked until signals aer reenabled by using this function with + * onoff = true. Note that signals are not queued, if emitting is disabled all signals are lost. + * + * @param onoff bool value if signals shall be emitted or if they are disabled + */ + void enableSignals(bool onoff); + //with no vararg templates before c++11 we need preprocessor to create the overloads of emit signal we need BOOST_PP_REPEAT(5, EMIT_CALL_DEF, ~) - + protected: /*signal handling * extract all signal types to allow index search (inex search on signal functions would fail as same @@ -144,17 +159,19 @@ struct SignalOwner { typedef typename mpl::fold < SigMap, mpl::vector<>, mpl::push_back > >::type sig_functions; typedef typename mpl::fold < sig_functions, mpl::vector<>, - mpl::push_back > >::type sig_vectors; + mpl::push_back > >::type sig_vectors; typedef typename fusion::result_of::as_vector::type Signals; Signals m_signals; + bool m_emit_signals; + int m_signal_count; }; /** * @brief Base class for all object types * * This class add's property and signal capabilitys to all deriving classes. For properties it is tigthly - * integrated with the system class: It searches systems property list for the derived class as specified by + * integrated with the system class: It searches systems property map for the derived class as specified by * the second template parameter and makes it accessible via appopriate functions. Signals are speciefied by a * mpl::map with signal name type as key and a boost::function as values. * @@ -164,7 +181,7 @@ struct SignalOwner { **/ template struct Object : public PropertyOwner::type>, - public SignalOwner, + public SignalOwner, boost::enable_shared_from_this { Object() {}; @@ -204,15 +221,19 @@ boost::shared_ptr Object::clone(Sys& newSys) return np; }; +template +SignalOwner::SignalOwner() : m_emit_signals(true), m_signal_count(0) {}; + template template Connection SignalOwner::connectSignal(typename mpl::at::type function) { typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; - typedef typename fusion::result_of::value_at::type list_type; - list_type& list = fusion::at(m_signals); - return list.insert(list.begin(), function); + typedef typename fusion::result_of::value_at::type map_type; + map_type& map = fusion::at(m_signals); + map[++m_signal_count] = function; + return m_signal_count; }; template @@ -222,9 +243,15 @@ void SignalOwner::disconnectSignal(Connection c) typedef typename mpl::find::type iterator; typedef typename mpl::distance::type, iterator>::type distance; - typedef typename fusion::result_of::value_at::type list_type; - list_type& list = fusion::at(m_signals); - list.erase(boost::any_cast(c)); + typedef typename fusion::result_of::value_at::type map_type; + map_type& map = fusion::at(m_signals); + map.erase(c); +}; + +template +void SignalOwner::enableSignals(bool onoff) +{ + m_emit_signals = onoff; }; BOOST_PP_REPEAT(5, EMIT_CALL_DEC, ~) diff --git a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp index df4764556917..ce36d7728e33 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/alignment.hpp @@ -38,7 +38,7 @@ struct al_orientation : public Equation { }; al_orientation& operator=(const al_orientation& d) { - return Equation::operator=(d); + return Equation::assign(d); }; void setDefault() { diff --git a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp index 86fb690168d5..3ddc356c74c4 100644 --- a/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp +++ b/src/Mod/Assembly/App/opendcm/module3d/coincident.hpp @@ -37,7 +37,7 @@ struct ci_orientation : public Equation { }; ci_orientation& operator=(const ci_orientation& d) { - return Equation::operator=(d); + return Equation::assign(d); }; void setDefault() { @@ -193,7 +193,7 @@ struct ci_distance : public Equation struct Module3D { @@ -773,6 +774,9 @@ void Module3D::type::inheriter_id::removeGeometry3D(Identifie if(hasGeometry3D(id)) inheriter_base::removeGeometry3D(getGeometry3D(id)); + else + throw module3d_error() << boost::errinfo_errno(410) << error_message("no geometry with this ID in this system"); + }; template @@ -792,6 +796,8 @@ void Module3D::type::inheriter_id::removeConstraint3D(Identif if(hasConstraint3D(id)) removeConstraint3D(getConstraint3D(id)); + else + throw module3d_error() << boost::errinfo_errno(411) << error_message("no constraint with this ID in this system"); }; diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp index acff262924b9..3b4252124686 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/fixed.hpp @@ -33,7 +33,6 @@ namespace details { //this fixed equation struct Fixed : public Equation { - using Equation::operator=; using Equation::options; Fixed() : Equation() { setDefault(); diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp index d2977b98245d..38eb3b8d31f2 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/generator.hpp @@ -43,6 +43,10 @@ struct ShapeGeneratorBase { typedef typename module3d::Constraint3D Constraint3D; typedef typename system_traits::template getModule::type moduleShape3d; typedef typename moduleShape3d::Shape3D Shape3D; + + typedef typename Shape3D::ShapeVector ShapeVector; + typedef typename Shape3D::GeometryVector GeometryVector; + typedef typename Shape3D::ConstraintVector ConstraintVector; typedef typename moduleShape3d::shape_purpose_prop shape_purpose_prop; typedef typename moduleShape3d::shape_geometry_prop shape_geometry_prop; @@ -50,17 +54,17 @@ struct ShapeGeneratorBase { Sys* m_system; boost::shared_ptr m_shape; - std::vector >* m_geometries; - std::vector >* m_shapes; - std::vector >* m_constraints; + GeometryVector* m_geometries; + ShapeVector* m_shapes; + ConstraintVector* m_constraints; ShapeGeneratorBase(Sys* system) : m_system(system) {}; virtual ~ShapeGeneratorBase() {}; void set(boost::shared_ptr shape, - std::vector >* geometries, - std::vector >* shapes, - std::vector >* constraints) { + GeometryVector* geometries, + ShapeVector* shapes, + ConstraintVector* constraints) { m_shape = shape; m_geometries = geometries; @@ -76,6 +80,17 @@ struct ShapeGeneratorBase { virtual boost::shared_ptr getOrCreateG3d(int type) = 0; //get hlgeometry3d for optional types virtual boost::shared_ptr getOrCreateHLG3d(int type) = 0; + + //append needs to be on this base class as the shape appends are protected + void append(boost::shared_ptr g) { + m_shape->append(g); + }; + void append(boost::shared_ptr g) { + m_shape->append(g); + }; + void append(boost::shared_ptr g) { + m_shape->append(g); + }; }; } //details @@ -117,7 +132,7 @@ struct segment3D { typedef typename Sys::Kernel Kernel; using typename base::Geometry3D; using typename base::Constraint3D; - using typename base::Shape3D; + using typename base::Shape3D; type(Sys* system) : details::ShapeGeneratorBase(system) {}; @@ -141,17 +156,17 @@ struct segment3D { //link the line geometrie to our shape boost::shared_ptr g1 = base::m_system->createGeometry3D(); - base::m_geometries->push_back(g1); + base::append(g1); g1->template linkTo(base::m_shape,0); g1->template setProperty(line); - g1->template connectSignal(boost::bind(&base::Shape3D::recalc, base::m_shape, _1)); + g1->template connectSignal(boost::bind(&base::Shape3D::recalc, base::m_shape, _1)); //we have a segment, lets link the two points to it boost::shared_ptr g2 = base::m_system->createGeometry3D(); - base::m_geometries->push_back(g2); + base::append(g2); g2->template setProperty(startpoint); boost::shared_ptr g3 = base::m_system->createGeometry3D(); - base::m_geometries->push_back(g3); + base::append(g3); g3->template setProperty(endpoint); //link the points to our new segment @@ -162,49 +177,52 @@ struct segment3D { boost::shared_ptr c1 = base::m_system->createConstraint3D(g1,g2, details::fixed); boost::shared_ptr c2 = base::m_system->createConstraint3D(g1,g3, details::fixed); c1->disable(); //required by fixed constraint + base::append(c1); c2->disable(); //requiered by fixed constraint + base::append(c2); } - else - if(base::m_geometries->size() == 2) { - //we have two points, lets get them - boost::shared_ptr g1 = base::m_geometries->operator[](0); - boost::shared_ptr g2 = base::m_geometries->operator[](1); - - //possibility 1: two points. we add a segment line an link the point in - if(g1->getGeometryType() == tag::weight::point::value || g2->getGeometryType() == tag::weight::point::value) { - - g1->template setProperty(startpoint); - g2->template setProperty(endpoint); - - //construct our segment value - typename Kernel::Vector val(6); - val.head(3) = g1->getValue(); - val.tail(3) = g2->getValue(); - - //the shape is a segment - base::m_shape->template setValue(val); - - //and create a segment geometry we use as line - boost::shared_ptr g3 = base::m_system->createGeometry3D(); - base::m_geometries->push_back(g3); - g3->template linkTo(base::m_shape,0); - g3->template setProperty(line); - g3->template connectSignal(boost::bind(&base::Shape3D::recalc, base::m_shape, _1)); - - //link the points to our new segment - g1->template linkTo(base::m_shape, 0); - g2->template linkTo(base::m_shape, 3); - - //add the fix constraints to show our relation - boost::shared_ptr c1 = base::m_system->createConstraint3D(g1,g3, details::fixed); - boost::shared_ptr c2 = base::m_system->createConstraint3D(g1,g3, details::fixed); - c1->disable(); //required by fixed constraint - c2->disable(); //requiered by fixed constraint - - } - else - throw creation_error() << boost::errinfo_errno(501) << error_message("Wrong geometries for segment construction"); - }; + else if(base::m_geometries->size() == 2) { + //we have two points, lets get them + boost::shared_ptr g1 = fusion::at_c<0>(base::m_geometries->operator[](0)); + boost::shared_ptr g2 = fusion::at_c<0>(base::m_geometries->operator[](1)); + + //possibility 1: two points. we add a segment line an link the point in + if(g1->getGeometryType() == tag::weight::point::value || g2->getGeometryType() == tag::weight::point::value) { + + g1->template setProperty(startpoint); + g2->template setProperty(endpoint); + + //construct our segment value + typename Kernel::Vector val(6); + val.head(3) = g1->getValue(); + val.tail(3) = g2->getValue(); + + //the shape is a segment + base::m_shape->template setValue(val); + + //and create a segment geometry we use as line + boost::shared_ptr g3 = base::m_system->createGeometry3D(); + base::append(g3); + g3->template linkTo(base::m_shape,0); + g3->template setProperty(line); + g3->template connectSignal(boost::bind(&base::Shape3D::recalc, base::m_shape, _1)); + + //link the points to our new segment + g1->template linkTo(base::m_shape, 0); + g2->template linkTo(base::m_shape, 3); + + //add the fix constraints to show our relation + boost::shared_ptr c1 = base::m_system->createConstraint3D(g1,g3, details::fixed); + boost::shared_ptr c2 = base::m_system->createConstraint3D(g1,g3, details::fixed); + c1->disable(); //required by fixed constraint + base::append(c1); + c2->disable(); //requiered by fixed constraint + base::append(c2); + + } + else + throw creation_error() << boost::errinfo_errno(501) << error_message("Wrong geometries for segment construction"); + }; }; //get geometry3d for optional types (e.g. midpoints) virtual boost::shared_ptr::Geometry3D> getOrCreateG3d(int type) { diff --git a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp index 4517144e1e1c..97c228da4161 100644 --- a/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleShape3d/module.hpp @@ -191,7 +191,9 @@ struct ModuleShape3D { struct inheriter_base; struct Shape3D; - typedef mpl::map0<> ShapeSig; + typedef mpl::map2< + mpl::pair) > >, + mpl::pair) > > > ShapeSig; template struct Shape3D_base : public details::Geometry, public Object { @@ -235,34 +237,73 @@ struct ModuleShape3D { virtual boost::shared_ptr clone(Sys& newSys); - /*shape access functions*/ - typedef typename std::vector >::const_iterator geometry3d_iterator; - typedef typename std::vector >::const_iterator shape3d_iterator; - typedef typename std::vector >::const_iterator constraint3d_iterator; + /*shape access functions and extractors to mimic vector<> iterators*/ + typedef std::vector, Connection> > GeometryVector; + typedef std::vector, Connection> > ShapeVector; + typedef std::vector, Connection> > ConstraintVector; + + struct geom_extractor { + typedef boost::shared_ptr result_type; + template + result_type operator()(T& pair) const { + return fusion::at_c<0>(pair); + }; + }; + struct shape_extractor { + typedef boost::shared_ptr result_type; + template + result_type operator()(T& pair) const { + return fusion::at_c<0>(pair); + }; + }; + struct cons_extractor { + typedef boost::shared_ptr result_type; + template + result_type operator()(T& pair) const { + return fusion::at_c<0>(pair); + }; + }; + typedef boost::transform_iterator geometry3d_iterator; + typedef boost::transform_iterator shape3d_iterator; + typedef boost::transform_iterator constraint3d_iterator; + shape3d_iterator beginShape3D() { - return m_shapes.begin(); + return boost::make_transform_iterator(m_shapes.begin(), shape_extractor()); }; shape3d_iterator endShape3D() { - return m_shapes.end(); + return boost::make_transform_iterator(m_shapes.end(), shape_extractor()); }; geometry3d_iterator beginGeometry3D() { - return m_geometries.begin(); + return boost::make_transform_iterator(m_geometries.begin(), geom_extractor()); }; geometry3d_iterator endGeometry3D() { - return m_geometries.end(); + return boost::make_transform_iterator(m_geometries.end(), geom_extractor()); }; constraint3d_iterator beginConstraint3D() { - return m_constraints.begin(); + return boost::make_transform_iterator(m_constraints.begin(), cons_extractor()); }; - constraint3d_iterator endConstraint3D() { - return m_constraints.end(); + constraint3d_iterator endConstraint3D() { + return boost::make_transform_iterator(m_constraints.end(), cons_extractor()); }; boost::shared_ptr geometry(purpose f); template boost::shared_ptr subshape(); + //callbacks void recalc(boost::shared_ptr g); + void remove(boost::shared_ptr g); + void remove(boost::shared_ptr g); + void remove(boost::shared_ptr g); + + private: + + //we store all geometries, shapes and constraint which belong to this shape. + //Furthermore we store the remove connections, as we need to disconnect them later + GeometryVector m_geometries; + ShapeVector m_shapes; + ConstraintVector m_constraints; + protected: #ifdef USE_LOGGING @@ -301,11 +342,7 @@ struct ModuleShape3D { Variant m_geometry; //Variant holding the real geometry type boost::shared_ptr< details::ShapeGeneratorBase > m_generator; - using Object >::m_system; - - std::vector > m_geometries; - std::vector > m_shapes; - std::vector > m_constraints; + using Object::m_system; template void initShape() { @@ -318,9 +355,14 @@ struct ModuleShape3D { m_generator->init(); }; + //disconnect all remove signals of stored geometry/shapes/constraints + void disconnectAll(); + //the stroage is private, all things need to be added by this methods. + //this is used to ensure the proper event connections boost::shared_ptr append(boost::shared_ptr g); boost::shared_ptr append(boost::shared_ptr g); + boost::shared_ptr append(boost::shared_ptr g); //override protected event functions to emit signals void reset() {}; @@ -370,6 +412,7 @@ struct ModuleShape3D { friend struct details::SystemSolver; friend struct details::SystemSolver::Rescaler; friend struct inheriter_base; + friend struct details::ShapeGeneratorBase; public: //the geometry class itself does not hold an aligned eigen object, but maybe the variant @@ -400,9 +443,11 @@ struct ModuleShape3D { void removeShape3D(ID id); bool hasShape3D(ID id); boost::shared_ptr getShape3D(ID id); - - protected: - using inheriter_base::m_this; + + using inheriter_base::removeShape3D; + + protected: + using inheriter_base::m_this; }; struct inheriter : public mpl::if_, inheriter_base, inheriter_id>::type {}; @@ -507,7 +552,7 @@ template boost::shared_ptr::template getModule::type::Geometry3D> ModuleShape3D::type::Shape3D_base::geometry(purpose f) { - for(geometry3d_iterator it = m_geometries.begin(); it != m_geometries.end(); it++) { + for(geometry3d_iterator it = beginGeometry3D(); it != endGeometry3D(); it++) { if((*it)->template getProperty() == f) return *it; @@ -520,8 +565,11 @@ template template boost::shared_ptr ModuleShape3D::type::Shape3D_base::append(boost::shared_ptr g) { - m_geometries.push_back(g); + g->template setProperty(true); + Connection c = g->template connectSignal(boost::bind(static_cast)>(&Shape3D_base::remove) , this, _1)); + m_geometries.push_back(fusion::make_vector(g,c)); + return ObjBase::shared_from_this(); }; @@ -531,10 +579,42 @@ template template boost::shared_ptr ModuleShape3D::type::Shape3D_base::append(boost::shared_ptr g) { - m_shapes.push_back(g); + + Connection c = g->template connectSignal(boost::bind(static_cast)>(&Shape3D_base::remove) , this, _1)); + m_shapes.push_back(fusion::make_vector(g,c)); + return ObjBase::shared_from_this(); }; +template +template +template +boost::shared_ptr +ModuleShape3D::type::Shape3D_base::append(boost::shared_ptr g) { + + Connection c = g->template connectSignal(boost::bind(static_cast)>(&Shape3D_base::remove) , this, _1)); + m_constraints.push_back(fusion::make_vector(g,c)); + + return ObjBase::shared_from_this(); +}; +template +template +template +void ModuleShape3D::type::Shape3D_base::disconnectAll() { + + typename GeometryVector::iterator git; + for(git = m_geometries.begin(); git!=m_geometries.end(); git++) + fusion::at_c<0>(*git)->template disconnectSignal(fusion::at_c<1>(*git)); + + typename ShapeVector::iterator sit; + for(sit = m_shapes.begin(); sit!=m_shapes.end(); sit++) + fusion::at_c<0>(*sit)->template disconnectSignal(fusion::at_c<1>(*sit)); + + typename ConstraintVector::iterator cit; + for(cit = m_constraints.begin(); cit!=m_constraints.end(); cit++) + fusion::at_c<0>(*cit)->template disconnectSignal(fusion::at_c<1>(*cit)); +}; + template template template @@ -544,6 +624,63 @@ void ModuleShape3D::type::Shape3D_base::recalc(boost Base::finishCalculation(); }; +template +template +template +void ModuleShape3D::type::Shape3D_base::remove(boost::shared_ptr g) { + + //before we delete this shape by calling the system remove function, we need to remove + //this geometry as this would be deleted again by the system call and we would go into infinit recoursion + + //get the vector object where the geometry is part of + typename GeometryVector::const_iterator it; + for(it=m_geometries.begin(); it!=m_geometries.end(); it++) { + if(fusion::at_c<0>(*it)==g) + break; + }; + + m_geometries.erase(std::remove(m_geometries.begin(), m_geometries.end(), *it), m_geometries.end()); + ObjBase::m_system->removeShape3D(ObjBase::shared_from_this()); +}; + +template +template +template +void ModuleShape3D::type::Shape3D_base::remove(boost::shared_ptr g) { + + //before we delete this shape by calling the system remove function, we need to remove + //this geometry as this would be deleted again by the system call and we would go into infinit recoursion + + //get the vector object where the geometry is part of + typename ShapeVector::const_iterator it; + for(it=m_shapes.begin(); it!=m_shapes.end(); it++) { + if(fusion::at_c<0>(*it)==g) + break; + }; + + m_shapes.erase(std::remove(m_shapes.begin(), m_shapes.end(), *it), m_shapes.end()); + ObjBase::m_system->removeShape3D(ObjBase::shared_from_this()); +}; + +template +template +template +void ModuleShape3D::type::Shape3D_base::remove(boost::shared_ptr g) { + + //before we delete this shape by calling the system remove function, we need to remove + //this geometry as this would be deleted again by the system call and we would go into infinit recoursion + + //get the vector object where the geometry is part of + typename ConstraintVector::const_iterator it; + for(it=m_constraints.begin(); it!=m_constraints.end(); it++) { + if(fusion::at_c<0>(*it)==g) + break; + }; + + m_constraints.erase(std::remove(m_constraints.begin(), m_constraints.end(), *it), m_constraints.end()); + ObjBase::m_system->removeShape3D(ObjBase::shared_from_this()); +}; + template template template @@ -636,20 +773,23 @@ template template void ModuleShape3D::type::inheriter_base::removeShape3D(boost::shared_ptr g) { - //remove all constraints - typedef typename Shape3D::constraint3d_iterator cit; - for(cit it=g->constraint3dBegin(); it!=g->constraint3dEnd(); it++) - m_this->removeConstraint3D(*it); + //disconnect all shapes, geometries and constraints, as otherwise we would go into infinite + //recursion + g->disconnectAll(); + //remove all constraints is unnessecary as they get removed together with the geometries //remove all geometries typedef typename Shape3D::geometry3d_iterator git; - for(git it=g->geometry3dBegin(); it!=g->geometry3dEnd(); it++) + for(git it=g->beginGeometry3D(); it!=g->endGeometry3D(); it++) m_this->removeGeometry3D(*it); - - //remove all subshapes - typedef typename Shape3D::shape3d_iterator sit; - for(sit it=g->shape3dBegin(); it!=g->shape3dEnd(); it++) - m_this->removeShape3D(*it); + + + /* TODO: find out why it iterates over a empty vector and crashs... + //remove all subshapes + typedef typename Shape3D::shape3d_iterator sit; + for(sit it=g->beginShape3D(); it!=g->endShape3D(); it++) { + m_this->removeShape3D(*it); + };*/ //emit remove shape signal bevore actually deleting it g->template emitSignal(g); @@ -689,3 +829,4 @@ void ModuleShape3D::type::inheriter_id::removeShape3D(Identif }//dcm #endif //GCM_MODULE_SHAPE3D_H + diff --git a/src/Mod/Assembly/App/opendcm/moduleState/module.hpp b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp index c6760c371c44..d18600160aa1 100644 --- a/src/Mod/Assembly/App/opendcm/moduleState/module.hpp +++ b/src/Mod/Assembly/App/opendcm/moduleState/module.hpp @@ -92,4 +92,3 @@ struct ModuleState { - From aa5d84196c517965ad7ae91b0fa03cb12ce93301 Mon Sep 17 00:00:00 2001 From: Stefan Troeger Date: Fri, 1 Nov 2013 11:05:58 +0100 Subject: [PATCH 244/664] supress useless msvc warnings --- src/Mod/Assembly/App/opendcm/core.hpp | 2 ++ src/Mod/Assembly/CMakeLists.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index b30cd8aec73b..f878620bdf8d 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -25,6 +25,8 @@ #pragma warning( disable : 4503 ) //warning about changed pod initalising behaviour (boost blank in variant) #pragma warning( disable : 4345 ) + //warning about multiple assignemnt operators in Equation + #pragma warning( disable : 4522 ) //disable boost concept checks, as some of them have alignment problems which bring msvc to an error //(for example DFSvisitor check in boost::graph::depht_first_search) diff --git a/src/Mod/Assembly/CMakeLists.txt b/src/Mod/Assembly/CMakeLists.txt index f4b5f8416021..aa8e18d55d86 100644 --- a/src/Mod/Assembly/CMakeLists.txt +++ b/src/Mod/Assembly/CMakeLists.txt @@ -8,6 +8,7 @@ endif(FREECAD_ASSEMBLY_SOLVER_LOGS) if(MSVC) add_definitions(/wd4503) +add_definitions(/wd4181) endif(MSVC) add_subdirectory(App) From 8b0fe845bfd82681053b357d924877ce73eed9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Fri, 1 Nov 2013 11:50:44 +0100 Subject: [PATCH 245/664] use freecad resource, not local one --- .../Assembly/Gui/TaskAssemblyConstraints.ui | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui index df861e096d2c..053cfa7b61b8 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.ui @@ -118,7 +118,7 @@ Distance - + :/icons/Assembly_ConstraintDistance.svg:/icons/Assembly_ConstraintDistance.svg @@ -159,7 +159,7 @@ Coincident - + :/icons/Assembly_ConstraintCoincidence.svg:/icons/Assembly_ConstraintCoincidence.svg @@ -200,7 +200,7 @@ Fix - + :/icons/Assembly_ConstraintLock.svg:/icons/Assembly_ConstraintLock.svg @@ -241,7 +241,7 @@ Orientation - + :/icons/Assembly_ConstraintOrientation.svg:/icons/Assembly_ConstraintOrientation.svg @@ -282,7 +282,7 @@ Align - + :/icons/Assembly_ConstraintAlignment.svg:/icons/Assembly_ConstraintAlignment.svg @@ -323,7 +323,7 @@ Angle - + :/icons/Assembly_ConstraintAngle.svg:/icons/Assembly_ConstraintAngle.svg @@ -437,7 +437,7 @@ ... - + :/icons/Assembly_ConstraintBidirectional.svg:/icons/Assembly_ConstraintBidirectional.svg @@ -475,7 +475,7 @@ ... - + :/icons/Assembly_ConstraintUnidirectional2.svg:/icons/Assembly_ConstraintUnidirectional2.svg @@ -510,7 +510,7 @@ ... - + :/icons/Assembly_ConstraintUnidirectional1.svg:/icons/Assembly_ConstraintUnidirectional1.svg @@ -567,7 +567,7 @@ Parallel - + :/icons/Assembly_ConstraintParallel.svg:/icons/Assembly_ConstraintParallel.svg @@ -605,7 +605,7 @@ Equal - + :/icons/Assembly_ConstraintEqual.svg:/icons/Assembly_ConstraintEqual.svg @@ -646,7 +646,7 @@ Opposite - + :/icons/Assembly_ConstraintOpposite.svg:/icons/Assembly_ConstraintOpposite.svg @@ -687,7 +687,7 @@ Perpend. - + :/icons/Assembly_ConstraintPerpendicular.svg:/icons/Assembly_ConstraintPerpendicular.svg @@ -728,9 +728,7 @@ - - - + distance From f0ed9c81c32b9a0beba92938c7c21cb7791648cd Mon Sep 17 00:00:00 2001 From: Stefan Troeger Date: Fri, 1 Nov 2013 12:15:32 +0100 Subject: [PATCH 246/664] include dcm core directly to use the warning supression --- src/Mod/Assembly/Gui/TaskAssemblyConstraints.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h index a745ce53f796..06d3d9bbae2d 100644 --- a/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h +++ b/src/Mod/Assembly/Gui/TaskAssemblyConstraints.h @@ -27,7 +27,7 @@ #include #include #include "ViewProviderConstraint.h" -#include +#include #include #include #include "ui_TaskAssemblyConstraints.h" From 054dba0847854dde009edb8dddd533ccf213fc12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Mon, 4 Nov 2013 08:33:33 +0100 Subject: [PATCH 247/664] rename the add commands --- src/Mod/Assembly/Gui/Command.cpp | 8 ++++---- src/Mod/Assembly/Gui/Workbench.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Mod/Assembly/Gui/Command.cpp b/src/Mod/Assembly/Gui/Command.cpp index d711a7493fd8..fef2f5d246ac 100644 --- a/src/Mod/Assembly/Gui/Command.cpp +++ b/src/Mod/Assembly/Gui/Command.cpp @@ -116,8 +116,8 @@ CmdAssemblyAddNewComponent::CmdAssemblyAddNewComponent() { sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); - sMenuText = QT_TR_NOOP("Add new Component"); - sToolTipText = QT_TR_NOOP("Add a new Component into the active Assembly"); + sMenuText = QT_TR_NOOP("Add new Assembly"); + sToolTipText = QT_TR_NOOP("Add a new Subassembly into the active Assembly"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Part_Box"; @@ -137,7 +137,7 @@ void CmdAssemblyAddNewComponent::activated(int iMsg) } openCommand("Insert Component"); - std::string CompName = getUniqueObjectName("Product"); + std::string CompName = getUniqueObjectName("Assembly"); doCommand(Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','%s')",CompName.c_str()); if(dest){ std::string fatherName = dest->getNameInDocument(); @@ -155,7 +155,7 @@ CmdAssemblyAddExistingComponent::CmdAssemblyAddExistingComponent() sAppModule = "Assembly"; sGroup = QT_TR_NOOP("Assembly"); sMenuText = QT_TR_NOOP("Add existing Component..."); - sToolTipText = QT_TR_NOOP("Add a existing Component or File into the active Assembly"); + sToolTipText = QT_TR_NOOP("Add a existing Component into the active Assembly"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Part_Box"; diff --git a/src/Mod/Assembly/Gui/Workbench.cpp b/src/Mod/Assembly/Gui/Workbench.cpp index e003dbedc100..6e01dc1c029b 100644 --- a/src/Mod/Assembly/Gui/Workbench.cpp +++ b/src/Mod/Assembly/Gui/Workbench.cpp @@ -130,8 +130,8 @@ void Workbench::activated() assert(doc); if(doc->countObjects()==0){ - Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Product')"); - Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.setActiveAssembly(App.activeDocument().Product)"); + Gui::Command::doCommand(Gui::Command::Doc,"App.activeDocument().addObject('Assembly::ItemAssembly','Assembly')"); + Gui::Command::doCommand(Gui::Command::Doc,"AssemblyGui.setActiveAssembly(App.activeDocument().Assembly)"); } Gui::Control().showModelView(); From 0b28a757abf770d0151138a14d4f4618a87b3733 Mon Sep 17 00:00:00 2001 From: jriegel Date: Tue, 5 Nov 2013 22:51:41 +0100 Subject: [PATCH 248/664] Workaround for a wired linker problem on Windows. Actually still not solved... --- src/Mod/PartDesign/App/Body.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index c895843540e1..9a4fffeece0b 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -41,6 +41,7 @@ #include #include #include +#include using namespace PartDesign; @@ -222,7 +223,9 @@ const bool Body::isAllowed(const App::DocumentObject* f) return (f->getTypeId().isDerivedFrom(PartDesign::Feature::getClassTypeId()) || f->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || f->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId()) || - f->getTypeId().isDerivedFrom(Part::FeaturePython::getClassTypeId())); + //f->getTypeId().isDerivedFrom(Part::FeaturePython::getClassTypeId()) // trouble with this line on Windows!? Linker fails to find getClassTypeId() of the Part::FeaturePython... + f->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()) + ); } void Body::addFeature(App::DocumentObject *feature) From 273e0f0b71f852ed8edb1b3a749134680d033756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Rheinl=C3=A4nder?= Date: Wed, 4 Dec 2013 20:40:37 +0100 Subject: [PATCH 249/664] Fixed bug that did not allow selecting datum planes as external references in sketches --- src/Mod/Sketcher/App/SketchObject.cpp | 5 +++-- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 74344feba983..d156b8032ade 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -1707,10 +1707,11 @@ bool SketchObject::isExternalAllowed(App::Document *pDoc, App::DocumentObject *p { // Externals outside of the Document are NOT allowed if (this->getDocument() != pDoc) - return false; + return false; + // Note: Checking for the body of the support doesn't work when the support are the three base planes App::DocumentObject *support = this->Support.getValue(); - Part::BodyBase* body = Part::BodyBase::findBodyOf(support); + Part::BodyBase* body = Part::BodyBase::findBodyOf(this); if (body != NULL) { if (Part::BodyBase::findBodyOf(pObj) != body) { // Selection outside of body not allowed if flag is not set diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 067c3069e3ed..75714e31d898 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -4478,8 +4478,8 @@ namespace SketcherGui { if (!sketch->isExternalAllowed(pDoc, pObj)) return false; - App::DocumentObject *support = sketch->Support.getValue(); - Part::BodyBase* body = Part::BodyBase::findBodyOf(support); + // Note: its better to search the support of the sketch in case the sketch support is a base plane + Part::BodyBase* body = Part::BodyBase::findBodyOf(sketch); if ((body != NULL) && (Part::BodyBase::findBodyOf(pObj) == body) && body->isAfterTip(pObj)) // Don't allow selection after the Tip feature in the same body return false; @@ -4491,7 +4491,10 @@ namespace SketcherGui { (element.size() > 6 && element.substr(0,6) == "Vertex") || (element.size() > 4 && element.substr(0,4) == "Face")) { return true; - } + } + if (pObj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || + pObj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) + return true; return false; } }; From 9d196708b15d47b44e694c6cfe3ae2239666ecec Mon Sep 17 00:00:00 2001 From: jriegel Date: Thu, 12 Dec 2013 21:23:41 +0100 Subject: [PATCH 250/664] small fixes after merge from master --- src/Mod/PartDesign/Gui/ViewProviderDatum.cpp | 2 +- .../PartDesign/Gui/ViewProviderDatumLine.cpp | 4 ++-- .../PartDesign/Gui/ViewProviderDatumPlane.cpp | 20 +++++++++---------- .../PartDesign/Gui/ViewProviderDressUp.cpp | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 398bcc03299c..51dbddd66c61 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -103,7 +103,7 @@ void ViewProviderDatum::attach(App::DocumentObject *obj) SoNormalBinding* normb = new SoNormalBinding(); normb->value = SoNormalBinding::PER_VERTEX_INDEXED; SoBaseColor* color = new SoBaseColor(); - color->rgb.setValue(0.9, 0.9, 0.3); + color->rgb.setValue(0.9f, 0.9f, 0.3f); SoSeparator* sep = new SoSeparator(); SoPickStyle* ps = new SoPickStyle(); ps->style = SoPickStyle::SHAPE; diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp index fa0bd4931d05..010f0ea3b0e7 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumLine.cpp @@ -56,8 +56,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumLine,PartDesignGui::ViewProvider ViewProviderDatumLine::ViewProviderDatumLine() { SoMaterial* material = new SoMaterial(); - material->diffuseColor.setValue(0.9f, 0.9f, 0.13); - material->transparency.setValue(0.2); + material->diffuseColor.setValue(0.9f, 0.9f, 0.13f); + material->transparency.setValue(0.2f); pShapeSep->addChild(material); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp index 7305f6962825..7cd18c95f716 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatumPlane.cpp @@ -57,8 +57,8 @@ PROPERTY_SOURCE(PartDesignGui::ViewProviderDatumPlane,PartDesignGui::ViewProvide ViewProviderDatumPlane::ViewProviderDatumPlane() { SoMaterial* material = new SoMaterial(); - material->diffuseColor.setValue(0.9f, 0.9f, 0.13); - material->transparency.setValue(0.2); + material->diffuseColor.setValue(0.9f, 0.9f, 0.13f); + material->transparency.setValue(0.2f); pShapeSep->addChild(material); } @@ -153,7 +153,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) // Sort by angles std::vector a(points.size()); - for (int i = 0; i < points.size() - 1; i++) { + for (unsigned int i = 0; i < points.size() - 1; i++) { if (longest == 0) a[i] = atan2(points[i].z - m.z, points[i].y - m.y); else if (longest == 1) @@ -161,7 +161,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) else a[i] = atan2(points[i].y - m.y, points[i].x - m.x); - for (int k = i+1; k < points.size(); k++) { + for (unsigned int k = i+1; k < points.size(); k++) { if (longest == 0) a[k] = atan2(points[k].z - m.z, points[k].y - m.y); else if (longest == 1) @@ -192,7 +192,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) return; coord = new SoCoordinate3(); coord->point.setNum(points.size()); - for (int p = 0; p < points.size(); p++) + for (unsigned int p = 0; p < points.size(); p++) coord->point.set1Value(p, points[p].x, points[p].y, points[p].z); pShapeSep->addChild(coord); @@ -206,7 +206,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) faceSet->coordIndex.set1Value(2, 2); faceSet->coordIndex.set1Value(3, SO_END_FACE_INDEX); // One more triangle for every extra polygon point - for (int p = 3; p < points.size(); p++) { + for (unsigned int p = 3; p < points.size(); p++) { faceSet->coordIndex.set1Value(4 + 4*(p-3), 0); faceSet->coordIndex.set1Value(4 + 4*(p-3) + 1, p-1); faceSet->coordIndex.set1Value(4 + 4*(p-3) + 2, p); @@ -216,7 +216,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) lineSet = new SoIndexedLineSet(); lineSet->coordIndex.setNum(points.size()+2); - for (int p = 0; p < points.size(); p++) + for (unsigned int p = 0; p < points.size(); p++) lineSet->coordIndex.set1Value(p, p); lineSet->coordIndex.set1Value(points.size(), 0); lineSet->coordIndex.set1Value(points.size()+1, SO_END_LINE_INDEX); @@ -224,7 +224,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) } else { coord = static_cast(pShapeSep->getChild(1)); coord->point.setNum(points.size()); - for (int p = 0; p < points.size(); p++) + for (unsigned int p = 0; p < points.size(); p++) coord->point.set1Value(p, points[p].x, points[p].y, points[p].z); faceSet = static_cast(pShapeSep->getChild(2)); faceSet->partIndex.setNum(1); // One face @@ -236,7 +236,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) faceSet->coordIndex.set1Value(2, 2); faceSet->coordIndex.set1Value(3, SO_END_FACE_INDEX); // One more triangle for every extra polygon point - for (int p = 3; p < points.size(); p++) { + for (unsigned int p = 3; p < points.size(); p++) { faceSet->coordIndex.set1Value(4 + 4*(p-3), 0); faceSet->coordIndex.set1Value(4 + 4*(p-3) + 1, p-1); faceSet->coordIndex.set1Value(4 + 4*(p-3) + 2, p); @@ -244,7 +244,7 @@ void ViewProviderDatumPlane::updateData(const App::Property* prop) } lineSet = static_cast(pShapeSep->getChild(3)); lineSet->coordIndex.setNum(points.size()+2); - for (int p = 0; p < points.size(); p++) + for (unsigned int p = 0; p < points.size(); p++) lineSet->coordIndex.set1Value(p, p); lineSet->coordIndex.set1Value(points.size(), 0); lineSet->coordIndex.set1Value(points.size()+1, SO_END_LINE_INDEX); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp index c55bac981375..6b879bcd0b95 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp @@ -111,7 +111,7 @@ void ViewProviderDressUp::highlightReferences(const bool on) for (std::vector::const_iterator f = SubVals.begin(); f != SubVals.end(); f++) { int idx = atoi(f->substr(4).c_str()) - 1; // TODO: Find a better colour - colors[idx] = App::Color(0.2,1,0.2); + colors[idx] = App::Color(0.2f,1.0f,0.2f); } vp->DiffuseColor.setValues(colors); } else { From d4fdb92957e747228e28cf1e7a2205bec5a20c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Tr=C3=B6ger?= Date: Thu, 19 Dec 2013 06:55:41 +0100 Subject: [PATCH 251/664] new openDCM version --- src/Mod/Assembly/App/opendcm/core.hpp | 9 + .../App/opendcm/core/clustergraph.hpp | 1090 ++------------- .../Assembly/App/opendcm/core/constraint.hpp | 632 +-------- .../Assembly/App/opendcm/core/equations.hpp | 230 +--- .../Assembly/App/opendcm/core/geometry.hpp | 229 +--- .../App/opendcm/core/imp/clustergraph_imp.hpp | 1220 +++++++++++++++++ .../core/imp/constraint_holder_imp.hpp | 449 ++++++ .../App/opendcm/core/imp/constraint_imp.hpp | 208 +++ .../App/opendcm/core/imp/equations_imp.hpp | 255 ++++ .../App/opendcm/core/imp/geometry_imp.hpp | 266 ++++ .../App/opendcm/core/imp/kernel_imp.hpp | 512 +++++++ .../App/opendcm/core/imp/object_imp.hpp | 115 ++ .../App/opendcm/core/imp/system_imp.hpp | 257 ++++ .../opendcm/core/imp/transformation_imp.hpp | 303 ++++ src/Mod/Assembly/App/opendcm/core/kernel.hpp | 468 ++----- src/Mod/Assembly/App/opendcm/core/object.hpp | 85 +- .../Assembly/App/opendcm/core/property.hpp | 12 +- src/Mod/Assembly/App/opendcm/core/system.hpp | 253 ++-- src/Mod/Assembly/App/opendcm/core/traits.hpp | 37 +- .../App/opendcm/core/transformation.hpp | 238 +--- src/Mod/Assembly/App/opendcm/module3d.hpp | 31 +- .../App/opendcm/module3d/alignment.hpp | 2 +- .../App/opendcm/module3d/clustermath.hpp | 640 +-------- .../App/opendcm/module3d/coincident.hpp | 4 +- .../Assembly/App/opendcm/module3d/defines.hpp | 1 + .../App/opendcm/module3d/distance.hpp | 1 + .../opendcm/module3d/imp/clustermath_imp.hpp | 667 +++++++++ .../module3d/imp/constraint3d_holder_imp.hpp | 87 ++ .../opendcm/module3d/imp/constraint3d_imp.hpp | 119 ++ .../opendcm/module3d/imp/geometry3d_imp.hpp | 256 ++++ .../App/opendcm/module3d/imp/module_imp.hpp | 268 ++++ .../App/opendcm/module3d/imp/solver_imp.hpp | 410 ++++++ .../App/opendcm/module3d/imp/state_imp.hpp | 373 +++++ .../Assembly/App/opendcm/module3d/module.hpp | 541 +------- .../Assembly/App/opendcm/module3d/solver.hpp | 387 +----- .../Assembly/App/opendcm/module3d/state.hpp | 337 +---- .../App/opendcm/modulePart/module.hpp | 34 +- .../App/opendcm/moduleShape3d/module.hpp | 25 +- .../App/opendcm/moduleState/defines.hpp | 33 + .../moduleState/edge_vertex_generator.hpp | 4 +- .../moduleState/edge_vertex_parser.hpp | 7 +- .../App/opendcm/moduleState/extractor.hpp | 36 +- .../App/opendcm/moduleState/generator.hpp | 16 +- .../imp/edge_vertex_generator_imp.hpp | 58 + .../imp/edge_vertex_parser_imp.hpp | 55 + .../opendcm/moduleState/imp/generator_imp.hpp | 73 + .../opendcm/moduleState/imp/module_imp.hpp | 70 + .../moduleState/imp/object_generator_imp.hpp | 58 + .../moduleState/imp/object_parser_imp.hpp | 78 ++ .../opendcm/moduleState/imp/parser_imp.hpp | 77 ++ .../imp/property_generator_imp.hpp | 50 + .../moduleState/imp/property_parser_imp.hpp | 101 ++ .../opendcm/moduleState/imp/traits_impl.hpp | 185 +++ .../App/opendcm/moduleState/indent.hpp | 4 +- .../App/opendcm/moduleState/module.hpp | 44 +- .../opendcm/moduleState/object_generator.hpp | 4 +- .../App/opendcm/moduleState/object_parser.hpp | 29 +- .../App/opendcm/moduleState/parser.hpp | 18 +- .../moduleState/property_generator.hpp | 14 +- .../opendcm/moduleState/property_parser.hpp | 48 +- .../App/opendcm/moduleState/traits.hpp | 4 + src/Mod/Assembly/App/opendcm/modulestate.hpp | 51 + 62 files changed, 7308 insertions(+), 4860 deletions(-) create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/clustergraph_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/core/imp/transformation_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/clustermath_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/constraint3d_holder_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/constraint3d_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/geometry3d_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/module_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/solver_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/module3d/imp/state_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/edge_vertex_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/edge_vertex_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/module_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/object_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/object_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/property_generator_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/property_parser_imp.hpp create mode 100644 src/Mod/Assembly/App/opendcm/moduleState/imp/traits_impl.hpp diff --git a/src/Mod/Assembly/App/opendcm/core.hpp b/src/Mod/Assembly/App/opendcm/core.hpp index f878620bdf8d..8808cf6f7db6 100644 --- a/src/Mod/Assembly/App/opendcm/core.hpp +++ b/src/Mod/Assembly/App/opendcm/core.hpp @@ -43,5 +43,14 @@ #include "core/kernel.hpp" #include "core/system.hpp" + +#ifdef DCM_EXTERNAL_CORE + +#define DCM_EXTERNAL_CORE_INCLUDE_01 "opendcm/core/imp/system_imp.hpp" +#define DCM_EXTERNAL_CORE_01( Sys )\ + template class dcm::System; \ + +#endif //external + #endif //DCM_CORE_H diff --git a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp index 44b6ac6bf2fe..4d4c00012458 100644 --- a/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp +++ b/src/Mod/Assembly/App/opendcm/core/clustergraph.hpp @@ -21,9 +21,6 @@ #define CLUSTERGRAPH_HPP #include -#include -#include -#include #include #include @@ -32,25 +29,16 @@ #include #include -#include -#include #include #include #include -#include -#include -#include #include #include #include -#include -#include #include "property.hpp" -#include -#include #include @@ -71,20 +59,6 @@ namespace details { /** @addtogroup Metafunctions * @{*/ -/** - * @brief Appends a mpl sequences to another - * - * Makes two sequence to one by appending all types of the first to the second sequence. The new - * mpl sequence can be accessed by the ::type typedef. - * Usage: @code vector_fold::type @endcode - * - * @tparam state the mpl sequence which will be expanded - * @tparam seq the mpl sequence which will be appended - **/ -template -struct vector_fold : mpl::fold < seq, state, - mpl::push_back > {}; - /** * @brief Creates a fusion::vector of boost shared_ptr's from the given types * @@ -106,8 +80,6 @@ struct sps { //shared_ptr sequence typedef mpl::vector1 bgl_v_props; typedef mpl::vector1 bgl_e_props; - - typedef boost::adjacency_list_traits list_traits; @@ -162,7 +134,7 @@ struct IDgen { /** * @brief Set the current value for incremental creation * - * ID's are created incrementaly and if a specific startingpoint is whised it can be set here by + * ID's are created incrementaly and if a specific startingpoint is wished it can be set here by * supplying the last created ID or the amount of totaly created ID's * * @param id The last created ID @@ -183,19 +155,6 @@ struct cluster_error : virtual boost::exception {}; **/ typedef boost::shared_ptr IDpointer; -/** @ingroup Functors - * @brief Functor to clear vertex or edge objects - * - * All objects are boost::shared_ptr, therefore they can be cleared by calling the reset() method. As - * objects are stored within fusion::sequences a functor is needed to clear all of them. - **/ -struct clear_ptr { - template - void operator()(T& t) const { - t.reset(); - }; -}; - } /** @name Descriptors */ @@ -345,21 +304,18 @@ public boost::noncopyable, typedef std::map > ClusterMap; -private: + struct global_extractor { typedef GlobalEdge& result_type; template - result_type operator()(T& bundle) const { - return fusion::at_c<1> (bundle); - }; + result_type operator()(T& bundle) const; }; + struct global_vertex_extractor { typedef GlobalVertex result_type; ClusterGraph& graph; - global_vertex_extractor(ClusterGraph& g) : graph(g) {}; - result_type operator()(LocalVertex& v) const { - return graph.getGlobalVertex(v); - }; + global_vertex_extractor(ClusterGraph& g); + result_type operator()(LocalVertex& v) const; }; template @@ -371,54 +327,10 @@ public boost::noncopyable, typedef typename mpl::distance::type, iterator>::type distance; BOOST_MPL_ASSERT((mpl::not_::type > >)); - result_type operator()(vertex_bundle& bundle) const { - return fusion::at (fusion::at_c<2> (bundle)); - }; - result_type operator()(edge_bundle_single& bundle) const { - return fusion::at (fusion::at_c<0> (bundle)); - }; - }; - - template - struct property_extractor { - - typedef typename prop::type base_type; - typedef base_type& result_type; - - typedef typename mpl::if_< is_edge_property, edge_properties, vertex_properties >::type sequence; - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - typedef typename mpl::if_< is_edge_property, mpl::int_<0>, mpl::int_<1> >::type pos; - - template< typename seq> - result_type operator()(seq& b) const { - return fusion::at (fusion::at (b)); - }; + result_type operator()(vertex_bundle& bundle) const; + result_type operator()(edge_bundle_single& bundle) const; }; - struct edge_copier { - edge_copier(const ClusterGraph& g1, ClusterGraph& g2) - : graph1(g1), graph2(g2) { } - - void operator()(LocalEdge e1, LocalEdge e2) const { - graph2[e2] = graph1[e1]; - } - const ClusterGraph& graph1; - ClusterGraph& graph2; - }; - - struct vertex_copier { - vertex_copier(const ClusterGraph& g1, ClusterGraph& g2) - : graph1(g1), graph2(g2) { } - - void operator()(LocalVertex v1, LocalVertex v2) const { - graph2[v2] = graph1[v1]; - } - const ClusterGraph& graph1; - ClusterGraph& graph2; - }; - -public: //iterators /** * @brief Iterator for global edge descriptors \ref GlobalEdge @@ -490,52 +402,7 @@ public boost::noncopyable, * copied graph */ template - void copyInto(boost::shared_ptr into, Functor& functor) const { - - //lists does not provide vertex index, so we have to build our own (cant use the internal - //vertex_index_property as we would need to reset the indices and that's not possible in const graph) - typedef std::map IndexMap; - IndexMap mapIndex; - boost::associative_property_map propmapIndex(mapIndex); - - std::pair vit = boost::vertices(*this); - - for(int c = 0; vit.first != vit.second; vit.first++, c++) - put(propmapIndex, *vit.first, c); - - //first copy all vertices and edges, but be aware that the objects in the new graph - //are also copys only and point to the old graph. there is a bug in older boost version - //(<1.5 i belive) that breaks vertex_all propety map for bundled properties, so we - //have to create our own copie functors - into->clear(); - vertex_copier vc(*this, *into); - edge_copier ec(*this, *into); - boost::copy_graph(*this, *into, boost::vertex_index_map(propmapIndex).vertex_copy(vc).edge_copy(ec)); - - //set the IDgen to the same value to avoid duplicate id's in the copied cluster - into->m_id->setCount(m_id->count()); - - //now that we have all vertices we can recreate the subclusters - std::pair it = clusters(); - - for(; it.first != it.second; it.first++) { - //create the new Graph - boost::shared_ptr ng = boost::shared_ptr (new ClusterGraph(into)); - - //we already have the new vertex, however, we need to find it - GlobalVertex gv = getGlobalVertex((*it.first).first); - LocalVertex lv = into->getLocalVertex(gv).first; - - //add the new graph to the subclustermap - into->m_clusters[lv] = ng; - - //copy the subcluster - (*it.first).second->copyInto(ng, functor); - } - - //lets see if the objects need special treatment - into->for_each_object(functor, false); - }; + void copyInto(boost::shared_ptr into, Functor& functor) const; /** * @brief Compare by adress, not by content @@ -543,9 +410,7 @@ public boost::noncopyable, * @return bool if this is the same cluster in memory **/ template - bool operator== (const T& other) const { - return this == &other; - }; + bool operator== (const T& other) const; /** * @brief Compare by adress, not by content @@ -553,9 +418,7 @@ public boost::noncopyable, * @return bool if this is the not same cluster in memory **/ template - bool operator!= (const T& other) const { - return !(this == &other); - }; + bool operator!= (const T& other) const; /** * @brief Set diffrent behaviour for changed markers @@ -566,9 +429,7 @@ public boost::noncopyable, * @param on Turn change markers on or of * @return void **/ - void setCopyMode(bool on) { - copy_mode = on; - }; + void setCopyMode(bool on); //Make sure the compiler finds the base class setters even with equal named functions in this class using PropertyOwner::getProperty; @@ -583,19 +444,14 @@ public boost::noncopyable, * @param v the local vertex which describes the subcluster **/ template - typename P::type& getSubclusterProperty(LocalVertex v) { - return getVertexCluster(v)->template getProperty

(); - }; + typename P::type& getSubclusterProperty(LocalVertex v); /** * @brief Mark if the cluster was changed * * @return void **/ - void setChanged() { - if(!copy_mode) - PropertyOwner::template setProperty (true); - }; + void setChanged(); /* ******************************************************* @@ -612,12 +468,7 @@ public boost::noncopyable, * * @return :pair< boost::shared_ptr< ClusterGraph >, LocalVertex > Subcluster and its descriptor **/ - std::pair, LocalVertex> createCluster() { - vertex_bundle vp; - fusion::at_c<0> (vp) = m_id->generate(); - LocalVertex v = boost::add_vertex(vp, *this); - return std::pair, LocalVertex> (m_clusters[v] = boost::shared_ptr (new ClusterGraph(sp_base::shared_from_this())), v); - }; + std::pair, LocalVertex> createCluster(); /** * @brief Returns the parent cluster @@ -627,45 +478,35 @@ public boost::noncopyable, * * @return :shared_ptr< ClusterGraph > the parent cluster or empty pointer **/ - inline boost::shared_ptr parent() { - return boost::shared_ptr (m_parent); - }; + boost::shared_ptr parent(); /** * @brief const version of \ref parent() * * @return :shared_ptr< ClusterGraph > **/ - inline const boost::shared_ptr parent() const { - return boost::shared_ptr (m_parent); - }; + const boost::shared_ptr parent() const; /** * @brief Is this the toplevel cluster? * * @return bool if it is **/ - bool isRoot() const { - return m_parent.expired(); - }; + bool isRoot() const; /** * @brief Returns the toplevel cluster * * @return :shared_ptr< ClusterGraph > **/ - boost::shared_ptr root() { - return isRoot() ? sp_base::shared_from_this() : parent()->root(); - }; + boost::shared_ptr root(); /** * @brief const equivalent of \ref root() * * @return :shared_ptr< ClusterGraph > **/ - const boost::shared_ptr root() const { - return isRoot() ? sp_base::shared_from_this() : parent()->root(); - }; + const boost::shared_ptr root() const; /** * @brief Iterators for all subclusters @@ -675,27 +516,21 @@ public boost::noncopyable, * * @return :pair< cluster_iterator, cluster_iterator > **/ - std::pair clusters() { - return std::make_pair(m_clusters.begin(), m_clusters.end()); - } + std::pair clusters(); /** * @brief const equivalent to \ref clusters() * * @return :pair< const_cluster_iterator, const_cluster_iterator > **/ - std::pair clusters() const { - return std::make_pair(m_clusters.begin(), m_clusters.end()); - } + std::pair clusters() const; /** * @brief The amount of all subclusters * * @return :size_t **/ - std::size_t numClusters() const { - return m_clusters.size(); - } + std::size_t numClusters() const; /** * @brief Check if this vertex is a cluster @@ -708,9 +543,7 @@ public boost::noncopyable, * @param v The vertex to be checked * @return bool is cluster or not **/ - bool isCluster(LocalVertex v) { - return (m_clusters.find(v) != m_clusters.end()); - }; + bool isCluster(const dcm::LocalVertex v) const; /** * @brief Get the cluster corresponding the discriptor @@ -723,13 +556,7 @@ public boost::noncopyable, * @param v The vertex for which the cluster is wanted * @return boost::shared_ptr the coresponding cluster orempty pointer **/ - boost::shared_ptr getVertexCluster(LocalVertex v) { - if(isCluster(v)) - return m_clusters[v]; - - //TODO:throw if not a cluster - return sp_base::shared_from_this(); - }; + boost::shared_ptr getVertexCluster(LocalVertex v); /** * @brief Get the vertex descrptor which descripes the clusters position in the graph @@ -739,40 +566,24 @@ public boost::noncopyable, * @param g the graph for which the vertex is searched * @return :LocalVertex **/ - LocalVertex getClusterVertex(boost::shared_ptr g) { - std::pair it = clusters(); - - for(; it.first != it.second; it.first++) { - if((*it.first).second == g) - return (*it.first).first; - } - - throw details::cluster_error() << boost::errinfo_errno(12) << error_message("Cluster is not part of this graph"); - }; + LocalVertex getClusterVertex(boost::shared_ptr g); /** * @brief Convinience function for \ref removeCluster **/ template - void removeCluster(boost::shared_ptr g, Functor& f) { - removeCluster(getClusterVertex(g), f); - }; + void removeCluster(boost::shared_ptr g, Functor& f); /** * @brief Convinience function for \ref removeCluster **/ - void removeCluster(boost::shared_ptr g) { - placehoder p; - removeCluster(getClusterVertex(g), p); - }; + void removeCluster(boost::shared_ptr g); /** * @brief Delete all subcluster * * @return void **/ - void clearClusters() { - m_clusters.clear(); - }; + void clearClusters(); /** * @brief Remove a subcluster and applys the functor to all removed edges and vertices @@ -786,58 +597,12 @@ public boost::noncopyable, * @param f Functor to apply on all graph elements */ template - void removeCluster(LocalVertex v, Functor& f) { - - typename ClusterMap::iterator it = m_clusters.find(v); - - if(it == m_clusters.end()) - throw details::cluster_error() << boost::errinfo_errno(11) << error_message("Cluster is not part of this graph"); - - std::pair > res = *it; - - //apply functor to all vertices and edges in the subclusters - f(res.second); - res.second->remove_vertices(f, true); - - //remove from map, delete subcluster and remove vertex - m_clusters.erase(v); - boost::clear_vertex(v, *this); //should not be needed, just to ensure it - boost::remove_vertex(v, *this); - }; - void removeCluster(LocalVertex v) { - placehoder p; - removeCluster(v, p); - }; + void removeCluster(LocalVertex v, Functor& f); + void removeCluster(LocalVertex v); protected: template - void remove_vertices(Functor& f, bool recursive = false) { - - std::pair vit = boost::vertices(*this); - - //we iterate forward before deleting to not invalidate our iterator - while(vit.first != vit.second) { - LocalVertex v = * (vit.first); - vit.first++; - - if(!isCluster(v)) { - //let the functor know we remove this vertex - f(getGlobalVertex(v)); - //need to do this to allow the removal of all relevant edges to this vertex, even upstream - removeVertex(v, f); - } - }; - - if(recursive) { - cluster_iterator cit; - - for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { - f((*cit).second); - (*cit).second->remove_vertices(f, recursive); - } - } - }; - + void remove_vertices(Functor& f, bool recursive = false); /* ******************************************************* @@ -850,16 +615,20 @@ public boost::noncopyable, * * @return fusion::vector the local and global vertex descriptor **/ - fusion::vector addVertex() { - - vertex_bundle vp; - fusion::at_c<0> (vp) = m_id->generate(); - LocalVertex v = boost::add_vertex(vp, *this); - - setChanged(); - return fusion::make_vector(v, m_id->count()); - }; + fusion::vector addVertex(); + /** + * @brief Add a vertex to the local cluster with given global identifier + * + * Sometimes it is needed to add a vertex with given global identifier. As the global vertex can not + * be changed after creation, this method can be used to specify the global vertex by which this + * graph vertex can be identified. The given global vertex is not checked, you need to ensure that + * it is a unique id. The ID generator is changed so that it creates only identifier bigger than v. + * + * @return fusion::vector the local and global vertex descriptor + **/ + fusion::vector addVertex(GlobalVertex v); + /** * @brief Iterators of all global vertices in this cluster * @@ -868,13 +637,7 @@ public boost::noncopyable, * * @return std::pair< global_vertex_iterator, global_vertex_iterator > global vertex iterators **/ - std::pair globalVertices() { - std::pair res = boost::vertices(*this); - global_vertex_iterator begin = boost::make_transform_iterator(res.first, global_vertex_extractor(*this)); - global_vertex_iterator end = boost::make_transform_iterator(res.second, global_vertex_extractor(*this)); - - return std::pair (begin, end); - }; + std::pair globalVertices(); /** * @brief Returns the edge between the local vertices @@ -886,9 +649,7 @@ public boost::noncopyable, * @return std::pair with the local edge descriptor if existing. The bool value shows if the * edge exists or not **/ - std::pair edge(LocalVertex source, LocalVertex target) { - return boost::edge(source, target, *this); - }; + std::pair edge(LocalVertex source, LocalVertex target); /** * @brief Add a edge between two vertices, defined by local descriptors. @@ -903,32 +664,7 @@ public boost::noncopyable, * @return fusion::vector with the local and global descriptors of the edge and an bool * value indicationg the successful creation. **/ - fusion::vector addEdge(LocalVertex source, LocalVertex target) { - - //manual edge creation with cluster is not allowed - if((source == target) || isCluster(source) || isCluster(target)) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false); - - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(source, target, *this); - - //if done=true the edge alredy existed - if(!done) - boost::tie(e, done) = boost::add_edge(source, target, *this); - - if(!done) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false); - - //init the bundle corecctly for new edge - GlobalEdge global = { fusion::at_c<0> ((*this) [source]), fusion::at_c<0> ((*this) [target]), m_id->generate() }; - edge_bundle_single s; - fusion::at_c<1> (s) = global; - fusion::at_c<1> ((*this) [e]).push_back(s); - - setChanged(); - return fusion::make_vector(e, global, true); - }; + fusion::vector addEdge(LocalVertex source, LocalVertex target); /** * @brief Add a edge between two vertices, defined by global descriptors. @@ -947,48 +683,9 @@ public boost::noncopyable, * one where it was added. Success indicates if the function was successful and scope shows the validy of the local * descriptor in this cluster (true means the edge is in this cluster). **/ - fusion::vector addEdge(GlobalVertex source, GlobalVertex target) { - - LocalVertex v1, v2; - LocalEdge e; - bool d1, d2, d3; - boost::tie(v1, d1) = getContainingVertex(source); - boost::tie(v2, d2) = getContainingVertex(target); - - //if one vertex is not accessible from here this function fails - if(!(d1 && d2)) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); - - //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here - if(v1 == v2 && isCluster(v1)) { - fusion::vector res = getVertexCluster(v1)->addEdge(source, target); - fusion::at_c<3> (res) = false; - return res; - } - - //check if we already have that Local edge - boost::tie(e, d3) = boost::edge(v1, v2, *this); - - if(!d3) - boost::tie(e, d3) = boost::add_edge(v1, v2, *this); - - if(!d3) - return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + fusion::vector addEdge(GlobalVertex source, GlobalVertex target); - //init the bundle corectly for new edge - GlobalEdge global = { source, target, m_id->generate() }; - edge_bundle_single s; - fusion::at_c<1> (s) = global; - fusion::at_c<1> ((*this) [e]).push_back(s); - - setChanged(); - return fusion::make_vector(e, global, true, true); - - }; - - fusion::vector addEdgeGlobal(GlobalVertex source, GlobalVertex target) { - return addEdge(source, target); - }; + fusion::vector addEdgeGlobal(GlobalVertex source, GlobalVertex target); /** * @brief Get an iterator to all the global edges hold by this local edge @@ -1001,15 +698,7 @@ public boost::noncopyable, * @return std::pair with the global_edge_iterator's pointing to the vector's start * and end **/ - std::pair getGlobalEdges(LocalEdge e) { - - std::vector& vec = fusion::at_c<1> ((*this) [e]); - global_edge_iterator begin = boost::make_transform_iterator(vec.begin(), global_extractor()); - global_edge_iterator end = boost::make_transform_iterator(vec.end(), global_extractor()); - - setChanged(); - return std::pair (begin, end); - }; + std::pair getGlobalEdges(LocalEdge e); /** * @brief Get the count of all global edges @@ -1021,10 +710,7 @@ public boost::noncopyable, * @return std::pair with the global_edge_iterator's pointing to the vector's start * and end **/ - int getGlobalEdgeCount(LocalEdge e) { - - return fusion::at_c<1> ((*this) [e]).size(); - }; + int getGlobalEdgeCount(LocalEdge e); /** * @brief Get the local edge which holds the specified global edge. @@ -1036,9 +722,7 @@ public boost::noncopyable, * @param e GlobalEdge for which the containing local one is wanted * @return std:pair< LocalEdge, bool > with the containing LocalEdge and a bool indicator if function was successful. **/ - std::pair getLocalEdge(GlobalEdge e) { - return getContainingEdge(e); - }; + std::pair getLocalEdge(GlobalEdge e); /** * @brief Get the local edge which holds the specified global one and the subcluster in which it is valid. @@ -1049,9 +733,7 @@ public boost::noncopyable, * @param e GlobalEdge for which the containing local one is wanted * @return fusion::vector with the containing LocalEdge, the cluster which holds it and a bool indicator if function was successful. **/ - fusion::vector getLocalEdgeGraph(GlobalEdge e) { - return getContainingEdgeGraph(e); - }; + fusion::vector getLocalEdgeGraph(GlobalEdge e); /** * @brief Get the GlobalVertex assiociated with this local one. @@ -1059,24 +741,7 @@ public boost::noncopyable, * @param v LocalVertex * @return GlobalVertex **/ - GlobalVertex getGlobalVertex(LocalVertex v) const { - return fusion::at_c<0> ((*this) [v]); - }; - - /** - * @brief Set the GlobalVertex assiociated with this local one. - * - * Be carefull, LocalVertices get an global value assigned while created, override it only when your - * are sure that it is unique - * - * @param lv LocalVertex which sould get assigned the global one - * @param gv The value which the localVertex should get assigned - * @return GlobalVertex which was assigned - **/ - GlobalVertex setGlobalVertex(LocalVertex lv, GlobalVertex gv) { - fusion::at_c<0> ((*this) [lv]) = gv; - return gv; - }; + GlobalVertex getGlobalVertex(LocalVertex v) const; /** * @brief Get the LocalVertex which corresponds to the golab one @@ -1087,9 +752,7 @@ public boost::noncopyable, * @param vertex GlobalVertex for which the local one shall be returned * @return std::pair< LocalVertex, bool > The LocalVertex containing the global one and an success indicator **/ - std::pair getLocalVertex(GlobalVertex vertex) { - return getContainingVertex(vertex); - }; + std::pair getLocalVertex(GlobalVertex vertex); /** * @brief Get the local vertex which holds the specified global one and the subcluster in which it is valid. @@ -1100,9 +763,7 @@ public boost::noncopyable, * @param v GlobalVertex for which the containing local one is wanted * @return fusion::vector with the containing LocalVertex, the cluster which holds it and a bool indicator if function was successful. **/ - fusion::vector, bool> getLocalVertexGraph(GlobalVertex v) { - return getContainingVertexGraph(v); - }; + fusion::vector, bool> getLocalVertexGraph(GlobalVertex v); /* ******************************************************* @@ -1111,76 +772,9 @@ public boost::noncopyable, private: template - struct apply_remove_prediacte { - Functor& func; - GlobalVertex vert; - GlobalEdge edge; - bool isEdge; - - apply_remove_prediacte(Functor& f, GlobalVertex v) : func(f), vert(v), isEdge(false) {}; - apply_remove_prediacte(Functor& f, GlobalEdge e) : func(f), edge(e), vert(0), isEdge(true) {}; - bool operator()(edge_bundle_single& e) { - bool res; - - //this predicate can be used to compare the edge itself or the vertives it connects. See - //if we are a relevant edge - if(isEdge) - res = (edge == fusion::at_c<1> (e)); - else - res = (vert == fusion::at_c<1> (e).source) || (vert == fusion::at_c<1> (e).target); - - //we are a hit, invoke the functor. - if(res || vert < 0) - func(fusion::at_c<1> (e)); - - return res || vert < 0; - } - }; + void downstreamRemoveVertex(GlobalVertex v, Functor& f); - struct placehoder { - template - void operator()(T t) {}; - }; - - template - void downstreamRemoveVertex(GlobalVertex v, Functor& f) { - - std::pair res = getContainingVertex(v); - - //we don't throw, as this function gets invoked recursivly and it may happen that the - //vertex to remove is only in the top layers, not the button ones - if(!res.second) - return; - - - //iterate over every edge that connects to the global vertex or the cluster in which it is in - std::vector re; //remove edges - std::pair it = boost::out_edges(res.first, *this); - - for(; it.first != it.second; it.first++) { - std::vector& vec = fusion::at_c<1> ((*this) [* (it.first)]); - vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (f, v)), vec.end()); - - if(vec.empty()) - re.push_back(* (it.first)); - }; - - std::for_each(re.begin(), re.end(), boost::bind(&ClusterGraph::simpleRemoveEdge, this, _1)); - - //if we have the real vertex here and not only a containing cluster we can delete it - if(!isCluster(res.first)) { - boost::clear_vertex(res.first, *this); //just to make sure, should be done already - boost::remove_vertex(res.first, *this); - }; - - //lets go downstream - for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) - ((*it).second)->downstreamRemoveVertex(v, f); - }; - - void simpleRemoveEdge(LocalEdge e) { - boost::remove_edge(e, *this); - }; + void simpleRemoveEdge(LocalEdge e); public: @@ -1196,17 +790,9 @@ public boost::noncopyable, * @param f functor whose operator(GlobalEdge) is called for every removed edge **/ template - void removeVertex(LocalVertex id, Functor& f) { - //it is important to delete the global vertex, not the only local one as it's possible that - //we are in a subcluster and there are connections to the global vertex in the parent. They - //need to be deleted too. - removeVertex(getGlobalVertex(id), f); - }; + void removeVertex(LocalVertex id, Functor& f); //no default template arguments for template functions allowed before c++0x, so a little workaround - void removeVertex(LocalVertex id) { - placehoder p; - removeVertex(getGlobalVertex(id), p); - }; + void removeVertex(LocalVertex id) ; /** * @brief Removes a vertex from the cluster or it's subclusters and applys functor to removed edges @@ -1219,14 +805,9 @@ public boost::noncopyable, * @param f functor whose operator(LocalEdge) is called on every removed edge **/ template - void removeVertex(GlobalVertex id, Functor& f) { - root()->downstreamRemoveVertex(id, f); - }; + void removeVertex(GlobalVertex id, Functor& f); //no default template arguments for template functions allowed before c++0x, so a little workaround - void removeVertex(GlobalVertex id) { - placehoder p; - removeVertex(id, p); - }; + void removeVertex(GlobalVertex id); /** * @brief Removes a global Edge from the cluster or it's subclusters @@ -1237,19 +818,7 @@ public boost::noncopyable, * @param id Global Edge which should be removed from the graph * @return bool indicates if the global id could be removed **/ - void removeEdge(GlobalEdge id) { - fusion::vector res = getContainingEdgeGraph(id); - - if(!fusion::at_c<2> (res)) - return; //TODO:throw - - placehoder p; - std::vector& vec = fusion::at_c<1> ((*fusion::at_c<1> (res)) [fusion::at_c<0> (res)]); - vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (p, id)), vec.end()); - - if(vec.empty()) - boost::remove_edge(fusion::at_c<0> (res), *fusion::at_c<1> (res)); - }; + void removeEdge(GlobalEdge id); /** * @brief Removes a local edge from the cluster and calls the functor for all removed global edges @@ -1262,89 +831,12 @@ public boost::noncopyable, * @return bool indicates if the global id could be removed **/ template - void removeEdge(LocalEdge id, Functor& f) { - - std::vector& vec = fusion::at_c<1> ((*this) [id]); - std::for_each(vec.begin(), vec.end(), boost::bind (boost::ref(apply_remove_prediacte (f, -1)), _1)); - boost::remove_edge(id, *this); - }; + void removeEdge(LocalEdge id, Functor& f); /* ******************************************************* * Object Handling * *******************************************************/ - -protected: - //types needed to distinguish when objects need to be reset - struct get : public boost::false_type {}; - struct set : public boost::true_type {}; - - template - struct obj_helper { - - typedef typename object_extractor::result_type result_type; - - obj_helper(key k) : m_key(k) {}; - - //used with vertex bundle type - template - typename boost::enable_if < boost::is_same::type>, - result_type >::type operator()(bundle& p) { - - if(Type::value) - fusion::for_each(fusion::at_c<2> (p), details::clear_ptr()); - - return object_extractor()(p); - } - - //used with edge bundle type and global edge descriptor - template - typename boost::enable_if < mpl::and_ < boost::is_same::type>, - boost::is_same > , result_type >::type operator()(bundle& p) { - - edge_single_iterator e; - //need to search the edge_bundle for the global descriptor - std::vector& ebsv = fusion::at_c<1> (p); - - for(edge_single_iterator it = ebsv.begin(); it != ebsv.end(); it++) { - if(global_extractor()(*it) == m_key) { - if(Type::value) - fusion::for_each(fusion::at_c<0> (*it), details::clear_ptr()); - - e = it; - break; - } - } - - return object_extractor()(*e); - } - - //used with edge bundle type and local edge descriptor - template - typename boost::enable_if < mpl::and_ < boost::is_same::type>, - boost::is_same > , result_type >::type operator()(bundle& p) { - if(Type::value) - fusion::for_each(fusion::at_c<0> (fusion::at_c<1> (p).front()), details::clear_ptr()); - - return object_extractor()(fusion::at_c<1> (p).front()); - } - - key m_key; - }; - - template - struct valid_ptr_apply { - - Functor& func; - valid_ptr_apply(Functor& f) : func(f) {}; - - template - void operator()(Ptr& p) const { - if(p) - func(p); - } - }; - public: /** @@ -1360,9 +852,7 @@ public boost::noncopyable, * @return shared_ptr< Obj > the pointer to the desired object **/ template - boost::shared_ptr getObject(key k) { - return apply_to_bundle(k, obj_helper (k)); - }; + boost::shared_ptr getObject(key k); /** * @brief Set a object at the specified vertex or edge @@ -1378,11 +868,7 @@ public boost::noncopyable, * @return void **/ template - void setObject(key k, boost::shared_ptr val) { - apply_to_bundle(k, obj_helper (k)) = val; - - setChanged(); - }; + void setObject(key k, boost::shared_ptr val); /** * @brief Get iterator range for all GlobalEdge objects hold by this local edge @@ -1395,13 +881,7 @@ public boost::noncopyable, * @return pair< begin, end > the iterator rang from begin (first element) to end (first undefined element) **/ template - std::pair< object_iterator, object_iterator > getObjects(LocalEdge k) { - - std::vector& vec = fusion::at_c<1> ((*this) [k]); - object_iterator begin(vec.begin(), object_extractor()); - object_iterator end(vec.end(), object_extractor()); - return std::pair< object_iterator, object_iterator > (begin, end); - }; + std::pair< object_iterator, object_iterator > getObjects(LocalEdge k); /** * @brief Applys the functor to each occurence of an object @@ -1416,37 +896,7 @@ public boost::noncopyable, * @param recursive specifies if the subclusters should be searched for objects too **/ template - void for_each(Functor& f, bool recursive = false) { - - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - boost::shared_ptr ptr = getObject (* (it.first)) ; - - if(ptr) - f(ptr); - } - - std::pair eit = boost::edges(*this); - - for(; eit.first != eit.second; eit.first++) { - std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects (* (eit.first)); - - for(; goit.first != goit.second; goit.first++) { - if(*goit.first) - f(*goit.first); - } - } - - if(recursive) { - cluster_iterator cit; - - for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { - f((*cit).second); - (*cit).second->template for_each (f, recursive); - } - } - }; + void for_each(Functor& f, bool recursive = false); /** * @brief Applys the functor to each object @@ -1460,76 +910,12 @@ public boost::noncopyable, * @param recursive specifies if the subclusters should be searched for objects too **/ template - void for_each_object(Functor& f, bool recursive = false) { - - valid_ptr_apply func(f); - - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - typename details::sps::type& seq = fusion::at_c<2> ((*this) [*it.first]); - fusion::for_each(seq, func); - } - - typedef typename std::vector::iterator iter; - std::pair eit = boost::edges(*this); - - for(; eit.first != eit.second; eit.first++) { - std::vector& vec = fusion::at_c<1> ((*this) [*eit.first]); - - for(iter git = vec.begin(); git != vec.end(); git++) { - typename details::sps::type& seq = fusion::at_c<0> (*git); - fusion::for_each(seq, func); - } - } - - if(recursive) { - cluster_iterator cit; - - for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { - f((*cit).second); - (*cit).second->for_each_object(f, recursive); - } - } - }; + void for_each_object(Functor& f, bool recursive = false); /* ******************************************************* * Property Handling * *******************************************************/ -protected: - - template - struct get_prop_helper { - - get_prop_helper(key k) : m_key(k) {}; - - typedef typename prop::type base_type; - typedef base_type& result_type; - typedef typename mpl::find::type vertex_iterator; - typedef typename mpl::find::type edge_iterator; - typedef typename mpl::if_ < boost::is_same::type >, - edge_iterator, vertex_iterator >::type iterator; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - - //used with vertex bundle type - template - typename boost::enable_if < boost::is_same::type>, - result_type >::type operator()(bundle& p) { - return property_extractor()(p); - } - - //used with edge bundle type - template - typename boost::enable_if < boost::is_same::type>, - result_type >::type operator()(bundle& p) { - return property_extractor()(p); - } - - key m_key; - }; - -public: /** * @brief Get the desired property at the specified vertex or edge * @@ -1542,9 +928,7 @@ public boost::noncopyable, * @return property::type& the reference to the desired property **/ template - typename property::type& getProperty(key k) { - return apply_to_bundle(k, get_prop_helper (k)); - }; + typename property::type& getProperty(key k); /** * @brief Set a property at the specified vertex or edge @@ -1559,11 +943,7 @@ public boost::noncopyable, * @return void **/ template - void setProperty(key k, typename property::type val) { - apply_to_bundle(k, get_prop_helper (k)) = val; - - setChanged(); - }; + void setProperty(key k, typename property::type val); /** * @brief recreate the internal index maps for edges and vertices @@ -1575,19 +955,7 @@ public boost::noncopyable, * * @return void **/ - void initIndexMaps() { - - //just iterate over all edges and vertices and give them all a unique index - std::pair vit = boost::vertices(*this); - - for(int c = 0; vit.first != vit.second; vit.first++, c++) - setProperty(*vit.first, c); - - std::pair eit = boost::edges(*this); - - for(int c = 0; eit.first != eit.second; eit.first++, c++) - setProperty(*eit.first, c); - }; + void initIndexMaps(); @@ -1605,11 +973,7 @@ public boost::noncopyable, * @param cg reference to the subcluster to which v should be moved * @return LocalVertex the local descriptor of the moved vertex in the subcluster **/ - LocalVertex moveToSubcluster(LocalVertex v, boost::shared_ptr cg) { - - LocalVertex cv = getClusterVertex(cg); - return moveToSubcluster(v, cv, cg); - }; + LocalVertex moveToSubcluster(LocalVertex v, boost::shared_ptr cg); /** * @brief Move a vertex to a subcluster @@ -1621,11 +985,7 @@ public boost::noncopyable, * @param Cluster the local vertex descriptor representing the subcluster to which v should be moved * @return LocalVertex the local descriptor of the moved vertex in the subcluster **/ - LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster) { - - boost::shared_ptr cg = getVertexCluster(Cluster); - return moveToSubcluster(v, Cluster, cg); - }; + LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster); /** * @brief Move a vertex to a subcluster @@ -1642,88 +1002,7 @@ public boost::noncopyable, * @param cg reference to the subcluster to which v should be moved * @return LocalVertex the local descriptor of the moved vertex in the subcluster **/ - LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg) { - - std::pair it = boost::out_edges(v, *this); - - /* add the later removed edges to the coressponding existing edges - * (or create new edges between adjacent vertices of moved vertex and cluster). - * also get the edge between cluster and vertex while iterating */ - for(; it.first != it.second; it.first++) { - - LocalVertex target = boost::target(*it.first, *this); - - if(target != Cluster) { - - //get or create the edge between the old edge target and the cluster - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(target, Cluster, *this); - - if(!done) - boost::tie(e, done) = boost::add_edge(target, Cluster, *this); - - //if(!done) TODO: throw - - std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); - std::vector& nep = fusion::at_c<1> ((*this) [e]); - nep.insert(nep.end(), ep.begin(), ep.end()); - } - } - - /* Create new Vertex in Cluster and map the edge to vertices and clusters in the cluster - * if a connection existed */ - LocalVertex nv = boost::add_vertex((*this) [v], *cg); - - //resort cluster parentship if needed - if(isCluster(v)) { - - cg->m_clusters[nv] = m_clusters[v]; - cg->m_clusters[nv]->m_parent = cg; - m_clusters.erase(v); - } - - std::pair moveedge = boost::edge(v, Cluster, *this); - - if(moveedge.second) { - std::vector& vec = fusion::at_c<1> ((*this) [moveedge.first]); - - for(edge_single_iterator i = vec.begin(); i != vec.end(); i++) { - - //get the global vertex to which the global edge points and find the local vertex holding this - //global one - GlobalEdge global = global_extractor()(*i); - GlobalVertex target; - //bit cumbersome to support moving clusters - target = (cg->getContainingVertex(global.source).first == nv) ? global.target : global.source; - std::pair res = cg->getContainingVertex(target); - //if(!res.second) TODO: throw - - //get or create the edge between the new vertex and the target - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(nv, res.first, *cg); - - if(!done) - boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); - - //if(!done) TODO: throw - - //push the global edge to the local edge - fusion::at_c<1> ((*cg) [e]).push_back(*i); - }; - } - - //all global edges concerning the move vertex are processed and it is moved to the subcluster, - //lets destroy it in the local cluster - boost::clear_vertex(v, *this); - boost::remove_vertex(v, *this); - - setChanged(); - cg->setChanged(); - - return nv; - }; + LocalVertex moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg); /** @@ -1739,96 +1018,7 @@ public boost::noncopyable, * @param v Local vertex which should be moved to the parents cluster * @return LocalVertex the local descriptor of the moved vertex, valid in the parent cluster only. **/ - LocalVertex moveToParent(LocalVertex v) { - - //if(isRoot()) TODO:throw - - //create new vertex - vertex_bundle& vb = (*this) [v]; - LocalVertex nv = boost::add_vertex(vb, *parent()); - - //regrouping if needed - if(isCluster(v)) { - parent()->m_clusters[nv] = m_clusters[v]; - parent()->m_clusters[nv]->m_parent = m_parent; - m_clusters.erase(v); - } - - GlobalVertex gv = fusion::at_c<0> (vb); - - //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) - std::vector edge_vec; - LocalVertex this_v = parent()->getClusterVertex(sp_base::shared_from_this()); - std::pair it = boost::out_edges(this_v, *parent()); - - for(; it.first != it.second; it.first++) { - //iterate all global edges and find relevant ones - std::vector& vec = fusion::at_c<1> ((*parent()) [*it.first]); - edge_single_iterator i = vec.begin(); - - while(i != vec.end()) { - - GlobalEdge global = global_extractor()(*i); - GlobalVertex target; - - //a bit cumbersome to allow cluster moving - if(parent()->getContainingVertex(global.source).first == nv) - target = global.target; - else if(parent()->getContainingVertex(global.target).first == nv) - target = global.source; - else { - i++; - continue; - } - - std::pair res = parent()->getContainingVertex(target); - - //get or create the edge between the new vertex and the target - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(nv, res.first, *parent()); - - if(!done) - boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); - - //if(!done) TODO: throw - - //push the global edge bundle to the new local edge and erase it in the old - fusion::at_c<1> ((*parent()) [e]).push_back(*i); - i = vec.erase(i); - } - - //see if we should destroy this edge (no global edges remain in local one) - if(vec.empty()) - edge_vec.push_back(*it.first); - } - - //create a edge between new vertex and this cluster and add all global edges from within this cluster - it = boost::out_edges(v, *this); - LocalEdge e; - - if(it.first != it.second) - e = boost::add_edge(nv, this_v, *parent()).first; - - for(; it.first != it.second; it.first++) { - std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); - std::vector& nep = fusion::at_c<1> ((*parent()) [e]); - nep.insert(nep.end(), ep.begin(), ep.end()); - } - - //all global edges concerning the move vertex are processed and it is moved to the parent, - //lets destroy it in the local cluster - boost::clear_vertex(v, *this); - boost::remove_vertex(v, *this); - - //it's possible that some local edges in the parent are empty now, let's destroy them - for(std::vector::iterator it = edge_vec.begin(); it != edge_vec.end(); it++) - boost::remove_edge(*it, *parent()); - - setChanged(); - parent()->setChanged(); - return nv; - }; + LocalVertex moveToParent(LocalVertex v); /******************************************************** @@ -1837,6 +1027,7 @@ public boost::noncopyable, ClusterMap m_clusters; int test; + protected: boost::weak_ptr m_parent; details::IDpointer m_id; @@ -1849,140 +1040,35 @@ public boost::noncopyable, * be seached too, however, if found there the retourned local vertex will be the vertex * representing the toplevel cluster holding the global vertex in the initial graph. * */ - std::pair getContainingVertex(GlobalVertex id, bool recursive = true) { - - //check all vertices if they are the id - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - if(id == fusion::at_c<0> ((*this) [*it.first])) - return std::make_pair(*it.first, true); - } - - //check all clusters if they have the id - if(recursive) { - for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { - std::pair res = ((*it).second)->getContainingVertex(id); - - if(res.second) - return std::make_pair((*it).first, true); - } - } - - return std::make_pair((LocalVertex) NULL, false); - }; + std::pair getContainingVertex(GlobalVertex id, bool recursive = true); /* Searches the local vertex holding the specified global one in this and all it's subclusters. * If found, the holding local vertex and the graph in which it is valid will be returned. * */ - fusion::vector, bool> getContainingVertexGraph(GlobalVertex id) { - - LocalVertex v; - bool done; - boost::tie(v, done) = getContainingVertex(id); - - if(!done) - return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); - - if(isCluster(v) && (getGlobalVertex(v) != id)) - return m_clusters[v]->getContainingVertexGraph(id); - else - return fusion::make_vector(v, sp_base::shared_from_this(), true); - }; + fusion::vector, bool> getContainingVertexGraph(GlobalVertex id); /* Searches the global edge in all local edges of this graph, and returns the local * one which holds the global edge. If not successfull the local edge returned will be * invalid and the bool parameter will be false. * */ - std::pair getContainingEdge(GlobalEdge id) { - - LocalVertex v1, v2; - bool d1, d2; - boost::tie(v1, d1) = getContainingVertex(id.source, true); - boost::tie(v2, d2) = getContainingVertex(id.target, true); - - if(!((d1 && d2) && (v1 != v2))) - return std::make_pair(LocalEdge(), false); - - return boost::edge(v1, v2, *this); - }; + std::pair getContainingEdge(GlobalEdge id); /* Searches the local edge holding the specified global one in this and all it's subclusters. * If found, the holding local edge and the graph in which it is valid will be returned. * */ - fusion::vector getContainingEdgeGraph(GlobalEdge id) { - - LocalVertex v1, v2; - bool d1, d2; - boost::tie(v1, d1) = getContainingVertex(id.source, true); - boost::tie(v2, d2) = getContainingVertex(id.target, true); - - if(!(d1 && d2)) - return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); - - if(v1 == v2) - return m_clusters[v1]->getContainingEdgeGraph(id); - - return fusion::make_vector(boost::edge(v1, v2, *this).first, this, true); - }; + fusion::vector getContainingEdgeGraph(GlobalEdge id); template - typename functor::result_type apply_to_bundle(LocalVertex k, functor f) { - return f((*this) [k]); - }; + typename functor::result_type apply_to_bundle(LocalVertex k, functor f); template - typename functor::result_type apply_to_bundle(LocalEdge k, functor f) { - return f((*this) [k]); - }; + typename functor::result_type apply_to_bundle(LocalEdge k, functor f); template - typename functor::result_type apply_to_bundle(GlobalVertex k, functor f) { - - //check all vertices if they are the id - std::pair it = boost::vertices(*this); - - for(; it.first != it.second; it.first++) { - vertex_bundle& p = (*this) [*it.first]; - - if(k == fusion::at_c<0> (p)) - return f(p); - } - - //check all clusters if they have the object - fusion::vector, bool> res = getContainingVertexGraph(k); - - if(!fusion::at_c<2> (res)) { - //TODO: Throw (propeties return reference, but cant init a reference temporarily) - } - - return fusion::at_c<1> (res)->template apply_to_bundle (k, f); - }; + typename functor::result_type apply_to_bundle(GlobalVertex k, functor f); template - typename functor::result_type apply_to_bundle(GlobalEdge k, functor f) { - - LocalVertex v1, v2; - bool d1, d2; - boost::tie(v1, d1) = getContainingVertex(k.source); - boost::tie(v2, d2) = getContainingVertex(k.target); - - if(!(d1 && d2)) { - //TODO:Throw - } - - if((v1 == v2) && isCluster(v1)) - return m_clusters[v1]->apply_to_bundle(k, f); - else { - LocalEdge e; - bool done; - boost::tie(e, done) = boost::edge(v1, v2, *this); - //if(!done) TODO: throw, as there has to be a edge! - return f((*this) [e]); - }; - - - }; + typename functor::result_type apply_to_bundle(GlobalEdge k, functor f); public: //may hold cluster properties which have Eigen3 objects and therefore need alignment @@ -1995,6 +1081,10 @@ public boost::noncopyable, } //namespace dcm +#ifndef DCM_EXTERNAL_CORE +#include "imp/clustergraph_imp.hpp" +#endif + #endif // CLUSTERGRAPH_HPP diff --git a/src/Mod/Assembly/App/opendcm/core/constraint.hpp b/src/Mod/Assembly/App/opendcm/core/constraint.hpp index b4b857ff9c7b..a1e5bd9fe345 100644 --- a/src/Mod/Assembly/App/opendcm/core/constraint.hpp +++ b/src/Mod/Assembly/App/opendcm/core/constraint.hpp @@ -24,9 +24,6 @@ #include #include -#include -#include -#include #include #include @@ -36,13 +33,7 @@ #include #include - #include -#include -#include -#include -#include -#include #include @@ -61,8 +52,8 @@ namespace detail { //metafunction to avoid ot-of-range access of mpl sequences template struct in_range_value { - typedef typename mpl::prior >::type last_id; - typedef typename mpl::min< mpl::int_, last_id>::type type; + typedef typename mpl::prior >::type last_id; + typedef typename mpl::min< mpl::int_, last_id>::type type; }; //type erasure container for constraints @@ -119,22 +110,10 @@ class Constraint { inline void intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_); - int equationCount(); - - template< typename creator_type> - void resetType(creator_type& c); - + int equationCount(); void calculate(Scalar scale, bool rotation_only = false); void treatLGZ(); - void setMaps(MES& mes); - - void geometryReset(geom_ptr g) { - /* placeholder* p = content->resetConstraint(first, second); - delete content; - content = p;*/ - }; - void collectPseudoPoints(Vec& vec1, Vec& vec2); //Equation is the constraint with types, the EquationSet hold all needed Maps for calculation @@ -174,9 +153,13 @@ class Constraint { int value; public: - template< typename ConstraintVector, typename EquationVector> + template< typename ConstraintVector, typename tag1, typename tag2> struct holder : public placeholder { + //transform the constraints into eqautions with the now known types + typedef typename mpl::fold< ConstraintVector, mpl::vector<>, + mpl::push_back > >::type EquationVector; + //create a vector of EquationSets with some mpl trickery typedef typename mpl::fold< EquationVector, mpl::vector<>, mpl::push_back > >::type eq_set_vector; @@ -309,9 +292,7 @@ class Constraint { virtual void collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2); virtual placeholder* clone(); virtual int equationCount(); - virtual void disable() { - fusion::for_each(m_sets, disabler()); - }; + virtual void disable(); virtual std::vector getGenericEquations(); virtual std::vector getGenericConstraints(); @@ -330,599 +311,14 @@ class Constraint { geom_ptr first, second; }; - -/*****************************************************************************************************************/ -/*****************************************************************************************************************/ -/*****************************************************************************************************************/ -/*****************************************************************************************************************/ - - -template -Constraint::Constraint(geom_ptr f, geom_ptr s) - : first(f), second(s), content(0) { - - //cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); - //cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); -}; - -template -Constraint::~Constraint() { - delete content; - //first->template disconnectSignal(cf); - //second->template disconnectSignal(cs); -}; - -template -template -void Constraint::initializeFromTags(ConstraintVector& v) { - - typedef tag_order< tag1, tag2 > order; - - //transform the constraints into eqautions with the now known types - typedef typename mpl::fold< ConstraintVector, mpl::vector<>, - mpl::push_back > >::type EquationVector; - - //and build the placeholder - content = new holder(v); - - //geometry order needs to be the one needed by equations - if(order::swapt::value) - first.swap(second); -}; - -template -template -void Constraint::initialize(ConstraintVector& cv) { - - //use the compile time unrolling to retrieve the geometry tags - initializeFirstGeometry >(cv, mpl::true_()); -}; - -template -int Constraint::equationCount() { - return content->equationCount(); -}; - -template -template< typename creator_type> -void Constraint::resetType(creator_type& c) { - boost::apply_visitor(c, first->m_geometry, second->m_geometry); - content = c.p; - if(c.need_swap) - first.swap(second); -}; - -template -void Constraint::calculate(Scalar scale, bool rotation_only) { - content->calculate(first, second, scale, rotation_only); -}; - -template -void Constraint::treatLGZ() { - content->treatLGZ(first, second); -}; - -template -void Constraint::setMaps(MES& mes) { - content->setMaps(mes, first, second); -}; - -template -void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { - content->collectPseudoPoints(first, second, vec1, vec2); -}; - -template -std::vector Constraint::getGenericEquations() { - return content->getGenericEquations(); -}; - -template -std::vector Constraint::getGenericConstraints() { - return content->getGenericConstraints(); -}; - -template -std::vector Constraint::getEquationTypes() { - return content->getEquationTypes(); -}; - -template -std::vector Constraint::getConstraintTypes() { - return content->getConstraintTypes(); -}; - -template -template -Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; - -template -template -template -typename boost::enable_if::template holder::template has_option::type, void>::type -Constraint::holder::OptionSetter::operator()(EquationSet& val) const { - - //get the index of the corresbonding equation - typedef typename mpl::find::type iterator; - typedef typename mpl::distance::type, iterator>::type distance; - BOOST_MPL_ASSERT((mpl::not_::type > >)); - fusion::copy(fusion::at(objects).values, val.m_eq.values); - val.pure_rotation = fusion::at(objects).pure_rotation; -}; - -template -template -template -typename boost::enable_if::template holder::template has_option::type>, void>::type -Constraint::holder::OptionSetter::operator()(EquationSet& val) const { - -}; - -template -template -Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) - : first(f), second(s), scale(sc), rot_only(rotation_only) { - -}; - -template -template -template< typename T > -void Constraint::holder::Calculater::operator()(T& val) const { - - //if the equation is disabled we don't have anything mapped so avoid accessing it - if(!val.enabled) - return; - - //if we only need pure rotational functions and we are not such a nice thing, everything becomes 0 - if(rot_only && !val.pure_rotation) { - - val.m_residual(0) = 0; - if(first->getClusterMode()) { - if(!first->isClusterFixed()) { - val.m_diff_first_rot.setZero(); - val.m_diff_first.setZero(); - } - } - else - val.m_diff_first.setZero(); - - if(second->getClusterMode()) { - if(!second->isClusterFixed()) { - val.m_diff_second_rot.setZero(); - val.m_diff_second.setZero(); - } - } - else - val.m_diff_second.setZero(); - - } - //we need to calculate, so lets go for it! - else { - - val.m_eq.setScale(scale); - - val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); - - //now see which way we should calculate the gradient (may be diffrent for both geometries) - if(first->m_parameterCount) { - if(first->getClusterMode()) { - //when the cluster is fixed no maps are set as no parameters exist. - if(!first->isClusterFixed()) { - - //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors - for(int i=0; i<3; i++) { - val.m_diff_first_rot(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, first->m_diffparam.col(i)); - } - //and now with the translations - for(int i=0; i<3; i++) { - val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, first->m_diffparam.col(i+3)); - } - } - } - else { - //not in cluster, so allow the constraint to optimize the gradient calculation - val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); - } - } - if(second->m_parameterCount) { - if(second->getClusterMode()) { - if(!second->isClusterFixed()) { - - //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors - for(int i=0; i<3; i++) { - val.m_diff_second_rot(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, second->m_diffparam.col(i)); - } - //and the translation seperated - for(int i=0; i<3; i++) { - val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, - second->m_parameter, second->m_diffparam.col(i+3)); - } - } - } - else { - //not in cluster, so allow the constraint to optimize the gradient calculation - val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); - } - } - } -}; - -template -template -Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) - : mes(m), first(f), second(s) { - -}; - -template -template -template< typename T > -void Constraint::holder::MapSetter::operator()(T& val) const { - - if(!val.enabled) - return; - - //when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat - //for every parameter in the geometry; - int equation = mes.setResidualMap(val.m_residual); - if(first->getClusterMode()) { - if(!first->isClusterFixed()) { - mes.setJacobiMap(equation, first->m_offset_rot, 3, val.m_diff_first_rot); - mes.setJacobiMap(equation, first->m_offset, 3, val.m_diff_first); - } - } - else - mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); - - - if(second->getClusterMode()) { - if(!second->isClusterFixed()) { - mes.setJacobiMap(equation, second->m_offset_rot, 3, val.m_diff_second_rot); - mes.setJacobiMap(equation, second->m_offset, 3, val.m_diff_second); - } - } - else - mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); -}; - -template -template -Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) - : first(f), second(s), points1(vec1), points2(vec2) { - -}; - -template -template -template< typename T > -void Constraint::holder::PseudoCollector::operator()(T& val) const { - - if(!val.enabled) - return; - - if(first->m_isInCluster && second->m_isInCluster) { - val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); - } - else - if(first->m_isInCluster) { - typename Kernel::Vector sec = second->m_parameter; - val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); - } - else - if(second->m_isInCluster) { - typename Kernel::Vector fir = first->m_parameter; - val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); - } -}; - -template -template -Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) - : first(f), second(s) { - -}; - -template -template -template< typename T > -void Constraint::holder::LGZ::operator()(T& val) const { - - typedef typename Sys::Kernel Kernel; - - if(!val.enabled) - return; - - //to treat local gradient zeros we calculate a approximate second derivative of the equations - //only do that if neseccary: residual is not zero - if(!Kernel::isSame(val.m_residual(0),0, 1e-7)) { //TODO: use exact precission and scale value - - //rotations exist only in cluster - if(first->getClusterMode() && !first->isClusterFixed()) { - //LGZ exists for rotations only - for(int i=0; i<3; i++) { - - //only treat if the gradient realy is zero - if(Kernel::isSame(val.m_diff_first_rot(i), 0, 1e-7)) { - - //to get the approximated second derivative we need the slightly moved geometrie - const typename Kernel::Vector p_old = first->m_parameter; - first->m_parameter += first->m_diffparam.col(i)*1e-3; - first->normalize(); - //with this changed geometrie we test if a gradient exist now - typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); - typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); - first->m_parameter = p_old; - - //let's see if the initial LGZ was a real one - if(!Kernel::isSame(res, 0, 1e-7)) { - - //is a fake zero, let's correct it - val.m_diff_first_rot(i) = res; - }; - }; - }; - } - //and the same for the second one too - if(second->getClusterMode() && !second->isClusterFixed()) { - - for(int i=0; i<3; i++) { - - //only treat if the gradient realy is zero - if(Kernel::isSame(val.m_diff_second_rot(i), 0, 1e-7)) { - - //to get the approximated second derivative we need the slightly moved geometrie - const typename Kernel::Vector p_old = second->m_parameter; - second->m_parameter += second->m_diffparam.col(i)*1e-3; - second->normalize(); - //with this changed geometrie we test if a gradient exist now - typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); - typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, - second->m_parameter, block); - second->m_parameter = p_old; - - //let's see if the initial LGZ was a real one - if(!Kernel::isSame(res, 0, 1e-7)) { - - //is a fake zero, let's correct it - val.m_diff_second_rot(i) = res; - }; - }; - }; - }; - }; -}; - -template -template -Constraint::holder::GenericEquations::GenericEquations(std::vector& v) - : vec(v) { - -}; - -template -template -template< typename T > -void Constraint::holder::GenericEquations::operator()(T& val) const { - vec.push_back(val.m_eq); -}; - -template -template -Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) - : vec(v) { - -}; - -template -template -template< typename T > -void Constraint::holder::GenericConstraints::operator()(T& val) const { - vec.push_back(val); -}; - -template -template -Constraint::holder::Types::Types(std::vector& v) - : vec(v) { - -}; - -template -template -template< typename T > -void Constraint::holder::Types::operator()(T& val) const { - vec.push_back(&typeid(T)); -}; - -template -template -Constraint::holder::holder(Objects& obj) : m_objects(obj) { - //set the initial values in the equations - fusion::for_each(m_sets, OptionSetter(obj)); -}; - -template -template -void Constraint::holder::calculate(geom_ptr first, geom_ptr second, - Scalar scale, bool rotation_only) { - fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only)); -}; - -template -template -void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { - fusion::for_each(m_sets, LGZ(first, second)); -}; - -template -template -typename Constraint::placeholder* -Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { - //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); - //if(creator.need_swap) first.swap(second); - return NULL; -}; - -template -template -void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { - fusion::for_each(m_sets, MapSetter(mes, first, second)); -}; - -template -template -void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { - fusion::for_each(m_sets, PseudoCollector(f, s, vec1, vec2)); -}; - -template -template -typename Constraint::placeholder* -Constraint::holder::clone() { - return new holder(*this); -}; - -template -template -int Constraint::holder::equationCount() { - int count = 0; - EquationCounter counter(count); - fusion::for_each(m_sets, counter); - return count; -}; - -template -template -std::vector -Constraint::holder::getGenericEquations() { - std::vector vec; - fusion::for_each(m_sets, GenericEquations(vec)); - return vec; -}; - -template -template -std::vector -Constraint::holder::getGenericConstraints() { - std::vector vec; - fusion::for_each(m_objects, GenericConstraints(vec)); - return vec; -}; - -template -template -std::vector -Constraint::holder::getEquationTypes() { - std::vector vec; - mpl::for_each< EquationVector >(Types(vec)); - return vec; -}; - -template -template -std::vector -Constraint::holder::getConstraintTypes() { - std::vector vec; - mpl::for_each< ConstraintVector >(Types(vec)); - return vec; -}; - -/****************************************************************/ -/** compiletime unrolled geometry initialising */ -/****************************************************************/ - -template -template -void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { - //this function is only for breaking the compilation loop, it should never be called - BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist -}; - -template -template -void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { - - typedef typename Sys::geometries geometries; - - switch(first->getExactType()) { - -#ifdef BOOST_PP_LOCAL_ITERATE -#define BOOST_PP_LOCAL_MACRO(n) \ - case (WhichType::value + n): \ - return initializeSecondGeometry,\ - typename mpl::at::type >::type,\ - ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ - break; -#define BOOST_PP_LOCAL_LIMITS (0, 10) -#include BOOST_PP_LOCAL_ITERATE() -#endif //BOOST_PP_LOCAL_ITERATE - default: - typedef typename mpl::int_ next_which_t; - return initializeFirstGeometry (cv, - typename mpl::less< next_which_t, typename mpl::size::type >::type()); - } -}; - -template -template -void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { - //this function is only for breaking the compilation loop, it should never be called - BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist -}; - -template -template -void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { - - typedef typename Sys::geometries geometries; - switch(second->getExactType()) { - -#ifdef BOOST_PP_LOCAL_ITERATE -#define BOOST_PP_LOCAL_MACRO(n) \ - case (WhichType::value + n): \ - return intitalizeFinalize::type >::type,\ - ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ - break; -#define BOOST_PP_LOCAL_LIMITS (0, 10) -#include BOOST_PP_LOCAL_ITERATE() -#endif //BOOST_PP_LOCAL_ITERATE - default: - typedef typename mpl::int_ next_which_t; - return initializeSecondGeometry - (cv, typename mpl::less - < next_which_t - , typename mpl::size::type>::type() - ); - } -}; - -template -template -inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_ /*is_unrolled_t*/) { - - initializeFromTags(cv); -}; - -template -template -inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::false_ /*is_unrolled_t*/) { - //Should never be here at runtime; only required to block code generation that deref's the sequence out of bounds - BOOST_ASSERT(false); -} - - - };//detail - };//dcm +#ifndef DCM_EXTERNAL_CORE +#include "imp/constraint_imp.hpp" +#include "imp/constraint_holder_imp.hpp" +#endif + #endif //GCM_CONSTRAINT_H diff --git a/src/Mod/Assembly/App/opendcm/core/equations.hpp b/src/Mod/Assembly/App/opendcm/core/equations.hpp index bc34e6d45fa8..6ef1b8be2c95 100644 --- a/src/Mod/Assembly/App/opendcm/core/equations.hpp +++ b/src/Mod/Assembly/App/opendcm/core/equations.hpp @@ -25,21 +25,13 @@ #include #include #include -#include #include #include #include -#include -#include -#include -#include -#include -#include -#include #include #include +#include #include - #include namespace fusion = boost::fusion; @@ -82,8 +74,8 @@ struct PseudoScale { //type to allow a metaprogramming check for a Equation struct EQ {}; -template -struct pushed_seq; +//template +//struct pushed_seq; //metafunctions to retrieve the options of an equation template @@ -112,66 +104,17 @@ struct constraint_sequence : public seq { std::cout<<"pretty: "<<__PRETTY_FUNCTION__< - typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T& val) { - - typedef typename pushed_seq::type Sequence; - typedef typename fusion::result_of::begin::type Begin; - typedef typename fusion::result_of::find::S1>::type >::type EndOld; - - - //create the new sequence - Sequence vec; - - //copy the old values into the new sequence - Begin b(vec); - EndOld eo(vec); - - fusion::iterator_range range(b, eo); - fusion::copy(*this, range); - - //insert this object at the end of the sequence - *fusion::find(vec) = val; - - //and return our new extendet sequence - return vec; - }; - - //an sequence gets added to this sequence (happens only if sequenced equations like coincident are used) - template - typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type operator &(T& val) { - - typedef typename pushed_seq::type Sequence; - typedef typename fusion::result_of::begin::type Begin; - typedef typename fusion::result_of::find::S1>::type >::type EndF; - - //create the new sequence - Sequence vec; - - Begin b(vec); - EndF ef(vec); - - fusion::iterator_range range(b, ef); - fusion::copy(val, range); - - //to copy the types of the second sequence is not as easy as before. If types were already present in - //the original sequence they are not added again. therefore we need to find all types of the second sequence - //in the new one and assign the objects to this positions. - - //get a index vector for all second-sequence-elements - typedef typename mpl::transform::S2, - fusion::result_of::distance::type, - fusion::result_of::find > >::type position_vector; - - //and copy the types in - fusion::nview view(vec); - fusion::copy(*this, view); - - //and return our new extendet sequence - return vec; - }; + //dont allow expression equation stacking: the compile time impact is huge if we want to allow + //text parsing + /* + //an equation gets added to this sequence + template + typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type operator &(T& val); + //an sequence gets added to this sequence (happens only if sequenced equations like coincident are used) + template + typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type operator &(T& val); + */ //we also allow to set values directly into the equation, as this makes it more compftable for multi constraints //as align. Note that this only works if all option types of all equations in this sequence are distinguishable template @@ -182,6 +125,13 @@ struct constraint_sequence : public seq { fusion::front(view) = val; return *this; }; + +}; + +/* +template +struct get_equation_id { + typedef typename T::ID type; }; template @@ -191,12 +141,13 @@ struct pushed_seq { typedef typename mpl::fold< S2, S1, mpl::if_< boost::is_same< mpl::find, mpl::end >, mpl::push_back, mpl::_1> >::type unique_vector; + typedef typename mpl::sort, get_equation_id > >::type sorted_vector; - typedef typename fusion::result_of::as_vector< unique_vector >::type vec; + typedef typename fusion::result_of::as_vector< sorted_vector >::type vec; typedef constraint_sequence type; -}; +};*/ -template +template struct Equation : public EQ { typedef typename mpl::if_, Option, mpl::vector

(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::setChanged() { + if(!copy_mode) + PropertyOwner::template setProperty (true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair >, LocalVertex> ClusterGraph::createCluster() { + vertex_bundle vp; + fusion::at_c<0> (vp) = m_id->generate(); + LocalVertex v = boost::add_vertex(vp, *this); + return std::pair, LocalVertex> (m_clusters[v] = boost::shared_ptr (new ClusterGraph(sp_base::shared_from_this())), v); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +inline boost::shared_ptr< ClusterGraph > +ClusterGraph:: parent() { + return boost::shared_ptr (m_parent); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +inline const boost::shared_ptr< ClusterGraph > +ClusterGraph::parent() const { + return boost::shared_ptr (m_parent); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +bool ClusterGraph::isRoot() const { + return m_parent.expired(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +boost::shared_ptr< ClusterGraph > +ClusterGraph::root() { + return isRoot() ? sp_base::shared_from_this() : parent()->root(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +const boost::shared_ptr< ClusterGraph > +ClusterGraph::root() const { + return isRoot() ? sp_base::shared_from_this() : parent()->root(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::cluster_iterator, typename ClusterGraph::cluster_iterator> +ClusterGraph::clusters() { + return std::make_pair(m_clusters.begin(), m_clusters.end()); +} + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::const_cluster_iterator, typename ClusterGraph::const_cluster_iterator> +ClusterGraph::clusters() const { + return std::make_pair(m_clusters.begin(), m_clusters.end()); +} + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::size_t +ClusterGraph::numClusters() const { + return m_clusters.size(); +} + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +bool ClusterGraph::isCluster(const LocalVertex v) const { + return (m_clusters.find(v) != m_clusters.end()); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +boost::shared_ptr< ClusterGraph > +ClusterGraph::getVertexCluster(LocalVertex v) { + if(isCluster(v)) + return m_clusters[v]; + + //TODO:throw if not a cluster + return sp_base::shared_from_this(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex ClusterGraph::getClusterVertex(boost::shared_ptr g) { + std::pair it = clusters(); + + for(; it.first != it.second; it.first++) { + if((*it.first).second == g) + return (*it.first).first; + } + + throw details::cluster_error() << boost::errinfo_errno(12) << error_message("Cluster is not part of this graph"); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeCluster(boost::shared_ptr g, Functor& f) { + removeCluster(getClusterVertex(g), f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeCluster(boost::shared_ptr g) { + placehoder p; + removeCluster(getClusterVertex(g), p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::clearClusters() { + m_clusters.clear(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeCluster(LocalVertex v, Functor& f) { + + typename ClusterMap::iterator it = m_clusters.find(v); + + if(it == m_clusters.end()) + throw details::cluster_error() << boost::errinfo_errno(11) << error_message("Cluster is not part of this graph"); + + std::pair > res = *it; + + //apply functor to all vertices and edges in the subclusters + f(res.second); + res.second->remove_vertices(f, true); + + //remove from map, delete subcluster and remove vertex + m_clusters.erase(v); + boost::clear_vertex(v, *this); //should not be needed, just to ensure it + boost::remove_vertex(v, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeCluster(LocalVertex v) { + placehoder p; + removeCluster(v, p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::remove_vertices(Functor& f, bool recursive) { + + std::pair vit = boost::vertices(*this); + + //we iterate forward before deleting to not invalidate our iterator + while(vit.first != vit.second) { + LocalVertex v = * (vit.first); + vit.first++; + + if(!isCluster(v)) { + //let the functor know we remove this vertex + f(getGlobalVertex(v)); + //need to do this to allow the removal of all relevant edges to this vertex, even upstream + removeVertex(v, f); + } + }; + + if(recursive) { + cluster_iterator cit; + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->remove_vertices(f, recursive); + } + } +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addVertex() { + + vertex_bundle vp; + fusion::at_c<0> (vp) = m_id->generate(); + LocalVertex v = boost::add_vertex(vp, *this); + + setChanged(); + return fusion::make_vector(v, m_id->count()); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addVertex(GlobalVertex gv) { + + vertex_bundle vp; + fusion::at_c<0> (vp) = gv; + LocalVertex v = boost::add_vertex(vp, *this); + + //ensure that we never create this id, as it is used now + if(gv > m_id->count()) + m_id->setCount(gv); + + setChanged(); + return fusion::make_vector(v, gv); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::global_vertex_iterator, typename ClusterGraph::global_vertex_iterator> +ClusterGraph::globalVertices() { + std::pair res = boost::vertices(*this); + global_vertex_iterator begin = boost::make_transform_iterator(res.first, global_vertex_extractor(*this)); + global_vertex_iterator end = boost::make_transform_iterator(res.second, global_vertex_extractor(*this)); + + return std::pair (begin, end); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::edge(LocalVertex source, LocalVertex target) { + return boost::edge(source, target, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addEdge(LocalVertex source, LocalVertex target) { + + //manual edge creation with cluster is not allowed + if((source == target) || isCluster(source) || isCluster(target)) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(source, target, *this); + + //if done=true the edge alredy existed + if(!done) + boost::tie(e, done) = boost::add_edge(source, target, *this); + + if(!done) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false); + + //init the bundle corecctly for new edge + GlobalEdge global = { fusion::at_c<0> ((*this) [source]), fusion::at_c<0> ((*this) [target]), m_id->generate() }; + edge_bundle_single s; + fusion::at_c<1> (s) = global; + fusion::at_c<1> ((*this) [e]).push_back(s); + + setChanged(); + return fusion::make_vector(e, global, true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addEdge(GlobalVertex source, GlobalVertex target) { + + LocalVertex v1, v2; + LocalEdge e; + bool d1, d2, d3; + boost::tie(v1, d1) = getContainingVertex(source); + boost::tie(v2, d2) = getContainingVertex(target); + + //if one vertex is not accessible from here this function fails + if(!(d1 && d2)) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + + //if both vertices are in a subcluster this one must do the job as we cant access the local edge from here + if(v1 == v2 && isCluster(v1)) { + fusion::vector res = getVertexCluster(v1)->addEdge(source, target); + fusion::at_c<3> (res) = false; + return res; + } + + //check if we already have that Local edge + boost::tie(e, d3) = boost::edge(v1, v2, *this); + + if(!d3) + boost::tie(e, d3) = boost::add_edge(v1, v2, *this); + + if(!d3) + return fusion::make_vector(LocalEdge(), GlobalEdge(), false, false); + + //init the bundle corectly for new edge + GlobalEdge global = { source, target, m_id->generate() }; + edge_bundle_single s; + fusion::at_c<1> (s) = global; + fusion::at_c<1> ((*this) [e]).push_back(s); + + setChanged(); + return fusion::make_vector(e, global, true, true); + +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector +ClusterGraph::addEdgeGlobal(GlobalVertex source, GlobalVertex target) { + return addEdge(source, target); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair::global_edge_iterator, typename ClusterGraph::global_edge_iterator> +ClusterGraph::getGlobalEdges(LocalEdge e) { + + std::vector& vec = fusion::at_c<1> ((*this) [e]); + global_edge_iterator begin = boost::make_transform_iterator(vec.begin(), global_extractor()); + global_edge_iterator end = boost::make_transform_iterator(vec.end(), global_extractor()); + + setChanged(); + return std::pair (begin, end); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +int ClusterGraph::getGlobalEdgeCount(LocalEdge e) { + + return fusion::at_c<1> ((*this) [e]).size(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getLocalEdge(GlobalEdge e) { + return getContainingEdge(e); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector*, bool> +ClusterGraph::getLocalEdgeGraph(GlobalEdge e) { + return getContainingEdgeGraph(e); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +GlobalVertex +ClusterGraph::getGlobalVertex(LocalVertex v) const { + return fusion::at_c<0> ((*this) [v]); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getLocalVertex(GlobalVertex vertex) { + return getContainingVertex(vertex); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector >, bool> +ClusterGraph::getLocalVertexGraph(GlobalVertex v) { + return getContainingVertexGraph(v); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::downstreamRemoveVertex(GlobalVertex v, Functor& f) { + + std::pair res = getContainingVertex(v); + + //we don't throw, as this function gets invoked recursivly and it may happen that the + //vertex to remove is only in the top layers, not the button ones + if(!res.second) + return; + + + //iterate over every edge that connects to the global vertex or the cluster in which it is in + std::vector re; //remove edges + std::pair it = boost::out_edges(res.first, *this); + + for(; it.first != it.second; it.first++) { + std::vector& vec = fusion::at_c<1> ((*this) [* (it.first)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (f, v)), vec.end()); + + if(vec.empty()) + re.push_back(* (it.first)); + }; + + std::for_each(re.begin(), re.end(), boost::bind(&ClusterGraph::simpleRemoveEdge, this, _1)); + + //if we have the real vertex here and not only a containing cluster we can delete it + if(!isCluster(res.first)) { + boost::clear_vertex(res.first, *this); //just to make sure, should be done already + boost::remove_vertex(res.first, *this); + }; + + //lets go downstream + for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) + ((*it).second)->downstreamRemoveVertex(v, f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::simpleRemoveEdge(LocalEdge e) { + boost::remove_edge(e, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeVertex(LocalVertex id, Functor& f) { + //it is important to delete the global vertex, not the only local one as it's possible that + //we are in a subcluster and there are connections to the global vertex in the parent. They + //need to be deleted too. + removeVertex(getGlobalVertex(id), f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeVertex(LocalVertex id) { + placehoder p; + removeVertex(getGlobalVertex(id), p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeVertex(GlobalVertex id, Functor& f) { + root()->downstreamRemoveVertex(id, f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeVertex(GlobalVertex id) { + placehoder p; + removeVertex(id, p); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::removeEdge(GlobalEdge id) { + fusion::vector res = getContainingEdgeGraph(id); + + if(!fusion::at_c<2> (res)) + return; //TODO:throw + + placehoder p; + std::vector& vec = fusion::at_c<1> ((*fusion::at_c<1> (res)) [fusion::at_c<0> (res)]); + vec.erase(std::remove_if(vec.begin(), vec.end(), apply_remove_prediacte (p, id)), vec.end()); + + if(vec.empty()) + boost::remove_edge(fusion::at_c<0> (res), *fusion::at_c<1> (res)); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::removeEdge(LocalEdge id, Functor& f) { + + std::vector& vec = fusion::at_c<1> ((*this) [id]); + std::for_each(vec.begin(), vec.end(), boost::bind (boost::ref(apply_remove_prediacte (f, -1)), _1)); + boost::remove_edge(id, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +boost::shared_ptr +ClusterGraph::getObject(key k) { + return apply_to_bundle(k, obj_helper (k)); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::setObject(key k, boost::shared_ptr val) { + apply_to_bundle(k, obj_helper (k)) = val; + + setChanged(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +std::pair< typename ClusterGraph::template object_iterator, typename ClusterGraph::template object_iterator > +ClusterGraph::getObjects(LocalEdge k) { + + std::vector& vec = fusion::at_c<1> ((*this) [k]); + object_iterator begin(vec.begin(), object_extractor()); + object_iterator end(vec.end(), object_extractor()); + return std::pair< object_iterator, object_iterator > (begin, end); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::for_each(Functor& f, bool recursive) { + + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + boost::shared_ptr ptr = getObject (* (it.first)) ; + + if(ptr) + f(ptr); + } + + std::pair eit = boost::edges(*this); + + for(; eit.first != eit.second; eit.first++) { + std::pair< object_iterator< Obj >, object_iterator< Obj > > goit = getObjects (* (eit.first)); + + for(; goit.first != goit.second; goit.first++) { + if(*goit.first) + f(*goit.first); + } + } + + if(recursive) { + cluster_iterator cit; + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->template for_each (f, recursive); + } + } +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::for_each_object(Functor& f, bool recursive) { + + valid_ptr_apply func(f); + + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + typename details::sps::type& seq = fusion::at_c<2> ((*this) [*it.first]); + fusion::for_each(seq, func); + } + + typedef typename std::vector::iterator iter; + std::pair eit = boost::edges(*this); + + for(; eit.first != eit.second; eit.first++) { + std::vector& vec = fusion::at_c<1> ((*this) [*eit.first]); + + for(iter git = vec.begin(); git != vec.end(); git++) { + typename details::sps::type& seq = fusion::at_c<0> (*git); + fusion::for_each(seq, func); + } + } + + if(recursive) { + cluster_iterator cit; + + for(cit = m_clusters.begin(); cit != m_clusters.end(); cit++) { + f((*cit).second); + (*cit).second->for_each_object(f, recursive); + } + } +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename property::type& +ClusterGraph::getProperty(key k) { + return apply_to_bundle(k, get_prop_helper (k)); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +void ClusterGraph::setProperty(key k, typename property::type val) { + apply_to_bundle(k, get_prop_helper (k)) = val; + + setChanged(); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +void ClusterGraph::initIndexMaps() { + + //just iterate over all edges and vertices and give them all a unique index + std::pair vit = boost::vertices(*this); + + for(int c = 0; vit.first != vit.second; vit.first++, c++) + setProperty(*vit.first, c); + + std::pair eit = boost::edges(*this); + + for(int c = 0; eit.first != eit.second; eit.first++, c++) + setProperty(*eit.first, c); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToSubcluster(LocalVertex v, boost::shared_ptr cg) { + + LocalVertex cv = getClusterVertex(cg); + return moveToSubcluster(v, cv, cg); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToSubcluster(LocalVertex v, LocalVertex Cluster) { + + boost::shared_ptr cg = getVertexCluster(Cluster); + return moveToSubcluster(v, Cluster, cg); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToSubcluster(LocalVertex v, LocalVertex Cluster, boost::shared_ptr cg) { + + std::pair it = boost::out_edges(v, *this); + + /* add the later removed edges to the coressponding existing edges + * (or create new edges between adjacent vertices of moved vertex and cluster). + * also get the edge between cluster and vertex while iterating */ + for(; it.first != it.second; it.first++) { + + LocalVertex target = boost::target(*it.first, *this); + + if(target != Cluster) { + + //get or create the edge between the old edge target and the cluster + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(target, Cluster, *this); + + if(!done) + boost::tie(e, done) = boost::add_edge(target, Cluster, *this); + + //if(!done) TODO: throw + + std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); + std::vector& nep = fusion::at_c<1> ((*this) [e]); + nep.insert(nep.end(), ep.begin(), ep.end()); + } + } + + /* Create new Vertex in Cluster and map the edge to vertices and clusters in the cluster + * if a connection existed */ + LocalVertex nv = boost::add_vertex((*this) [v], *cg); + + //resort cluster parentship if needed + if(isCluster(v)) { + + cg->m_clusters[nv] = m_clusters[v]; + cg->m_clusters[nv]->m_parent = cg; + m_clusters.erase(v); + } + + std::pair moveedge = boost::edge(v, Cluster, *this); + + if(moveedge.second) { + std::vector& vec = fusion::at_c<1> ((*this) [moveedge.first]); + + for(edge_single_iterator i = vec.begin(); i != vec.end(); i++) { + + //get the global vertex to which the global edge points and find the local vertex holding this + //global one + GlobalEdge global = global_extractor()(*i); + GlobalVertex target; + //bit cumbersome to support moving clusters + target = (cg->getContainingVertex(global.source).first == nv) ? global.target : global.source; + std::pair res = cg->getContainingVertex(target); + //if(!res.second) TODO: throw + + //get or create the edge between the new vertex and the target + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(nv, res.first, *cg); + + if(!done) + boost::tie(e, done) = boost::add_edge(nv, res.first, *cg); + + //if(!done) TODO: throw + + //push the global edge to the local edge + fusion::at_c<1> ((*cg) [e]).push_back(*i); + }; + } + + //all global edges concerning the move vertex are processed and it is moved to the subcluster, + //lets destroy it in the local cluster + boost::clear_vertex(v, *this); + boost::remove_vertex(v, *this); + + setChanged(); + cg->setChanged(); + + return nv; +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +LocalVertex +ClusterGraph::moveToParent(LocalVertex v) { + + //if(isRoot()) TODO:throw + + //create new vertex + vertex_bundle& vb = (*this) [v]; + LocalVertex nv = boost::add_vertex(vb, *parent()); + + //regrouping if needed + if(isCluster(v)) { + parent()->m_clusters[nv] = m_clusters[v]; + parent()->m_clusters[nv]->m_parent = m_parent; + m_clusters.erase(v); + } + + GlobalVertex gv = fusion::at_c<0> (vb); + + //get all out_edges of this cluster in the parentcluster (because only they can hold relevant global_Edgs) + std::vector edge_vec; + LocalVertex this_v = parent()->getClusterVertex(sp_base::shared_from_this()); + std::pair it = boost::out_edges(this_v, *parent()); + + for(; it.first != it.second; it.first++) { + //iterate all global edges and find relevant ones + std::vector& vec = fusion::at_c<1> ((*parent()) [*it.first]); + edge_single_iterator i = vec.begin(); + + while(i != vec.end()) { + + GlobalEdge global = global_extractor()(*i); + GlobalVertex target; + + //a bit cumbersome to allow cluster moving + if(parent()->getContainingVertex(global.source).first == nv) + target = global.target; + else if(parent()->getContainingVertex(global.target).first == nv) + target = global.source; + else { + i++; + continue; + } + + std::pair res = parent()->getContainingVertex(target); + + //get or create the edge between the new vertex and the target + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(nv, res.first, *parent()); + + if(!done) + boost::tie(e, done) = boost::add_edge(nv, res.first, *parent()); + + //if(!done) TODO: throw + + //push the global edge bundle to the new local edge and erase it in the old + fusion::at_c<1> ((*parent()) [e]).push_back(*i); + i = vec.erase(i); + } + + //see if we should destroy this edge (no global edges remain in local one) + if(vec.empty()) + edge_vec.push_back(*it.first); + } + + //create a edge between new vertex and this cluster and add all global edges from within this cluster + it = boost::out_edges(v, *this); + LocalEdge e; + + if(it.first != it.second) + e = boost::add_edge(nv, this_v, *parent()).first; + + for(; it.first != it.second; it.first++) { + std::vector& ep = fusion::at_c<1> ((*this) [*it.first]); + std::vector& nep = fusion::at_c<1> ((*parent()) [e]); + nep.insert(nep.end(), ep.begin(), ep.end()); + } + + //all global edges concerning the move vertex are processed and it is moved to the parent, + //lets destroy it in the local cluster + boost::clear_vertex(v, *this); + boost::remove_vertex(v, *this); + + //it's possible that some local edges in the parent are empty now, let's destroy them + for(std::vector::iterator it = edge_vec.begin(); it != edge_vec.end(); it++) + boost::remove_edge(*it, *parent()); + + setChanged(); + parent()->setChanged(); + return nv; +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getContainingVertex(GlobalVertex id, bool recursive) { + + //check all vertices if they are the id + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + if(id == fusion::at_c<0> ((*this) [*it.first])) + return std::make_pair(*it.first, true); + } + + //check all clusters if they have the id + if(recursive) { + for(cluster_iterator it = m_clusters.begin(); it != m_clusters.end(); it++) { + std::pair res = ((*it).second)->getContainingVertex(id); + + if(res.second) + return std::make_pair((*it).first, true); + } + } + + return std::make_pair((LocalVertex) NULL, false); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector >, bool> +ClusterGraph::getContainingVertexGraph(GlobalVertex id) { + + LocalVertex v; + bool done; + boost::tie(v, done) = getContainingVertex(id); + + if(!done) + return fusion::make_vector(LocalVertex(), boost::shared_ptr(), false); + + if(isCluster(v) && (getGlobalVertex(v) != id)) + return m_clusters[v]->getContainingVertexGraph(id); + else + return fusion::make_vector(v, sp_base::shared_from_this(), true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +std::pair +ClusterGraph::getContainingEdge(GlobalEdge id) { + + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(id.source, true); + boost::tie(v2, d2) = getContainingVertex(id.target, true); + + if(!((d1 && d2) && (v1 != v2))) + return std::make_pair(LocalEdge(), false); + + return boost::edge(v1, v2, *this); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +fusion::vector*, bool> +ClusterGraph::getContainingEdgeGraph(GlobalEdge id) { + + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(id.source, true); + boost::tie(v2, d2) = getContainingVertex(id.target, true); + + if(!(d1 && d2)) + return fusion::make_vector(LocalEdge(), (ClusterGraph*) NULL, false); + + if(v1 == v2) + return m_clusters[v1]->getContainingEdgeGraph(id); + + return fusion::make_vector(boost::edge(v1, v2, *this).first, this, true); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(LocalVertex k, functor f) { + return f((*this) [k]); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(LocalEdge k, functor f) { + return f((*this) [k]); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(GlobalVertex k, functor f) { + + //check all vertices if they are the id + std::pair it = boost::vertices(*this); + + for(; it.first != it.second; it.first++) { + vertex_bundle& p = (*this) [*it.first]; + + if(k == fusion::at_c<0> (p)) + return f(p); + } + + //check all clusters if they have the object + fusion::vector, bool> res = getContainingVertexGraph(k); + + if(!fusion::at_c<2> (res)) { + //TODO: Throw (propeties return reference, but cant init a reference temporarily) + } + + return fusion::at_c<1> (res)->template apply_to_bundle (k, f); +}; + +template< typename edge_prop, typename vertex_prop, typename cluster_prop, typename objects> +template +typename functor::result_type +ClusterGraph::apply_to_bundle(GlobalEdge k, functor f) { + + LocalVertex v1, v2; + bool d1, d2; + boost::tie(v1, d1) = getContainingVertex(k.source); + boost::tie(v2, d2) = getContainingVertex(k.target); + + if(!(d1 && d2)) { + //TODO:Throw + } + + if((v1 == v2) && isCluster(v1)) + return m_clusters[v1]->apply_to_bundle(k, f); + else { + LocalEdge e; + bool done; + boost::tie(e, done) = boost::edge(v1, v2, *this); + //if(!done) TODO: throw, as there has to be a edge! + return f((*this) [e]); + }; + + +}; + +} //namespace dcm + + +#endif // CLUSTERGRAPH_HPP + + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp new file mode 100644 index 000000000000..d4d34b2adddb --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/constraint_holder_imp.hpp @@ -0,0 +1,449 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_CONSTRAINT_HOLDER_IMP_H +#define DCM_CONSTRAINT_HOLDER_IMP_H + +#include "opendcm/core/constraint.hpp" + +#include +#include +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace detail { + + +template +template +Constraint::holder::OptionSetter::OptionSetter(Objects& val) : objects(val) {}; + +template +template +template +typename boost::enable_if::template holder::template has_option::type, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { + + //get the index of the corresbonding equation + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + fusion::copy(fusion::at(objects).values, val.m_eq.values); + val.pure_rotation = fusion::at(objects).pure_rotation; +}; + +template +template +template +typename boost::enable_if::template holder::template has_option::type>, void>::type +Constraint::holder::OptionSetter::operator()(EquationSet& val) const { + +}; + +template +template +Constraint::holder::Calculater::Calculater(geom_ptr f, geom_ptr s, Scalar sc, bool rotation_only) + : first(f), second(s), scale(sc), rot_only(rotation_only) { + +}; + +template +template +template< typename T > +void Constraint::holder::Calculater::operator()(T& val) const { + + //if the equation is disabled we don't have anything mapped so avoid accessing it + if(!val.enabled) + return; + + //if we only need pure rotational functions and we are not such a nice thing, everything becomes 0 + if(rot_only && !val.pure_rotation) { + + val.m_residual(0) = 0; + if(first->getClusterMode()) { + if(!first->isClusterFixed()) { + val.m_diff_first_rot.setZero(); + val.m_diff_first.setZero(); + } + } + else + val.m_diff_first.setZero(); + + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + val.m_diff_second_rot.setZero(); + val.m_diff_second.setZero(); + } + } + else + val.m_diff_second.setZero(); + + } + //we need to calculate, so lets go for it! + else { + + val.m_eq.setScale(scale); + + val.m_residual(0) = val.m_eq.calculate(first->m_parameter, second->m_parameter); + + //now see which way we should calculate the gradient (may be diffrent for both geometries) + if(first->m_parameterCount) { + if(first->getClusterMode()) { + //when the cluster is fixed no maps are set as no parameters exist. + if(!first->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<3; i++) { + val.m_diff_first_rot(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, first->m_diffparam.col(i)); + } + //and now with the translations + for(int i=0; i<3; i++) { + val.m_diff_first(i) = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, first->m_diffparam.col(i+3)); + } + } + } + else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientFirstComplete(first->m_parameter, second->m_parameter, val.m_diff_first); + } + } + if(second->m_parameterCount) { + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + + //cluster mode, so we do a full calculation with all 3 rotation diffparam vectors + for(int i=0; i<3; i++) { + val.m_diff_second_rot(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, second->m_diffparam.col(i)); + } + //and the translation seperated + for(int i=0; i<3; i++) { + val.m_diff_second(i) = val.m_eq.calculateGradientSecond(first->m_parameter, + second->m_parameter, second->m_diffparam.col(i+3)); + } + } + } + else { + //not in cluster, so allow the constraint to optimize the gradient calculation + val.m_eq.calculateGradientSecondComplete(first->m_parameter, second->m_parameter, val.m_diff_second); + } + } + } +}; + +template +template +Constraint::holder::MapSetter::MapSetter(MES& m, geom_ptr f, geom_ptr s) + : mes(m), first(f), second(s) { + +}; + +template +template +template< typename T > +void Constraint::holder::MapSetter::operator()(T& val) const { + + if(!val.enabled) + return; + + //when in cluster, there are 6 clusterparameter we differentiat for, if not we differentiat + //for every parameter in the geometry; + int equation = mes.setResidualMap(val.m_residual); + if(first->getClusterMode()) { + if(!first->isClusterFixed()) { + mes.setJacobiMap(equation, first->m_offset_rot, 3, val.m_diff_first_rot); + mes.setJacobiMap(equation, first->m_offset, 3, val.m_diff_first); + } + } + else + mes.setJacobiMap(equation, first->m_offset, first->m_parameterCount, val.m_diff_first); + + + if(second->getClusterMode()) { + if(!second->isClusterFixed()) { + mes.setJacobiMap(equation, second->m_offset_rot, 3, val.m_diff_second_rot); + mes.setJacobiMap(equation, second->m_offset, 3, val.m_diff_second); + } + } + else + mes.setJacobiMap(equation, second->m_offset, second->m_parameterCount, val.m_diff_second); +}; + +template +template +Constraint::holder::PseudoCollector::PseudoCollector(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) + : first(f), second(s), points1(vec1), points2(vec2) { + +}; + +template +template +template< typename T > +void Constraint::holder::PseudoCollector::operator()(T& val) const { + + if(!val.enabled) + return; + + if(first->m_isInCluster && second->m_isInCluster) { + val.m_eq.calculatePseudo(first->m_rotated, points1, second->m_rotated, points2); + } + else if(first->m_isInCluster) { + typename Kernel::Vector sec = second->m_parameter; + val.m_eq.calculatePseudo(first->m_rotated, points1, sec, points2); + } + else if(second->m_isInCluster) { + typename Kernel::Vector fir = first->m_parameter; + val.m_eq.calculatePseudo(fir, points1, second->m_rotated, points2); + } +}; + +template +template +Constraint::holder::LGZ::LGZ(geom_ptr f, geom_ptr s) + : first(f), second(s) { + +}; + +template +template +template< typename T > +void Constraint::holder::LGZ::operator()(T& val) const { + + typedef typename Sys::Kernel Kernel; + + if(!val.enabled) + return; + + //to treat local gradient zeros we calculate a approximate second derivative of the equations + //only do that if neseccary: residual is not zero + if(!Kernel::isSame(val.m_residual(0),0, 1e-7)) { //TODO: use exact precission and scale value + + //rotations exist only in cluster + if(first->getClusterMode() && !first->isClusterFixed()) { + //LGZ exists for rotations only + for(int i=0; i<3; i++) { + + //only treat if the gradient realy is zero + if(Kernel::isSame(val.m_diff_first_rot(i), 0, 1e-7)) { + + //to get the approximated second derivative we need the slightly moved geometrie + const typename Kernel::Vector p_old = first->m_parameter; + first->m_parameter += first->m_diffparam.col(i)*1e-3; + first->normalize(); + //with this changed geometrie we test if a gradient exist now + typename Kernel::VectorMap block(&first->m_diffparam(0,i),first->m_parameterCount,1, DS(1,1)); + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + first->m_parameter = p_old; + + //let's see if the initial LGZ was a real one + if(!Kernel::isSame(res, 0, 1e-7)) { + + //is a fake zero, let's correct it + val.m_diff_first_rot(i) = res; + }; + }; + }; + } + //and the same for the second one too + if(second->getClusterMode() && !second->isClusterFixed()) { + + for(int i=0; i<3; i++) { + + //only treat if the gradient realy is zero + if(Kernel::isSame(val.m_diff_second_rot(i), 0, 1e-7)) { + + //to get the approximated second derivative we need the slightly moved geometrie + const typename Kernel::Vector p_old = second->m_parameter; + second->m_parameter += second->m_diffparam.col(i)*1e-3; + second->normalize(); + //with this changed geometrie we test if a gradient exist now + typename Kernel::VectorMap block(&second->m_diffparam(0,i),second->m_parameterCount,1, DS(1,1)); + typename Kernel::number_type res = val.m_eq.calculateGradientFirst(first->m_parameter, + second->m_parameter, block); + second->m_parameter = p_old; + + //let's see if the initial LGZ was a real one + if(!Kernel::isSame(res, 0, 1e-7)) { + + //is a fake zero, let's correct it + val.m_diff_second_rot(i) = res; + }; + }; + }; + }; + }; +}; + +template +template +Constraint::holder::GenericEquations::GenericEquations(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::GenericEquations::operator()(T& val) const { + vec.push_back(val.m_eq); +}; + +template +template +Constraint::holder::GenericConstraints::GenericConstraints(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::GenericConstraints::operator()(T& val) const { + vec.push_back(val); +}; + +template +template +Constraint::holder::Types::Types(std::vector& v) + : vec(v) { + +}; + +template +template +template< typename T > +void Constraint::holder::Types::operator()(T& val) const { + vec.push_back(&typeid(T)); +}; + +template +template +Constraint::holder::holder(Objects& obj) : m_objects(obj) { + //set the initial values in the equations + fusion::for_each(m_sets, OptionSetter(obj)); +}; + +template +template +void Constraint::holder::calculate(geom_ptr first, geom_ptr second, + Scalar scale, bool rotation_only) { + fusion::for_each(m_sets, Calculater(first, second, scale, rotation_only)); +}; + +template +template +void Constraint::holder::treatLGZ(geom_ptr first, geom_ptr second) { + fusion::for_each(m_sets, LGZ(first, second)); +}; + +template +template +typename Constraint::placeholder* +Constraint::holder::resetConstraint(geom_ptr first, geom_ptr second) const { + //boost::apply_visitor(creator, first->m_geometry, second->m_geometry); + //if(creator.need_swap) first.swap(second); + return NULL; +}; + +template +template +void Constraint::holder::setMaps(MES& mes, geom_ptr first, geom_ptr second) { + fusion::for_each(m_sets, MapSetter(mes, first, second)); +}; + +template +template +void Constraint::holder::collectPseudoPoints(geom_ptr f, geom_ptr s, Vec& vec1, Vec& vec2) { + fusion::for_each(m_sets, PseudoCollector(f, s, vec1, vec2)); +}; + +template +template +typename Constraint::placeholder* +Constraint::holder::clone() { + return new holder(*this); +}; + +template +template +int Constraint::holder::equationCount() { + int count = 0; + EquationCounter counter(count); + fusion::for_each(m_sets, counter); + return count; +}; + +template +template +std::vector +Constraint::holder::getGenericEquations() { + std::vector vec; + fusion::for_each(m_sets, GenericEquations(vec)); + return vec; +}; + +template +template +std::vector +Constraint::holder::getGenericConstraints() { + std::vector vec; + fusion::for_each(m_objects, GenericConstraints(vec)); + return vec; +}; + +template +template +std::vector +Constraint::holder::getEquationTypes() { + std::vector vec; + mpl::for_each< EquationVector >(Types(vec)); + return vec; +}; + +template +template +std::vector +Constraint::holder::getConstraintTypes() { + std::vector vec; + mpl::for_each< ConstraintVector >(Types(vec)); + return vec; +}; + +template +template +void Constraint::holder::disable() { + fusion::for_each(m_sets, disabler()); +}; + +};//detail + +};//dcm + +#endif //GCM_CONSTRAINT_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp new file mode 100644 index 000000000000..902943644e53 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/constraint_imp.hpp @@ -0,0 +1,208 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_CONSTRAINT_IMP_H +#define DCM_CONSTRAINT_IMP_H + +#include "../constraint.hpp" + +#include +#include +#include +#include + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace detail { + + + +template +template +void Constraint::initialize(ConstraintVector& cv) { + + //use the compile time unrolling to retrieve the geometry tags + initializeFirstGeometry >(cv, mpl::true_()); +}; + +template +template +void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { + //this function is only for breaking the compilation loop, it should never be called + BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist +}; + +template +template +void Constraint::initializeFirstGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { + + typedef typename Sys::geometries geometries; + + switch(first->getExactType()) { + +#ifdef BOOST_PP_LOCAL_ITERATE +#define BOOST_PP_LOCAL_MACRO(n) \ + case (WhichType::value + n): \ + return initializeSecondGeometry,\ + typename mpl::at::type >::type,\ + ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ + break; +#define BOOST_PP_LOCAL_LIMITS (0, 10) +#include BOOST_PP_LOCAL_ITERATE() +#endif //BOOST_PP_LOCAL_ITERATE + default: + typedef typename mpl::int_ next_which_t; + return initializeFirstGeometry (cv, + typename mpl::less< next_which_t, typename mpl::size::type >::type()); + } +}; + +template +template +void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::false_ /*unrolled*/) { + //this function is only for breaking the compilation loop, it should never be called + BOOST_ASSERT(false); //Should never assert here; only meant to stop recursion at the end of the typelist +}; + +template +template +void Constraint::initializeSecondGeometry(ConstraintVector& cv, boost::mpl::true_ /*unrolled*/) { + + typedef typename Sys::geometries geometries; + switch(second->getExactType()) { + +#ifdef BOOST_PP_LOCAL_ITERATE +#define BOOST_PP_LOCAL_MACRO(n) \ + case (WhichType::value + n): \ + return intitalizeFinalize::type >::type,\ + ConstraintVector>(cv, typename boost::mpl::less, boost::mpl::size >::type()); \ + break; +#define BOOST_PP_LOCAL_LIMITS (0, 10) +#include BOOST_PP_LOCAL_ITERATE() +#endif //BOOST_PP_LOCAL_ITERATE + default: + typedef typename mpl::int_ next_which_t; + return initializeSecondGeometry + (cv, typename mpl::less + < next_which_t + , typename mpl::size::type>::type() + ); + } +}; + +template +template +inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::true_ /*is_unrolled_t*/) { + + initializeFromTags(cv); +}; + +template +template +inline void Constraint::intitalizeFinalize(ConstraintVector& cv, boost::mpl::false_ /*is_unrolled_t*/) { + //Should never be here at runtime; only required to block code generation that deref's the sequence out of bounds + BOOST_ASSERT(false); +} + +template +template +void Constraint::initializeFromTags(ConstraintVector& v) { + + typedef tag_order< tag1, tag2 > order; + + //and build the placeholder + content = new holder(v); + + //geometry order needs to be the one needed by equations + if(order::swapt::value) + first.swap(second); +}; + +template +Constraint::Constraint(geom_ptr f, geom_ptr s) + : first(f), second(s), content(0) { + + //cf = first->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); + //cs = second->template connectSignal (boost::bind(&Constraint::geometryReset, this, _1)); +}; + +template +Constraint::~Constraint() { + delete content; + //first->template disconnectSignal(cf); + //second->template disconnectSignal(cs); +}; + +template +int Constraint::equationCount() { + return content->equationCount(); +}; + +template +void Constraint::calculate(Scalar scale, bool rotation_only) { + content->calculate(first, second, scale, rotation_only); +}; + +template +void Constraint::treatLGZ() { + content->treatLGZ(first, second); +}; + +template +void Constraint::setMaps(MES& mes) { + content->setMaps(mes, first, second); +}; + +template +void Constraint::collectPseudoPoints(Vec& vec1, Vec& vec2) { + content->collectPseudoPoints(first, second, vec1, vec2); +}; + +template +std::vector Constraint::getGenericEquations() { + return content->getGenericEquations(); +}; + +template +std::vector Constraint::getGenericConstraints() { + return content->getGenericConstraints(); +}; + +template +std::vector Constraint::getEquationTypes() { + return content->getEquationTypes(); +}; + +template +std::vector Constraint::getConstraintTypes() { + return content->getConstraintTypes(); +}; + +};//detail + +};//dcm + +#endif //GCM_CONSTRAINT_H + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp new file mode 100644 index 000000000000..2090ac413766 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/equations_imp.hpp @@ -0,0 +1,255 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more detemplate tails. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_EQUATIONS_IMP_H +#define DCM_EQUATIONS_IMP_H + +#include + +#include "../equations.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace fusion = boost::fusion; +namespace mpl = boost::mpl; + +namespace dcm { + +template +struct pushed_seq; + +/* +template +template +typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type +constraint_sequence::operator &(T& val) { + + typedef typename pushed_seq::type Sequence; + + //create the new sequence + Sequence vec; + + //get a index vector for this sequence + typedef typename mpl::transform::S1, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector_added; + + //and copy the types in + fusion::nview view_added(vec); + fusion::copy(*this, view_added); + + //insert this object at the end of the sequence + *fusion::find(vec) = val; + + //and return our new extendet sequence + return vec; +}; + +template +template +typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type +constraint_sequence::operator &(T& val) { + + typedef typename pushed_seq::type Sequence; + + //create the new sequence + Sequence vec; + + //get a index vector for the added sequence + typedef typename mpl::transform::S1, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector_added; + + //and copy the types in + fusion::nview view_added(vec); + fusion::copy(val, view_added); + + //to copy the types of the second sequence is not as easy as before. If types were already present in + //the original sequence they are not added again. therefore we need to find all types of the second sequence + //in the new one and assign the objects to this positions. + + //get a index vector for all second-sequence-elements + typedef typename mpl::transform::S2, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector; + + //and copy the types in + fusion::nview view(vec); + fusion::copy(*this, view); + + //and return our new extendet sequence + return vec; +}; +*/ +template +struct option_copy { + + options* values; + option_copy(options& op) : values(&op) {}; + + template + void operator()(const T& val) const { + if(val.second.first) + fusion::at_key(*values) = val.second; + }; +}; + +template +Derived& Equation::assign(const Derived& eq) { + + //we only copy the values which were set and are therefore valid + option_copy oc(values); + fusion::for_each(eq.values, oc); + + //the assigned eqution can be set back to default for convinience in further usage + const_cast(&eq)->setDefault(); + + return *static_cast(this); +}; + +/* +template +template +typename boost::enable_if< boost::is_base_of< dcm::EQ, T>, typename pushed_seq::type >::type +Equation::operator &(T& val) { + + typename pushed_seq::type vec; + *fusion::find(vec) = val; + *fusion::find(vec) = *(static_cast(this)); + return vec; +}; + +template +template +typename boost::enable_if< mpl::is_sequence, typename pushed_seq::type >::type +Equation::operator &(T& val) { + + typedef typename pushed_seq::type Sequence; + + //create the new sequence + Sequence vec; + + //get a index vector for the added sequence + typedef typename mpl::transform::S1, + fusion::result_of::distance::type, + fusion::result_of::find > >::type position_vector; + + //and copy the types in + fusion::nview view(vec); + fusion::copy(val, view); + + //insert this object into the sequence + *fusion::find(vec) = *static_cast(this); + + //and return our new extendet sequence + return vec; +}; +*/ + +template +void Equation::setDefault() { + fusion::at_key(values) = std::make_pair(false, 0.); + fusion::at_key(values) = std::make_pair(false, bidirectional); +}; + +//convinience stream functions for debugging +template +struct print_pair { + std::basic_ostream* stream; + + template + void operator()(const T& t) const { + *stream << "("< +typename boost::enable_if, std::basic_ostream&>::type +operator << (std::basic_ostream& stream, const Eq& equation) +{ + print_pair pr; + pr.stream = &stream; + stream << typeid(equation).name() << ": "; + fusion::for_each(equation.values, pr); + return stream; +} + +Distance::Distance() : Equation() { + setDefault(); +}; + +Distance& Distance::operator=(const Distance& d) { + return Equation::assign(d); +}; + +void Distance::setDefault() {}; + + + +Orientation::Orientation() : Equation() { + setDefault(); +}; + +Orientation& Orientation::operator=(const Orientation& d) { + return Equation::assign(d); +}; + +void Orientation::setDefault() { + fusion::at_key(values) = std::make_pair(false, parallel); +}; + +Angle::Angle() : Equation() { + setDefault(); +}; + +Angle& Angle::operator=(const Angle& d) { + return Equation::assign(d); +}; + +void Angle::setDefault() { + fusion::at_key(values) = std::make_pair(false, 0.); + fusion::at_key(values) = std::make_pair(false, bidirectional); +}; + + +}; + +#endif //GCM_EQUATIONS_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp new file mode 100644 index 000000000000..91b76fce50f9 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/geometry_imp.hpp @@ -0,0 +1,266 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#ifndef GCM_GEOMETRY_IMP_H +#define GCM_GEOMETRY_IMP_H + +#include + +#include "../geometry.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef USE_LOGGING +#include +#endif + +namespace mpl = boost::mpl; +namespace fusion = boost::fusion; + +namespace dcm { + +namespace details { + +template< typename Kernel, int Dim, typename TagList> +Geometry::Geometry() + : m_isInCluster(false), m_parameter(NULL,0,DS(0,0)), + m_clusterFixed(false), m_init(false) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Geometry")); +#endif + +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::transform(const Transform& t) { + + if(m_isInCluster) + transform(t, m_toplocal); + else + if(m_init) + transform(t, m_rotated); + else + transform(t, m_global); +}; + +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::init() { + + m_BaseParameterCount = tag::parameters::value; + m_parameterCount = m_BaseParameterCount; + m_rotations = tag::rotations::value; + m_translations = tag::translations::value; + + m_toplocal.setZero(m_parameterCount); + m_global.resize(m_parameterCount); + m_rotated.resize(m_parameterCount); + m_rotated.setZero(); + + m_diffparam.resize(m_parameterCount,6); + m_diffparam.setZero(); + + m_general_type = tag::weight::value; + m_exact_type = mpl::find::type::pos::value; + + normalize(); + + //new value which is not set into parameter, so init is false + m_init = false; + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Init: "< +void Geometry::normalize() { + //directions are not nessessarily normalized, but we need to ensure this in cluster mode + for(int i=m_translations; i!=m_rotations; i++) + m_global.template segment(i*Dim).normalize(); +}; + +template< typename Kernel, int Dim, typename TagList> +typename Kernel::VectorMap& Geometry::getParameterMap() { + m_isInCluster = false; + m_parameterCount = m_BaseParameterCount; + return m_parameter; +}; + +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::linkTo(boost::shared_ptr > geom, int offset) { + + init(); + m_link = geom; + m_link_offset = offset; + m_global = geom->m_global.segment(offset, m_BaseParameterCount); +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::initMap(typename Kernel::MappedEquationSystem* mes) { + + //check should not be needed, but how knows... + if(!m_init) { + + if(!isLinked()) { + m_offset = mes->setParameterMap(m_parameterCount, getParameterMap()); + m_parameter = m_global; + m_init = true; + } + else { + //it's important that the linked geometry is initialised, as we going to access its parameter map + if(!m_link->isInitialised()) + m_link->initMap(mes); + + m_offset = m_link->m_offset + m_link_offset; + new(&getParameterMap()) typename Kernel::VectorMap(&m_link->getParameterMap()(m_link_offset), m_parameterCount, typename Kernel::DynStride(1,1)); + } + } +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::setClusterMode(bool iscluster, bool isFixed) { + + m_isInCluster = iscluster; + m_clusterFixed = isFixed; + if(iscluster) { + //we are in cluster, therfore the parameter map should not point to a solver value but to + //the rotated original value; + new(&m_parameter) typename Kernel::VectorMap(&m_rotated(0), m_parameterCount, DS(1,1)); + //the local value is the global one as no transformation was applied yet + m_toplocal = m_global; + m_rotated = m_global; + } + else + new(&m_parameter) typename Kernel::VectorMap(&m_global(0), m_parameterCount, DS(1,1)); +}; + +template< typename Kernel, int Dim, typename TagList> +void Geometry::recalculate(DiffTransform& trans) { + if(!m_isInCluster) + return; + + for(int i=0; i!=m_rotations; i++) { + //first rotate the original to the transformed value + m_rotated.block(i*Dim,0,Dim,1) = trans.rotation()*m_toplocal.template segment(i*Dim); + + //now calculate the gradient vectors and add them to diffparam + for(int j=0; j(i*Dim); + } + //after rotating the needed parameters we translate the stuff that needs to be moved + for(int i=0; i!=m_translations; i++) { + m_rotated.block(i*Dim,0,Dim,1) += trans.translation().vector(); + m_rotated.block(i*Dim,0,Dim,1) *= trans.scaling().factor(); + //calculate the gradient vectors and add them to diffparam + m_diffparam.block(i*Dim,Dim,Dim,Dim).setIdentity(); + } + +#ifdef USE_LOGGING + if(!boost::math::isnormal(m_rotated.norm()) || !boost::math::isnormal(m_diffparam.norm())) { + BOOST_LOG(log) << "Unnormal recalculated value detected: "< +void Geometry::finishCalculation() { + //if fixed nothing needs to be changed + if(m_isInCluster) { + //recalculate(1.); //remove scaling to get right global value + m_global = m_rotated; +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish cluster calculation"; +#endif + } + //TODO:non cluster paramter scaling + else { + m_global = m_parameter; + normalize(); +#ifdef USE_LOGGING + BOOST_LOG(log) << "Finish calculation"; +#endif + }; + + m_init = false; + m_isInCluster = false; + + recalculated(); +}; + +template< typename Kernel, int Dim, typename TagList> +template +void Geometry::transform(const Transform& t, VectorType& vec) { + + //everything that needs to be translated needs to be fully transformed + for(int i=0; i!=m_translations; i++) { + typename Kernel::Vector3 v = vec.template segment(i*Dim); + vec.template segment(i*Dim) = t*v; + } + + for(int i=m_translations; i!=m_rotations; i++) { + typename Kernel::Vector3 v = vec.template segment(i*Dim); + vec.template segment(i*Dim) = t.rotate(v); + } + +#ifdef USE_LOGGING + BOOST_LOG(log) << "Transformed with cluster: "< +void Geometry::scale(Scalar value) { + + for(int i=0; i!=m_translations; i++) + m_parameter.template segment(i*Dim) *= 1./value; + +}; + +} +} + +#endif // GCM_GEOMETRY_H diff --git a/src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp new file mode 100644 index 000000000000..17433445444f --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/kernel_imp.hpp @@ -0,0 +1,512 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_KERNEL_IMP_H +#define DCM_KERNEL_IMP_H + +#include "../kernel.hpp" +#include + +namespace dcm { + +template +Dogleg::Dogleg(Kernel* k) : m_kernel(k), tolg(1e-40), tolx(1e-20) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); +#endif +}; + +template +Dogleg::Dogleg() : tolg(1e-40), tolx(1e-20) { + +#ifdef USE_LOGGING + log.add_attribute("Tag", attrs::constant< std::string >("Dogleg")); +#endif +}; + +template +void Dogleg::setKernel(Kernel* k) { + + m_kernel = k; +}; + +template +template +void Dogleg::calculateStep(const Eigen::MatrixBase& g, const Eigen::MatrixBase& jacobi, + const Eigen::MatrixBase& residual, Eigen::MatrixBase& h_dl, + const double delta) { + + // get the steepest descent stepsize and direction + const double alpha(g.squaredNorm()/(jacobi*g).squaredNorm()); + const typename Kernel::Vector h_sd = -g; + + // get the gauss-newton step + const typename Kernel::Vector h_gn = (jacobi).fullPivLu().solve(-residual); +#ifdef USE_LOGGING + + if(!boost::math::isfinite(h_gn.norm())) { + BOOST_LOG(log)<< "Unnormal gauss-newton detected: "<= delta) { + //h_dl = alpha*h_sd; + h_dl = (delta/(h_sd.norm()))*h_sd; +#ifdef USE_LOGGING + + if(!boost::math::isfinite(h_dl.norm())) { + BOOST_LOG(log)<< "Unnormal dogleg descent detected: "< +void Dogleg::init(typename Kernel::MappedEquationSystem& sys) { + + if(!sys.isValid()) + throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system"); + + F_old.resize(sys.equationCount()); + g.resize(sys.equationCount()); + J_old.resize(sys.equationCount(), sys.parameterCount()); + + sys.recalculate(); +#ifdef USE_LOGGING + BOOST_LOG(log)<< "initial jacobi: "<(); +#endif + sys.removeLocalGradientZeros(); + +#ifdef USE_LOGGING + BOOST_LOG(log)<< "LGZ jacobi: "<(); +#endif + + err = sys.Residual.norm(); + + F_old = sys.Residual; + J_old = sys.Jacobi; + + g = sys.Jacobi.transpose()*(sys.Residual); + + // get the infinity norm fx_inf and g_inf + g_inf = g.template lpNorm(); + fx_inf = sys.Residual.template lpNorm(); + + delta=5; + nu=2.; + iter=0; + stop=0; + reduce=0; + unused=0; + counter=0; +}; + +template +int Dogleg::solve(typename Kernel::MappedEquationSystem& sys, bool continuous) { + nothing n; + return solve(sys, n, continuous); +}; + +template +template +int Dogleg::solve(typename Kernel::MappedEquationSystem& sys, Functor& rescale, bool continuous) { + + clock_t start = clock(); + + if(!sys.isValid()) + throw solving_error() << boost::errinfo_errno(5) << error_message("invalid equation system"); + + int maxIterNumber = 5000;//MaxIterations * xsize; + number_type diverging_lim = 1e6*err + 1e12; + + do { + + // check if finished + if(fx_inf <= m_kernel->template getProperty()*sys.Scaling) // Success + stop = 1; + else if(g_inf <= tolg) + throw solving_error() << boost::errinfo_errno(2) << error_message("g infinity norm smaller below limit"); + else if(delta <= tolx) + throw solving_error() << boost::errinfo_errno(3) << error_message("step size below limit"); + else if(iter >= maxIterNumber) + throw solving_error() << boost::errinfo_errno(4) << error_message("maximal iterations reached"); + else if(!boost::math::isfinite(err)) + throw solving_error() << boost::errinfo_errno(5) << error_message("error is inf or nan"); + else if(err > diverging_lim) + throw solving_error() << boost::errinfo_errno(6) << error_message("error diverged"); + + + // see if we are already finished + if(stop) + break; + + number_type err_new; + number_type dF=0, dL=0; + number_type rho; + + //get the update step + calculateStep(g, sys.Jacobi, sys.Residual, h_dl, delta); + + // calculate the linear model + dL = 0.5*sys.Residual.norm() - 0.5*(sys.Residual + sys.Jacobi*h_dl).norm(); + + // get the new values + sys.Parameter += h_dl; + sys.recalculate(); + +#ifdef USE_LOGGING + + if(!boost::math::isfinite(sys.Residual.norm())) { + BOOST_LOG(log)<< "Unnormal residual detected: "<0.85) { + delta = std::max(delta,2*h_dl.norm()); + nu = 2; + } + else if(rho < 0.25) { + delta = delta/nu; + nu = 2*nu; + } + + if(dF > 0 && dL > 0) { + + //see if we got too high differentials + if(sys.Jacobi.template lpNorm() > 2) { +#ifdef USE_LOGGING + BOOST_LOG(log)<< "High differential detected: "<()<<" in iteration: "<1 && (counter>50)) { + rescale(); + sys.recalculate(); + counter = 0; + } + + F_old = sys.Residual; + J_old = sys.Jacobi; + + err = sys.Residual.norm(); + g = sys.Jacobi.transpose()*(sys.Residual); + + // get infinity norms + g_inf = g.template lpNorm(); + fx_inf = sys.Residual.template lpNorm(); + + } + else { + sys.Residual = F_old; + sys.Jacobi = J_old; + sys.Parameter -= h_dl; + unused++; +#ifdef USE_LOGGING + BOOST_LOG(log)<< "Reject step in iter "< class Nonlinear> +int Kernel::MappedEquationSystem::parameterCount() { + return m_params; +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::equationCount() { + return m_eqns; +}; + +template class Nonlinear> +bool Kernel::MappedEquationSystem::rotationOnly() { + return rot_only; +}; + +template class Nonlinear> +Kernel::MappedEquationSystem::MappedEquationSystem(int params, int equations) + : rot_only(false), m_jacobi(equations, params), + m_parameter(params), Residual(equations), + m_params(params), m_eqns(equations), Scaling(1.), + Jacobi(&m_jacobi(0,0),equations,params,DynStride(equations,1)), + Parameter(&m_parameter(0),params,DynStride(1,1)) { + + m_param_rot_offset = 0; + m_param_trans_offset = params; + m_eqn_offset = 0; + + m_jacobi.setZero(); //important as some places are never written +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::setParameterMap(int number, VectorMap& map, ParameterType t) { + + if(t == rotation) { + new(&map) VectorMap(&m_parameter(m_param_rot_offset), number, DynStride(1,1)); + m_param_rot_offset += number; + return m_param_rot_offset-number; + } + else { + m_param_trans_offset -= number; + new(&map) VectorMap(&m_parameter(m_param_trans_offset), number, DynStride(1,1)); + return m_param_trans_offset; + } +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::setParameterMap(Vector3Map& map, ParameterType t) { + + if(t == rotation) { + new(&map) Vector3Map(&m_parameter(m_param_rot_offset)); + m_param_rot_offset += 3; + return m_param_rot_offset-3; + } + else { + m_param_trans_offset -= 3; + new(&map) Vector3Map(&m_parameter(m_param_trans_offset)); + return m_param_trans_offset; + } +}; + +template class Nonlinear> +int Kernel::MappedEquationSystem::setResidualMap(VectorMap& map) { + new(&map) VectorMap(&Residual(m_eqn_offset), 1, DynStride(1,1)); + return m_eqn_offset++; +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setJacobiMap(int eqn, int offset, int number, CVectorMap& map) { + new(&map) CVectorMap(&m_jacobi(eqn, offset), number, DynStride(0,m_eqns)); +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setJacobiMap(int eqn, int offset, int number, VectorMap& map) { + new(&map) VectorMap(&m_jacobi(eqn, offset), number, DynStride(0,m_eqns)); +}; + +template class Nonlinear> +bool Kernel::MappedEquationSystem::isValid() { + if(!m_params || !m_eqns) + return false; + + return true; +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setAccess(ParameterType t) { + + if(t==complete) { + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,m_params,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),m_params,DynStride(1,1)); + } + else if(t==rotation) { + int num = m_param_trans_offset; + new(&Jacobi) MatrixMap(&m_jacobi(0,0),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(0),num,DynStride(1,1)); + } + else if(t==general) { + int num = m_params - m_param_trans_offset; + new(&Jacobi) MatrixMap(&m_jacobi(0,m_param_trans_offset),m_eqns,num,DynStride(m_eqns,1)); + new(&Parameter) VectorMap(&m_parameter(m_param_trans_offset),num,DynStride(1,1)); + } +}; + +template class Nonlinear> +void Kernel::MappedEquationSystem::setGeneralEquationAccess(bool general) { + rot_only = !general; +}; + +template class Nonlinear> +bool Kernel::MappedEquationSystem::hasParameterType(ParameterType t) { + + if(t==rotation) + return (m_param_rot_offset>0); + else if(t==general) + return (m_param_trans_offset0); +}; + +template class Nonlinear> +Kernel::Kernel() { + //init the solver + m_solver.setKernel(this); +} + +template class Nonlinear> +SolverInfo Kernel::getSolverInfo() { + + SolverInfo info; + info.iterations = m_solver.iter; + info.error = m_solver.err; + info.time = m_solver.time; + + return info; +} + +//static comparison versions +template class Nonlinear> +template +bool Kernel::isSame(const E::MatrixBase& p1,const E::MatrixBase& p2, number_type precission) { + return ((p1-p2).squaredNorm() < precission); +} + +template class Nonlinear> +bool Kernel::isSame(number_type t1, number_type t2, number_type precission) { + return (std::abs(t1-t2) < precission); +} + +template class Nonlinear> +template +bool Kernel::isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2, number_type precission) { + return ((p1+p2).squaredNorm() < precission); +} + +template class Nonlinear> +template +bool Kernel::isSame(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1-p2).squaredNorm() < getProperty()); +} + +template class Nonlinear> +bool Kernel::isSame(number_type t1, number_type t2) { + return (std::abs(t1-t2) < getProperty()); +} + +template class Nonlinear> +template +bool Kernel::isOpposite(const E::MatrixBase& p1,const E::MatrixBase& p2) { + return ((p1+p2).squaredNorm() < getProperty()); +} + +template class Nonlinear> +int Kernel::solve(MappedEquationSystem& mes) { + + nothing n; + + if(getProperty()==continuous) + m_solver.init(mes); + + return m_solver.solve(mes, n); +}; + +template class Nonlinear> +template +int Kernel::solve(MappedEquationSystem& mes, Functor& f) { + + if(getProperty()==continuous) + m_solver.init(mes); + + return m_solver.solve(mes, f); +}; + +} + +#endif //GCM_KERNEL_H + + + + + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp new file mode 100644 index 000000000000..66f3220284e9 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/object_imp.hpp @@ -0,0 +1,115 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef GCM_OBJECT_IMP_H +#define GCM_OBJECT_IMP_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "../property.hpp" + +#define EMIT_CALL_DEC(z, n, data) \ + template \ + template < \ + typename S \ + BOOST_PP_ENUM_TRAILING_PARAMS(n, typename Arg) \ + > \ + void SignalOwner::emitSignal( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, Arg, const& arg) \ + ) \ + { \ + if(m_emit_signals) {\ + typedef typename mpl::find::type iterator; \ + typedef typename mpl::distance::type, iterator>::type distance; \ + typedef typename fusion::result_of::value_at::type map_type; \ + map_type& map = fusion::at(m_signals); \ + for (typename map_type::iterator it=map.begin(); it != map.end(); it++) \ + (it->second)(BOOST_PP_ENUM(n, EMIT_ARGUMENTS, arg)); \ + }\ + }; + +namespace dcm { + +template +Object::Object(Sys& system) : m_system(&system) {}; + +template +boost::shared_ptr Object::clone(Sys& newSys) +{ + + boost::shared_ptr np = boost::shared_ptr(new Derived(*static_cast(this))); + np->m_system = &newSys; + return np; +}; + +template +SignalOwner::SignalOwner() : m_emit_signals(true), m_signal_count(0) {}; + +template +template +Connection SignalOwner::connectSignal(typename mpl::at::type function) +{ + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + typedef typename fusion::result_of::value_at::type map_type; + map_type& map = fusion::at(m_signals); + map[++m_signal_count] = function; + return m_signal_count; +}; + +template +template +void SignalOwner::disconnectSignal(Connection c) +{ + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + + typedef typename fusion::result_of::value_at::type map_type; + map_type& map = fusion::at(m_signals); + map.erase(c); +}; + +template +void SignalOwner::enableSignals(bool onoff) +{ + m_emit_signals = onoff; +}; + +BOOST_PP_REPEAT(5, EMIT_CALL_DEC, ~) + +} + +#endif //GCM_OBJECT_H + + diff --git a/src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp b/src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp new file mode 100644 index 000000000000..33384fdde6a9 --- /dev/null +++ b/src/Mod/Assembly/App/opendcm/core/imp/system_imp.hpp @@ -0,0 +1,257 @@ +/* + openDCM, dimensional constraint manager + Copyright (C) 2012 Stefan Troeger + + This library 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef DCM_SYSTEM_IMP_H +#define DCM_SYSTEM_IMP_H + +#ifdef DCM_EXTERNAL_CORE +#include "kernel_imp.hpp" +#include "transformation_imp.hpp" +#include "clustergraph_imp.hpp" +#include "equations_imp.hpp" +#endif + +#include "../system.hpp" + +#include + +namespace dcm { + +struct clearer { + template + void operator()(T& vector) const { + vector.clear(); + }; +}; + +template +struct cloner { + + System& newSys; + cloner(System& ns) : newSys(ns) {}; + + template + struct test : mpl::and_, + mpl::not_ > > > {}; + + template + typename boost::enable_if< test, void>::type operator()(T& p) const { + p = p->clone(newSys); + newSys.push_back(p); + }; + template + typename boost::enable_if< mpl::not_ >, void>::type operator()(const T& p) const {}; +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +System::System() : m_cluster(new Cluster), m_storage(new Storage) +#ifdef USE_LOGGING + , sink(init_log()) +#endif +{ + Type1::system_init(*this); + Type2::system_init(*this); + Type3::system_init(*this); +}; + + +template< typename KernelType, typename T1, typename T2, typename T3 > +System::~System() { +#ifdef USE_LOGGING + stop_log(sink); +#endif +}; + + +template< typename KernelType, typename T1, typename T2, typename T3 > +void System::clear() { + + m_cluster->clearClusters(); + m_cluster->clear(); + fusion::for_each(*m_storage, clearer()); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +typename std::vector< boost::shared_ptr >::iterator System::begin() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage).begin(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +typename std::vector< boost::shared_ptr >::iterator System::end() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage).end(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +std::vector< boost::shared_ptr >& System::objectVector() { + + typedef typename mpl::find::type iterator; + typedef typename mpl::distance::type, iterator>::type distance; + BOOST_MPL_ASSERT((mpl::not_::type > >)); + return fusion::at(*m_storage); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +void System::push_back(boost::shared_ptr ptr) { + objectVector().push_back(ptr); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +void System::erase(boost::shared_ptr ptr) { + + std::vector< boost::shared_ptr >& vec = objectVector(); + vec.erase(std::remove(vec.begin(), vec.end(), ptr), vec.end()); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +SolverInfo System::solve() { + clock_t start = clock(); + m_sheduler.execute(*this); + clock_t end = clock(); + + SolverInfo info = m_kernel.getSolverInfo(); + info.time = (double(end-start)* 1000.) / double(CLOCKS_PER_SEC); + + //signal our successful solving + BaseType::template emitSignal(this); + + return info; +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +boost::shared_ptr > System::createSubsystem() { + + boost::shared_ptr s = boost::shared_ptr(new System()); + s->m_cluster = m_cluster->createCluster().first; + s->m_storage = m_storage; + s->m_cluster->template setProperty(details::subcluster); +#ifdef USE_LOGGING + stop_log(s->sink); +#endif + + //inform modules that we have a subsystem now + Inheriter1::system_sub(s); + Inheriter2::system_sub(s); + Inheriter3::system_sub(s); + + m_subsystems.push_back(s); + + return s; +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +typename std::vector > >::iterator System::beginSubsystems() { + return m_subsystems.begin(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +typename std::vector > >::iterator System::endSubsystems() { + return m_subsystems.end(); +}; + +template< typename KernelType, typename T1, typename T2, typename T3 > +template +typename boost::enable_if< boost::is_same< typename mpl::find::type, + typename mpl::end::type >, typename Option::type& >::type +System::getOption() { + return m_options.template getProperty