diff --git a/CMakeLists.txt b/CMakeLists.txt index 602f37de4..2864f687b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,7 +206,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) if( ${OCE_FOUND} ) message("-- OpenCASCADE Community Edition has been found.") add_definitions ( -DHAVE_CONFIG_H ) - set( OCC_LIBRARIES "TKFillet;TKMesh;TKernel;TKG2d;TKG3d;TKMath;TKIGES;TKSTL;TKShHealing;TKXSBase;TKBool;TKBO;TKBRep;TKTopAlgo;TKGeomAlgo;TKGeomBase;TKOffset;TKPrim;TKSTEP;TKSTEPBase;TKSTEPAttr;TKHLR" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake + set( OCC_LIBRARIES "TKFeat;TKFillet;TKMesh;TKernel;TKG2d;TKG3d;TKMath;TKIGES;TKSTL;TKShHealing;TKXSBase;TKBool;TKBO;TKBRep;TKTopAlgo;TKGeomAlgo;TKGeomBase;TKOffset;TKPrim;TKSTEP;TKSTEPBase;TKSTEPAttr;TKHLR" ) #lib list copied from FreeCAD's FindOpenCasCade.cmake set( OCC_INCLUDE_DIR ${OCE_INCLUDE_DIRS} ) set( OCC_FOUND ${OCE_FOUND} ) else() #look for OpenCASCADE @@ -219,12 +219,6 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) ENDIF() endif() -# -------------------------------- f2c ---------------------------------- - - IF(OCC_FOUND) - find_package(F2C REQUIRED) - ENDIF(OCC_FOUND) - # -------------------------------- Salome SMESH -------------------------- # Salome SMESH sources are under src/3rdParty now @@ -268,7 +262,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) # -------------------------------- ODE ---------------------------------- - find_package(ODE) +# find_package(ODE) # -------------------------------- Qt -------------------------------- @@ -439,7 +433,7 @@ if(FREECAD_MAINTAINERS_BUILD AND NOT WIN32) set(PKG_ARCH amd64) ENDIF( CMAKE_SIZEOF_VOID_P EQUAL 4 ) set(CPACK_DEBIAN_PACKAGE_SECTION "science") - set(CPACK_DEBIAN_PACKAGE_DEPENDS "python, oce | opencascade, libqtgui4, libcoin60, libode1, libsoqt4-20, libxerces-c3.1, libgts-0.7-5, zlib1g, libboost-dev, libeigen2-dev") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "python, oce | opencascade, libqtgui4, libcoin60, libsoqt4-20, libxerces-c3.1, zlib1g, libboost-dev, libeigen2-dev") set(CPACK_PACKAGE_CONTACT "") set(CPACK_PACKAGE_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}_${PKG_ARCH}") diff --git a/cMake/FindOpenCasCade.cmake b/cMake/FindOpenCasCade.cmake index 678d4f722..1b04f709d 100644 --- a/cMake/FindOpenCasCade.cmake +++ b/cMake/FindOpenCasCade.cmake @@ -78,6 +78,7 @@ IF(OCC_LIBRARY) TKSTEPBase TKSTEPAttr TKHLR + TKFeat ) ENDIF(OCC_LIBRARY) diff --git a/copying.lib b/copying.lib index 3fcf74e71..81a5194fa 100644 --- a/copying.lib +++ b/copying.lib @@ -7,8 +7,8 @@ by the authors who actually wrote it. Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA. + 51 Franklin Street - Fifth Floor + Boston, MA 02110-1301, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. diff --git a/src/3rdParty/salomesmesh/CMakeLists.txt b/src/3rdParty/salomesmesh/CMakeLists.txt index 314632396..616972570 100644 --- a/src/3rdParty/salomesmesh/CMakeLists.txt +++ b/src/3rdParty/salomesmesh/CMakeLists.txt @@ -173,7 +173,7 @@ FILE(GLOB StdMeshers_source_files src/StdMeshers/*.cpp src/MEFISTO2/*.cpp src/ME INCLUDE_DIRECTORIES(src/StdMeshers) ADD_LIBRARY(StdMeshers SHARED ${StdMeshers_source_files}) -TARGET_LINK_LIBRARIES(StdMeshers SMESH TKernel TKMath TKAdvTools f2c gfortran) +TARGET_LINK_LIBRARIES(StdMeshers SMESH TKernel TKMath TKAdvTools gfortran) SET(StdMeshers_CFLAGS "") IF(WIN32) SET(StdMeshers_CFLAGS "-DSTDMESHERS_EXPORTS -DMEFISTO2D_EXPORTS") diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 17b99601f..e6a399926 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1188,13 +1188,13 @@ void Application::processCmdLineFiles(void) Application::_pcSingleton->openDocument(File.filePath().c_str()); } else if (File.hasExtension("fcscript")||File.hasExtension("fcmacro")) { - Base::Interpreter().runFile(File.filePath().c_str(), false); + Base::Interpreter().runFile(File.filePath().c_str(), true); } else if (File.hasExtension("py")) { //FIXME: Does this make any sense? I think we should do the ame as for // fcmacro or fcscript. //Base::Interpreter().loadModule(File.fileNamePure().c_str()); - Base::Interpreter().runFile(File.filePath().c_str(), false); + Base::Interpreter().runFile(File.filePath().c_str(), true); } else { std::vector mods = App::GetApplication().getImportModules(Ext.c_str()); @@ -1210,8 +1210,7 @@ void Application::processCmdLineFiles(void) } } catch (const Base::SystemExitException&) { - Base::PyGILStateLocker locker; - Base::Interpreter().systemExit(); + 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()); @@ -1523,20 +1522,23 @@ void Application::ParseOptions(int ac, char ** av) notify(vm); } catch (const std::exception& e) { - cerr << e.what() << endl << endl << visible << endl; - exit(1); + std::stringstream str; + str << e.what() << endl << endl << visible << endl; + throw UnknownProgramOption(str.str()); } catch (...) { - cerr << "Wrong or unknown option, bailing out!" << endl << endl << visible << endl; - exit(1); + std::stringstream str; + str << "Wrong or unknown option, bailing out!" << endl << endl << visible << endl; + throw UnknownProgramOption(str.str()); } if (vm.count("help")) { - cout << mConfig["ExeName"] << endl << endl; - cout << "For detailed descripton see http://free-cad.sf.net" << endl<().c_str()); if (!ifs) { Base::Console().Error("Could no open the response file\n"); - cerr << "Could no open the response file: '" - << vm["response-file"].as() << "'" << endl; - exit(1); + 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; @@ -1562,9 +1565,10 @@ void Application::ParseOptions(int ac, char ** av) } if (vm.count("version")) { - std::cout << mConfig["ExeName"] << " " << mConfig["ExeVersion"] - << " Revision: " << mConfig["BuildRevision"] << std::endl; - exit(0); + std::stringstream str; + str << mConfig["ExeName"] << " " << mConfig["ExeVersion"] + << " Revision: " << mConfig["BuildRevision"] << std::endl; + throw Base::ProgramInformation(str.str()); } if (vm.count("console")) { diff --git a/src/App/PropertyPythonObject.cpp b/src/App/PropertyPythonObject.cpp index c335dabf5..aa5534e61 100644 --- a/src/App/PropertyPythonObject.cpp +++ b/src/App/PropertyPythonObject.cpp @@ -35,6 +35,7 @@ #include #include #include +#include using namespace App; @@ -82,10 +83,20 @@ std::string PropertyPythonObject::toString() const std::string repr; Base::PyGILStateLocker lock; try { - Py::Module pickle(PyImport_ImportModule("cPickle"),true); + Py::Module pickle(PyImport_ImportModule("json"),true); Py::Callable method(pickle.getAttr(std::string("dumps"))); + Py::Object dump; + if (this->object.hasAttr("__getstate__")) { + Py::Tuple args(0); + Py::Callable state(this->object.getAttr("__getstate__")); + dump = state.apply(args); + } + else if (this->object.hasAttr("__dict__")) { + dump = this->object.getAttr("__dict__"); + } + Py::Tuple args(1); - args.setItem(0, this->object); + args.setItem(0, dump); Py::Object res = method.apply(args); Py::String str(res); repr = str.as_std_string(); @@ -102,12 +113,21 @@ void PropertyPythonObject::fromString(const std::string& repr) { Base::PyGILStateLocker lock; try { - Py::Module pickle(PyImport_ImportModule("cPickle"),true); + Py::Module pickle(PyImport_ImportModule("json"),true); Py::Callable method(pickle.getAttr(std::string("loads"))); Py::Tuple args(1); args.setItem(0, Py::String(repr)); Py::Object res = method.apply(args); - this->object = res; + + if (this->object.hasAttr("__setstate__")) { + Py::Tuple args(1); + args.setItem(0, res); + Py::Callable state(this->object.getAttr("__setstate__")); + state.apply(args); + } + else { + this->object.setAttr("__dict__", res); + } } catch (Py::Exception&) { Base::PyException e; // extract the Python error text @@ -115,6 +135,32 @@ void PropertyPythonObject::fromString(const std::string& repr) } } +void PropertyPythonObject::loadPickle(const std::string& str) +{ + // find the custom attributes and restore them + Base::PyGILStateLocker lock; + try { + std::string buffer = str; + boost::regex pickle("S'(\\w+)'.+S'(\\w+)'\\n"); + boost::match_results what; + std::string::const_iterator start, end; + start = buffer.begin(); + end = buffer.end(); + while (boost::regex_search(start, end, what, pickle)) { + std::string key = std::string(what[1].first, what[1].second); + std::string val = std::string(what[2].first, what[2].second); + this->object.setAttr(key, Py::String(val)); + buffer = std::string(what[2].second, end); + start = buffer.begin(); + end = buffer.end(); + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + Base::Console().Warning("PropertyPythonObject::loadPickle: %s\n", e.what()); + } +} + std::string PropertyPythonObject::encodeValue(const std::string& str) const { std::string tmp; @@ -210,7 +256,25 @@ void PropertyPythonObject::Save (Base::Writer &writer) const repr = Base::base64_encode((const unsigned char*)repr.c_str(), repr.size()); std::string val = /*encodeValue*/(repr); writer.Stream() << writer.ind() << "object.hasAttr("__module__") && this->object.hasAttr("__class__")) { + Py::String mod(this->object.getAttr("__module__")); + Py::Object cls(this->object.getAttr("__class__")); + if (cls.hasAttr("__name__")) { + Py::String name(cls.getAttr("__name__")); + writer.Stream() << " module=\"" << (std::string)mod << "\"" + << " class=\"" << (std::string)name << "\""; + } + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + Base::Console().Warning("PropertyPythonObject::Save: %s\n", e.what()); + } + saveObject(writer); writer.Stream() << "/>" << std::endl; //} @@ -228,6 +292,8 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader) reader.addFile(file.c_str(),this); } else { + bool load_json=false; + bool load_pickle=false; std::string buffer = reader.getAttribute("value"); if (reader.hasAttribute("encoded") && strcmp(reader.getAttribute("encoded"),"yes") == 0) { @@ -237,8 +303,39 @@ void PropertyPythonObject::Restore(Base::XMLReader &reader) buffer = decodeValue(buffer); } + Base::PyGILStateLocker lock; + try { + boost::regex pickle("^\\(i(\\w+)\\n(\\w+)\\n"); + boost::match_results what; + std::string::const_iterator start, end; + start = buffer.begin(); + end = buffer.end(); + if (reader.hasAttribute("module") && reader.hasAttribute("class")) { + Py::Module mod(PyImport_ImportModule(reader.getAttribute("module")),true); + this->object = PyInstance_NewRaw(mod.getAttr(reader.getAttribute("class")).ptr(), 0); + load_json = true; + } + else if (boost::regex_search(start, end, what, pickle)) { + std::string nam = std::string(what[1].first, what[1].second); + std::string cls = std::string(what[2].first, what[2].second); + Py::Module mod(PyImport_ImportModule(nam.c_str()),true); + this->object = PyInstance_NewRaw(mod.getAttr(cls).ptr(), 0); + load_pickle = true; + buffer = std::string(what[2].second, end); + } + } + catch (Py::Exception&) { + Base::PyException e; // extract the Python error text + Base::Console().Warning("PropertyPythonObject::Restore: %s\n", e.what()); + } + aboutToSetValue(); - this->fromString(buffer); + if (load_json) + this->fromString(buffer); + else if (load_pickle) + this->loadPickle(buffer); + else + Base::Console().Warning("PropertyPythonObject::Restore: unsupported serialisation: %s\n", buffer.c_str()); restoreObject(reader); hasSetValue(); } diff --git a/src/App/PropertyPythonObject.h b/src/App/PropertyPythonObject.h index 381929995..bd4bec933 100644 --- a/src/App/PropertyPythonObject.h +++ b/src/App/PropertyPythonObject.h @@ -77,6 +77,7 @@ private: void restoreObject(Base::XMLReader &reader); std::string encodeValue(const std::string& str) const; std::string decodeValue(const std::string& str) const; + void loadPickle(const std::string& str); Py::Object object; }; diff --git a/src/Base/Exception.cpp b/src/Base/Exception.cpp index e573c2735..4ca62890c 100644 --- a/src/Base/Exception.cpp +++ b/src/Base/Exception.cpp @@ -202,6 +202,40 @@ AbnormalProgramTermination::AbnormalProgramTermination(const AbnormalProgramTerm // --------------------------------------------------------- +UnknownProgramOption::UnknownProgramOption(const char * sMessage) + : Exception(sMessage) +{ +} + +UnknownProgramOption::UnknownProgramOption(const std::string& sMessage) + : Exception(sMessage) +{ +} + +UnknownProgramOption::UnknownProgramOption(const UnknownProgramOption &inst) + : Exception(inst) +{ +} + +// --------------------------------------------------------- + +ProgramInformation::ProgramInformation(const char * sMessage) + : Exception(sMessage) +{ +} + +ProgramInformation::ProgramInformation(const std::string& sMessage) + : Exception(sMessage) +{ +} + +ProgramInformation::ProgramInformation(const ProgramInformation &inst) + : Exception(inst) +{ +} + +// --------------------------------------------------------- + #if defined(__GNUC__) && defined (FC_OS_LINUX) #include #include diff --git a/src/Base/Exception.h b/src/Base/Exception.h index f50fdb7d3..19bd9155c 100644 --- a/src/Base/Exception.h +++ b/src/Base/Exception.h @@ -174,6 +174,38 @@ public: virtual ~AbnormalProgramTermination() throw() {} }; +/** + * The UnknownProgramOption can be used to indicate an unknown program option. + * @author Werner Mayer + */ +class BaseExport UnknownProgramOption : public Exception +{ +public: + /// Construction + UnknownProgramOption(const char * sMessage); + UnknownProgramOption(const std::string& sMessage); + /// Construction + UnknownProgramOption(const UnknownProgramOption &inst); + /// Destruction + virtual ~UnknownProgramOption() throw() {} +}; + +/** + * The ProgramInformation can be used to show information about the program. + * @author Werner Mayer + */ +class BaseExport ProgramInformation : public Exception +{ +public: + /// Construction + ProgramInformation(const char * sMessage); + ProgramInformation(const std::string& sMessage); + /// Construction + ProgramInformation(const ProgramInformation &inst); + /// Destruction + virtual ~ProgramInformation() throw() {} +}; + inline void Exception::setMessage(const char * sMessage) { diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index 0a8c4b9e8..a1ddd5a7a 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -190,7 +190,6 @@ void InterpreterSingleton::runInteractiveString(const char *sCmd) presult = PyRun_String(sCmd, Py_single_input, dict, dict); /* eval direct */ if (!presult) { if (PyErr_ExceptionMatches(PyExc_SystemExit)) { - //systemExit(); throw SystemExitException(); } /* get latest python exception information */ diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index ad5663902..5fdc7ed29 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1545,8 +1545,16 @@ void Application::runApplication(void) int argc = App::Application::GetARGC(); GUIApplication mainApp(argc, App::Application::GetARGV()); // set application icon and window title + const std::map& cfg = App::Application::Config(); + std::map::const_iterator it; + it = cfg.find("Application"); + if (it != cfg.end()) { + mainApp.setApplicationName(QString::fromUtf8(it->second.c_str())); + } + else { + mainApp.setApplicationName(QString::fromUtf8(App::GetApplication().getExecutableName())); + } mainApp.setWindowIcon(Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str())); - mainApp.setApplicationName(QString::fromAscii(App::GetApplication().getExecutableName())); QString plugin; plugin = QString::fromUtf8(App::GetApplication().GetHomePath()); plugin += QLatin1String("/plugins"); @@ -1606,8 +1614,6 @@ void Application::runApplication(void) QString home = QString::fromUtf8(App::GetApplication().GetHomePath()); - const std::map& cfg = App::Application::Config(); - std::map::const_iterator it; it = cfg.find("WindowTitle"); if (it != cfg.end()) { QString title = QString::fromUtf8(it->second.c_str()); diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index 3d728e394..9520b80b3 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -292,7 +292,7 @@ StdCmdMergeProjects::StdCmdMergeProjects() void StdCmdMergeProjects::activated(int iMsg) { - QString exe = QString::fromUtf8(App::GetApplication().getExecutableName()); + QString exe = qApp->applicationName(); QString project = QFileDialog::getOpenFileName(Gui::getMainWindow(), QString::fromUtf8(QT_TR_NOOP("Merge project")), QDir::homePath(), QString::fromUtf8(QT_TR_NOOP("%1 document (*.fcstd)")).arg(exe)); diff --git a/src/Gui/CommandStd.cpp b/src/Gui/CommandStd.cpp index 3861e1e64..dba6d5f71 100644 --- a/src/Gui/CommandStd.cpp +++ b/src/Gui/CommandStd.cpp @@ -193,13 +193,7 @@ Action * StdCmdAbout::createAction(void) { Action *pcAction; - QString exe; - std::map& cfg = App::Application::Config(); - std::map::iterator it = cfg.find("Application"); - if (it != cfg.end()) - exe = QString::fromUtf8(it->second.c_str()); - else - exe = QString::fromUtf8(App::GetApplication().getExecutableName()); + QString exe = qApp->applicationName(); pcAction = new Action(this,getMainWindow()); pcAction->setText(QCoreApplication::translate( this->className(), sMenuText, 0, @@ -235,13 +229,7 @@ void StdCmdAbout::activated(int iMsg) void StdCmdAbout::languageChange() { if (_pcAction) { - QString exe; - std::map& cfg = App::Application::Config(); - std::map::iterator it = cfg.find("Application"); - if (it != cfg.end()) - exe = QString::fromUtf8(it->second.c_str()); - else - exe = QString::fromUtf8(App::GetApplication().getExecutableName()); + QString exe = qApp->applicationName(); _pcAction->setText(QCoreApplication::translate( this->className(), sMenuText, 0, QCoreApplication::CodecForTr).arg(exe)); diff --git a/src/Gui/DlgSettingsMacro.ui b/src/Gui/DlgSettingsMacro.ui index 75d84a396..e22998a27 100644 --- a/src/Gui/DlgSettingsMacro.ui +++ b/src/Gui/DlgSettingsMacro.ui @@ -1,45 +1,62 @@ - - - - + + Gui::Dialog::DlgSettingsMacro - - + + 0 0 - 384 - 388 + 391 + 407 - + Macro - - - 9 - - - 6 - - - - + + + + + General macro settings + + + + + + Run macros in local environment + + + true + + + LocalEnvironment + + + Macro + + + + + + + + + Macro recording settings - - + + 9 - + 6 - + - + Qt::Vertical - + 20 40 @@ -47,56 +64,56 @@ - - - + + + Logging Commands - - - 11 - - + + 6 + + 11 + - - + + Show script commands in python console - - true - - + + true + + ScriptToPyConsole - + Macro - - + + Log all commands issued by menus to file: - + ScriptToFile - + Macro - - + + FullScript.FCScript - + ScriptFile - + Macro @@ -104,46 +121,46 @@ - - - + + + Gui commands - - + + 11 - + 6 - - - + + + Recording GUI commands - + true - + RecordGui - + Macro - - - + + + Record as comment - + true - + GuiAsComment - + Macro @@ -151,27 +168,27 @@ - - - + + + Macro path - - + + 11 - + 6 - - - + + + Gui::FileChooser::Directory - + MacroPath - + Macro @@ -184,21 +201,22 @@ - + - Gui::PrefCheckBox - QCheckBox -
Gui/PrefWidgets.h
- 0 - + Gui::FileChooser + QWidget +
Gui/FileDialog.h
Gui::PrefFileChooser Gui::FileChooser
Gui/PrefWidgets.h
- 0 - +
+ + Gui::PrefCheckBox + QCheckBox +
Gui/PrefWidgets.h
@@ -209,11 +227,11 @@ PrefCheckBox_GuiAsComment setEnabled(bool) - + 20 20 - + 20 20 diff --git a/src/Gui/DlgSettingsMacroImp.cpp b/src/Gui/DlgSettingsMacroImp.cpp index bccacfd7f..ce79fba28 100644 --- a/src/Gui/DlgSettingsMacroImp.cpp +++ b/src/Gui/DlgSettingsMacroImp.cpp @@ -54,6 +54,7 @@ DlgSettingsMacroImp::~DlgSettingsMacroImp() void DlgSettingsMacroImp::saveSettings() { + PrefCheckBox_LocalEnv->onSave(); MacroPath->onSave(); PrefCheckBox_RecordGui->onSave(); PrefCheckBox_GuiAsComment->onSave(); @@ -64,6 +65,7 @@ void DlgSettingsMacroImp::saveSettings() void DlgSettingsMacroImp::loadSettings() { + PrefCheckBox_LocalEnv->onRestore(); MacroPath->onRestore(); PrefCheckBox_RecordGui->onRestore(); PrefCheckBox_GuiAsComment->onRestore(); diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 0192d3e86..3b339bff4 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -504,7 +504,7 @@ bool Document::saveAs(void) { getMainWindow()->statusBar()->showMessage(QObject::tr("Save document under new filename...")); - QString exe = QString::fromUtf8(App::GetApplication().getExecutableName()); + QString exe = qApp->applicationName(); QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe), FileDialog::getWorkingDirectory(), QObject::tr("%1 document (*.FCStd)").arg(exe)); if (!fn.isEmpty()) { diff --git a/src/Gui/FileDialog.cpp b/src/Gui/FileDialog.cpp index bbadc2d14..a34c62fea 100644 --- a/src/Gui/FileDialog.cpp +++ b/src/Gui/FileDialog.cpp @@ -15,8 +15,8 @@ * * * 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 * + * write to the Free Software Foundation, Inc., 51 Franklin Street, * + * Fifth Floor, Boston, MA 02110-1301, USA * * * ***************************************************************************/ diff --git a/src/Gui/Macro.cpp b/src/Gui/Macro.cpp index f0d6658d9..1ac796478 100644 --- a/src/Gui/Macro.cpp +++ b/src/Gui/Macro.cpp @@ -26,6 +26,7 @@ #ifndef _PreComp_ # include # include +# include # include # include #endif @@ -71,6 +72,7 @@ void MacroManager::OnChange(Base::Subject &rCaller, const char * sR this->recordGui = this->params->GetBool("RecordGui", true); this->guiAsComment = this->params->GetBool("GuiAsComment", true); this->scriptToPyConsole = this->params->GetBool("ScriptToPyConsole", true); + this->localEnv = this->params->GetBool("LocalEnvironment", true); } void MacroManager::open(MacroType eType,const char *sName) @@ -228,12 +230,10 @@ void MacroManager::run(MacroType eType,const char *sName) PythonRedirector std_out("stdout",pyout); PythonRedirector std_err("stderr",pyerr); //The given path name is expected to be Utf-8 - Base::Interpreter().runFile(sName, true); + Base::Interpreter().runFile(sName, this->localEnv); } catch (const Base::SystemExitException&) { - Base::PyGILStateLocker lock; - PyErr_Clear(); - Base::Interpreter().systemExit(); + qApp->quit(); } catch (const Base::PyException& e) { Base::Console().Error("%s%s: %s\n", diff --git a/src/Gui/Macro.h b/src/Gui/Macro.h index cba009d2b..bbd4266b1 100644 --- a/src/Gui/Macro.h +++ b/src/Gui/Macro.h @@ -98,6 +98,7 @@ protected: bool recordGui; bool guiAsComment; bool scriptToPyConsole; + bool localEnv; PythonConsole* pyConsole; // link to the python console PythonDebugger* pyDebugger; Base::Reference params; // link to the Macro parameter group diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 8c129d761..a13a16c2c 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -1152,7 +1153,13 @@ void MainWindow::showMainWindow() void MainWindow::delayedStartup() { // processing all command line files - App::Application::processCmdLineFiles(); + try { + App::Application::processCmdLineFiles(); + } + catch (const Base::SystemExitException&) { + QApplication::quit(); + return; + } const std::map& cfg = App::Application::Config(); std::map::const_iterator it = cfg.find("StartHidden"); @@ -1318,10 +1325,7 @@ QPixmap MainWindow::splashImage() const // include application name and version number std::map::const_iterator tc = App::Application::Config().find("SplashInfoColor"); if (tc != App::Application::Config().end()) { - QString title = QString::fromAscii(App::Application::Config()["ExeName"].c_str()); - std::map::iterator it = App::Application::Config().find("Application"); - if (it != App::Application::Config().end()) - title = QString::fromUtf8(it->second.c_str()); + QString title = qApp->applicationName(); QString major = QString::fromAscii(App::Application::Config()["BuildVersionMajor"].c_str()); QString minor = QString::fromAscii(App::Application::Config()["BuildVersionMinor"].c_str()); QString version = QString::fromAscii("%1.%2").arg(major).arg(minor); diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 30f5ecf40..50dba3cf2 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -1118,11 +1118,13 @@ SbBool NavigationStyle::processEvent(const SoEvent * const ev) pcPolygon = mouseSelection->getPositions(); clipInner = mouseSelection->isInner(); delete mouseSelection; mouseSelection = 0; + syncWithEvent(ev); return NavigationStyle::processSoEvent(ev); } else if (hd==AbstractMouseSelection::Cancel) { pcPolygon.clear(); delete mouseSelection; mouseSelection = 0; + syncWithEvent(ev); return NavigationStyle::processSoEvent(ev); } } @@ -1150,6 +1152,72 @@ SbBool NavigationStyle::processSoEvent(const SoEvent * const ev) return viewer->processSoEventBase(ev); } +void NavigationStyle::syncWithEvent(const SoEvent * const ev) +{ + // Events when in "ready-to-seek" mode are ignored, except those + // which influence the seek mode itself -- these are handled further + // up the inheritance hierarchy. + if (this->isSeekMode()) { return; } + + const SoType type(ev->getTypeId()); + + // Mismatches in state of the modifier keys happens if the user + // presses or releases them outside the viewer window. + if (this->ctrldown != ev->wasCtrlDown()) { + this->ctrldown = ev->wasCtrlDown(); + } + if (this->shiftdown != ev->wasShiftDown()) { + this->shiftdown = ev->wasShiftDown(); + } + if (this->altdown != ev->wasAltDown()) { + this->altdown = ev->wasAltDown(); + } + + // Keyboard handling + if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) { + const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev; + const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; + switch (event->getKey()) { + case SoKeyboardEvent::LEFT_CONTROL: + case SoKeyboardEvent::RIGHT_CONTROL: + this->ctrldown = press; + break; + case SoKeyboardEvent::LEFT_SHIFT: + case SoKeyboardEvent::RIGHT_SHIFT: + this->shiftdown = press; + break; + case SoKeyboardEvent::LEFT_ALT: + case SoKeyboardEvent::RIGHT_ALT: + this->altdown = press; + break; + default: + break; + } + } + + // Mouse Button / Spaceball Button handling + if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) { + const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev; + const int button = event->getButton(); + const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE; + + // SoDebugError::postInfo("processSoEvent", "button = %d", button); + switch (button) { + case SoMouseButtonEvent::BUTTON1: + this->button1down = press; + break; + case SoMouseButtonEvent::BUTTON2: + this->button2down = press; + break; + case SoMouseButtonEvent::BUTTON3: + this->button3down = press; + break; + default: + break; + } + } +} + SbBool NavigationStyle::processMotionEvent(const SoMotion3Event * const ev) { SoCamera * const camera = viewer->getCamera(); diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index b6d4e20e6..cf7a1cdbc 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -175,6 +175,7 @@ protected: SbBool handleEventInForeground(const SoEvent* const e); virtual SbBool processSoEvent(const SoEvent * const ev); + void syncWithEvent(const SoEvent * const ev); virtual void openPopupMenu(const SbVec2s& position); void clearLog(void); diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index edccd488a..8364ae4e9 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -700,12 +701,13 @@ void PythonConsole::runSource(const QString& line) catch (const Base::SystemExitException&) { ParameterGrp::handle hPrefGrp = getWindowParameter(); bool check = hPrefGrp->GetBool("CheckSystemExit",true); - if (!check) Base::Interpreter().systemExit(); + if (!check) qApp->quit(); int ret = QMessageBox::question(this, tr("System exit"), tr("The application is still running.\nDo you want to exit without saving your data?"), QMessageBox::Yes, QMessageBox::No|QMessageBox::Escape|QMessageBox::Default); if (ret == QMessageBox::Yes) { - Base::Interpreter().systemExit(); - } else { + qApp->quit(); + } + else { PyErr_Clear(); } } diff --git a/src/Gui/Splashscreen.cpp b/src/Gui/Splashscreen.cpp index 9464a5da1..769af1a07 100644 --- a/src/Gui/Splashscreen.cpp +++ b/src/Gui/Splashscreen.cpp @@ -88,23 +88,31 @@ public: textColor = col; } } - virtual ~SplashObserver() { Base::Console().DetachObserver(this); } - + const char* Name() + { + return "SplashObserver"; + } void Warning(const char * s) { +#ifdef FC_DEBUG Log(s); +#endif } void Message(const char * s) { +#ifdef FC_DEBUG Log(s); +#endif } void Error (const char * s) { +#ifdef FC_DEBUG Log(s); +#endif } void Log (const char * s) { @@ -267,11 +275,9 @@ static QString getPlatform() void AboutDialog::setupLabels() { + QString exeName = qApp->applicationName(); std::map& config = App::Application::Config(); - QString exeName = QString::fromAscii(config["ExeName"].c_str()); - std::map::iterator it = config.find("WindowTitle"); - if (it != config.end()) - exeName = QString::fromUtf8(it->second.c_str()); + std::map::iterator it; QString banner = QString::fromUtf8(config["CopyrightInfo"].c_str()); banner = banner.left( banner.indexOf(QLatin1Char('\n')) ); QString major = QString::fromAscii(config["BuildVersionMajor"].c_str()); diff --git a/src/Gui/Thumbnail.cpp b/src/Gui/Thumbnail.cpp index e6f362ad0..df5cbdf3a 100644 --- a/src/Gui/Thumbnail.cpp +++ b/src/Gui/Thumbnail.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include @@ -97,7 +98,7 @@ void Thumbnail::SaveDocFile (Base::Writer &writer) const // according to specification add some meta-information to the image uint mt = QDateTime::currentDateTime().toTime_t(); QString mtime = QString::fromAscii("%1").arg(mt); - img.setText(QLatin1String("Software"), QString::fromUtf8(App::GetApplication().getExecutableName())); + img.setText(QLatin1String("Software"), qApp->applicationName()); img.setText(QLatin1String("Thumb::Mimetype"), QLatin1String("application/x-extension-fcstd")); img.setText(QLatin1String("Thumb::MTime"), mtime); img.setText(QLatin1String("Thumb::URI"), this->uri.toString()); diff --git a/src/Gui/View3DInventorExamples.cpp b/src/Gui/View3DInventorExamples.cpp index 99510a005..c7e5a1b4f 100644 --- a/src/Gui/View3DInventorExamples.cpp +++ b/src/Gui/View3DInventorExamples.cpp @@ -311,7 +311,7 @@ void LightManip(SoSeparator * root) in.setBuffer((void *)scenegraph, std::strlen(scenegraph)); SoSeparator * _root = SoDB::readAll( &in ); root->addChild(_root); - if ( root == NULL ) exit( 1 ); // Shouldn't happen. + if ( root == NULL ) return; // Shouldn't happen. root->ref(); const char * pointlightnames[3] = { "RedLight", "GreenLight", "BlueLight" }; @@ -323,7 +323,7 @@ void LightManip(SoSeparator * root) sa.setSearchingAll( FALSE ); sa.apply( root ); SoPath * path = sa.getPath(); - if ( path == NULL) exit( 1 ); // Shouldn't happen. + if ( path == NULL) return; // Shouldn't happen. SoPointLightManip * manip = new SoPointLightManip; manip->replaceNode( path ); @@ -446,7 +446,7 @@ void AnimationTexture(SoSeparator * root) texturetimer->schedule(); // Scene graph - if ( root == NULL ) exit( 1 ); // Shouldn't happen. + if ( root == NULL ) return; // Shouldn't happen. root->ref(); // prevent from being deleted because of the still running timer sensor // SoSeparator * root = new SoSeparator; // root->ref(); diff --git a/src/Main/MainCmd.cpp b/src/Main/MainCmd.cpp index f42d7598b..4fcae2687 100644 --- a/src/Main/MainCmd.cpp +++ b/src/Main/MainCmd.cpp @@ -37,6 +37,7 @@ #include #include +#include // FreeCAD Base header #include @@ -89,6 +90,14 @@ int main( int argc, char ** argv ) // Inits the Application App::Application::init(argc,argv); } + catch (const Base::UnknownProgramOption& e) { + std::cerr << e.what(); + exit(1); + } + catch (const Base::ProgramInformation& e) { + std::cout << e.what(); + exit(0); + } catch (const Base::Exception& e) { std::string appName = App::Application::Config()["ExeName"]; std::stringstream msg; diff --git a/src/Main/MainGui.cpp b/src/Main/MainGui.cpp index 83c4487f4..5552bd6b4 100644 --- a/src/Main/MainGui.cpp +++ b/src/Main/MainGui.cpp @@ -161,83 +161,6 @@ private: QDomDocument domDocument; }; -class ProgramOptions -{ -public: - ProgramOptions() - { - newcout = new ProgramOptionsStream(out); - oldcout = std::cout.rdbuf(newcout); - out.reserve(80); - newcerr = new ProgramOptionsStream(err); - oldcerr = std::cerr.rdbuf(newcerr); - err.reserve(80); - - error = true; - ::atexit(ProgramOptions::failure); - } - ~ProgramOptions() - { - std::cout.rdbuf(oldcout); - delete newcout; - std::cerr.rdbuf(oldcerr); - delete newcerr; - error = false; - } - static void failure() - { - if (error) { - int argc=0; - QApplication app(argc,0); - QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str()); - if (!err.empty()) { - QString msg = QString::fromAscii(err.c_str()); - QString s = QLatin1String("
") + msg + QLatin1String("
"); - QMessageBox::critical(0, appName, s); - } - else if (!out.empty()) { - QString msg = QString::fromAscii(out.c_str()); - QString s = QLatin1String("
") + msg + QLatin1String("
"); - QMessageBox::information(0, appName, s); - } - } - } - -private: - class ProgramOptionsStream : public std::streambuf - { - public: - ProgramOptionsStream(std::string& s) : buf(s) - { - } - int overflow(int c = EOF) - { - if (c != EOF) - buf.push_back((char)c); - return c; - } - int sync() - { - return 0; - } - private: - std::string& buf; - }; - -private: - friend class ProgramOptionsStream; - std::streambuf* oldcout; - std::streambuf* newcout; - std::streambuf* oldcerr; - std::streambuf* newcerr; - static std::string out, err; - static bool error; -}; - -bool ProgramOptions::error = false; -std::string ProgramOptions::out; -std::string ProgramOptions::err; - #if defined (FC_OS_LINUX) || defined(FC_OS_BSD) QString myDecoderFunc(const QByteArray &localFileName) { @@ -300,10 +223,25 @@ int main( int argc, char ** argv ) App::Application::Config()["RunMode"] = "Gui"; // Inits the Application - ProgramOptions po; App::Application::init(argc,argv); Gui::Application::initApplication(); } + catch (const Base::UnknownProgramOption& e) { + QApplication app(argc,argv); + QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str()); + QString msg = QString::fromAscii(e.what()); + QString s = QLatin1String("
") + msg + QLatin1String("
"); + QMessageBox::critical(0, appName, s); + exit(1); + } + catch (const Base::ProgramInformation& e) { + QApplication app(argc,argv); + QString appName = QString::fromAscii(App::Application::Config()["ExeName"].c_str()); + QString msg = QString::fromAscii(e.what()); + QString s = QLatin1String("
") + msg + QLatin1String("
"); + QMessageBox::information(0, appName, s); + exit(0); + } catch (const Base::Exception& e) { // Popup an own dialog box instead of that one of Windows QApplication app(argc,argv); diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 2025a6f30..83ceb4a96 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -154,31 +154,36 @@ def splitMesh(obj,mark=True): def makeFace(wires,method=2,cleanup=False): '''makeFace(wires): makes a face from a list of wires, finding which ones are holes''' - + #print "makeFace: start:", wires import Part if not isinstance(wires,list): + if len(wires.Vertexes) < 3: + raise return Part.Face(wires) elif len(wires) == 1: + #import Draft;Draft.printShape(wires[0]) + if len(wires[0].Vertexes) < 3: + raise return Part.Face(wires[0]) wires = wires[:] - print "inner wires found" + #print "makeFace: inner wires found" ext = None max_length = 0 # cleaning up rubbish in wires if cleanup: for i in range(len(wires)): wires[i] = DraftGeomUtils.removeInterVertices(wires[i]) - print "garbage removed" + #print "makeFace: garbage removed" for w in wires: # we assume that the exterior boundary is that one with # the biggest bounding box if w.BoundBox.DiagonalLength > max_length: max_length = w.BoundBox.DiagonalLength ext = w - print "exterior wire",ext + #print "makeFace: exterior wire",ext wires.remove(ext) if method == 1: @@ -186,23 +191,22 @@ def makeFace(wires,method=2,cleanup=False): # all interior wires mark a hole and must reverse # their orientation, otherwise Part.Face fails for w in wires: - print "reversing",w + #print "makeFace: reversing",w w.reverse() - print "reversed" # make sure that the exterior wires comes as first in the list wires.insert(0, ext) - print "done sorting", wires + #print "makeFace: done sorting", wires if wires: return Part.Face(wires) else: # method 2: use the cut method mf = Part.Face(ext) - print "external face:",mf + #print "makeFace: external face:",mf for w in wires: f = Part.Face(w) - print "internal face:",f + #print "makeFace: internal face:",f mf = mf.cut(f) - print "final face:",mf.Faces + #print "makeFace: final face:",mf.Faces return mf.Faces[0] def meshToShape(obj,mark=True): diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index 5e0206fe9..7b220f588 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -62,7 +62,8 @@ def addToComponent(compobject,addobject,mod=None): l = getattr(compobject,mod) l.append(addobject) setattr(compobject,mod,l) - addobject.ViewObject.hide() + if mod != "Objects": + addobject.ViewObject.hide() else: for a in attribs[:3]: if hasattr(compobject,a): diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index 460d3a7d1..f71828a96 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -21,7 +21,7 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,math,Draft,ArchCommands, DraftVecUtils +import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,math,Draft,ArchCommands,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore from pivy import coin @@ -215,7 +215,7 @@ class _ArchDrawingView: import ArchVRM render = ArchVRM.Renderer() render.setWorkingPlane(obj.Source.Placement) - render.addObjects(objs) + render.addObjects(Draft.getGroupContents(objs,walls=True)) render.cut(obj.Source.Shape) svg += render.getViewSVG(linewidth=linewidth) svg += render.getSectionSVG(linewidth=linewidth*2) diff --git a/src/Mod/Arch/ArchVRM.py b/src/Mod/Arch/ArchVRM.py index 2eefd8f27..91edfed56 100644 --- a/src/Mod/Arch/ArchVRM.py +++ b/src/Mod/Arch/ArchVRM.py @@ -145,12 +145,14 @@ class Renderer: def reorient(self): "reorients the faces on the WP" + #print "VRM: start reorient" if not self.faces: return self.faces = [self.projectFace(f) for f in self.faces] if self.sections: self.sections = [self.projectFace(f) for f in self.sections] self.oriented = True + #print "VRM: end reorient" def removeHidden(self): "removes faces pointing outwards" @@ -166,17 +168,24 @@ class Renderer: def projectFace(self,face): "projects a single face on the WP" + #print "VRM: projectFace start: ",len(face[0].Vertexes)," verts, ",len(face[0].Edges)," edges" wires = [] + if not face[0].Wires: + if DEBUG: print "Error: Unable to project face on the WP" + return None norm = face[0].normalAt(0,0) for w in face[0].Wires: verts = [] edges = DraftGeomUtils.sortEdges(w.Edges) + #print len(edges)," edges after sorting" for e in edges: v = e.Vertexes[0].Point + #print v v = self.wp.getLocalCoords(v) verts.append(v) verts.append(verts[0]) if len(verts) > 2: + #print "new wire with ",len(verts) wires.append(Part.makePolygon(verts)) try: sh = ArchCommands.makeFace(wires) @@ -188,6 +197,7 @@ class Renderer: vnorm = self.wp.getLocalCoords(norm) if vnorm.getAngle(sh.normalAt(0,0)) > 1: sh.reverse() + #print "VRM: projectFace end: ",len(sh.Vertexes)," verts" return [sh]+face[1:] def flattenFace(self,face): @@ -211,6 +221,7 @@ class Renderer: def cut(self,cutplane): "Cuts through the shapes with a given cut plane and builds section faces" + if DEBUG: print "\n\n======> Starting cut\n\n" if self.iscut: return if not self.shapes: @@ -262,12 +273,10 @@ class Renderer: shapes.append([c]+sh[1:]) for f in c.Faces: faces.append([f]+sh[1:]) - sec = sol.section(cutface) - if sec.Edges: - wires = DraftGeomUtils.findWires(sec.Edges) - for w in wires: - sec = Part.Face(w) - sections.append([sec,fill]) + print "iscoplanar:",f.Vertexes[0].Point,f.normalAt(0,0),cutface.Vertexes[0].Point,cutface.normalAt(0,0) + if DraftGeomUtils.isCoplanar([f,cutface]): + print "COPLANAR" + sections.append([f,fill]) self.shapes = shapes self.faces = faces self.sections = sections @@ -277,6 +286,7 @@ class Renderer: self.trimmed = False self.sorted = False self.joined = False + if DEBUG: print "\n\n======> Finished cut\n\n" def isInside(self,vert,face): "Returns True if the vert is inside the face in Z projection" @@ -319,6 +329,15 @@ class Renderer: def compare(self,face1,face2): "zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise" + #print face1,face2 + + if not face1: + if DEBUG: print "Warning, undefined face!" + return 31 + elif not face2: + if DEBUG: print "Warning, undefined face!" + return 32 + # theory from # http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm # and practical application http://vrm.ao2.it/ (blender vector renderer) @@ -456,14 +475,17 @@ class Renderer: def sort(self): "projects a shape on the WP" + if DEBUG: print "\n\n======> Starting sort\n\n" if len(self.faces) <= 1: return if not self.trimmed: self.removeHidden() + if DEBUG: print "Done hidden face removal" if len(self.faces) == 1: return if not self.oriented: self.reorient() + if DEBUG: print "Done reorientation" faces = self.faces[:] if DEBUG: print "sorting ",len(self.faces)," faces" sfaces = [] @@ -492,6 +514,7 @@ class Renderer: for f2 in faces[1:]: if DEBUG: print "comparing face",str(self.faces.index(f1))," with face",str(self.faces.index(f2)) r = self.compare(f1,f2) + print "comparison result:",r if r == 1: faces.remove(f2) sfaces.append(f2) @@ -506,6 +529,10 @@ class Renderer: sfaces.append(f2) notfoundstack = 0 break + elif r == 31: + faces.remove(f1) + elif r == 32: + faces.remove(f2) else: # nothing found, move the face to the end of the pile faces.remove(f1) @@ -518,6 +545,7 @@ class Renderer: if DEBUG: print "done Z sorting. ", len(sfaces), " faces retained, ", len(self.faces)-len(sfaces), " faces lost." self.faces = sfaces self.sorted = True + if DEBUG: print "\n\n======> Finished sort\n\n" def buildDummy(self): "Builds a dummy object with faces spaced on the Z axis, for visual check" @@ -544,19 +572,21 @@ class Renderer: def getPathData(self,w): "Returns a SVG path data string from a 2D wire" + def tostr(val): + return str(round(val,DraftVecUtils.precision())) edges = DraftGeomUtils.sortEdges(w.Edges) v = edges[0].Vertexes[0].Point - svg = 'M '+ str(v.x) +' '+ str(v.y) + ' ' + svg = 'M '+ tostr(v.x) +' '+ tostr(v.y) + ' ' for e in edges: if isinstance(e.Curve,Part.Line) or isinstance(e.Curve,Part.BSplineCurve): v = e.Vertexes[-1].Point - svg += 'L '+ str(v.x) +' '+ str(v.y) + ' ' + svg += 'L '+ tostr(v.x) +' '+ tostr(v.y) + ' ' elif isinstance(e.Curve,Part.Circle): r = e.Curve.Radius v = e.Vertexes[-1].Point - svg += 'A '+ str(r) + ' '+ str(r) +' 0 0 1 '+ str(v.x) +' ' - svg += str(v.y) + ' ' - svg += 'z ' + svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' ' + svg += tostr(v.y) + ' ' + svg += 'Z ' return svg def getViewSVG(self,linewidth=0.01): @@ -566,44 +596,47 @@ class Renderer: self.sort() svg = '' for f in self.faces: - fill = self.getFill(f[1]) - svg +=' a2: + a1,a2 = a2,a1 + + #print "creating sketch arc from ",cu, ", p1=",v1, " (",math.degrees(a1), "d) p2=",v2," (", math.degrees(a2),"d)" + p= Part.ArcOfCircle(cu,a1,a2) + return p + else: + return edge.Curve def mirror (point, edge): "finds mirror point relative to an edge" @@ -445,98 +451,91 @@ def isLine(bsp): return True def sortEdges(lEdges, aVertex=None): - "an alternative, more accurate version of Part.__sortEdges__" + "an alternative, more accurate version of Part.__sortEdges__" - #There is no reason to limit this to lines only because every non-closed edge always - #has exactly two vertices (wmayer) - #for e in lEdges: - # if not isinstance(e.Curve,Part.Line): - # print "Warning: sortedges cannot treat wired containing curves yet." - # return lEdges - - def isSameVertex(V1, V2): - ''' Test if vertexes have same coordinates with precision 10E(-precision)''' - if round(V1.X-V2.X,1)==0 and round(V1.Y-V2.Y,1)==0 and round(V1.Z-V2.Z,1)==0 : - return True - else : - return False - - def lookfor(aVertex, inEdges): - ''' Look for (aVertex, inEdges) returns count, the position of the instance - the position in the instance and the instance of the Edge''' - count = 0 - linstances = [] #lists the instances of aVertex - for i in range(len(inEdges)) : - for j in range(2) : - if isSameVertex(aVertex,inEdges[i].Vertexes[j-1]): - instance = inEdges[i] - count += 1 - linstances += [i,j-1,instance] - return [count]+linstances - - if (len(lEdges) < 2): - if aVertex == None: - return lEdges + #There is no reason to limit this to lines only because every non-closed edge always + #has exactly two vertices (wmayer) + #for e in lEdges: + # if not isinstance(e.Curve,Part.Line): + # print "Warning: sortedges cannot treat wired containing curves yet." + # return lEdges + + def lookfor(aVertex, inEdges): + ''' Look for (aVertex, inEdges) returns count, the position of the instance + the position in the instance and the instance of the Edge''' + count = 0 + linstances = [] #lists the instances of aVertex + for i in range(len(inEdges)) : + for j in range(2) : + if aVertex.Point == inEdges[i].Vertexes[j-1].Point: + instance = inEdges[i] + count += 1 + linstances += [i,j-1,instance] + return [count]+linstances + + if (len(lEdges) < 2): + if aVertex == None: + return lEdges + else: + result = lookfor(aVertex,lEdges) + if result[0] != 0: + if aVertex.Point == result[3].Vertexes[0].Point: + return lEdges else: - result = lookfor(aVertex,lEdges) - if result[0] != 0: - if isSameVertex(aVertex,result[3].Vertexes[0]): - return lEdges - else: - if isinstance(result[3].Curve,Part.Line): - return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()] - elif isinstance(result[3].Curve,Part.Circle): - mp = findMidpoint(result[3]) - return [Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape()] - elif isinstance(result[3].Curve,Part.BSplineCurve): - if isLine(result[3].Curve): - return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()] - else: - return lEdges - else: - return lEdges - - olEdges = [] # ol stands for ordered list - if aVertex == None: - for i in range(len(lEdges)*2) : - if len(lEdges[i/2].Vertexes) > 1: - result = lookfor(lEdges[i/2].Vertexes[i%2],lEdges) - if result[0] == 1 : # Have we found an end ? - olEdges = sortEdges(lEdges, result[3].Vertexes[result[2]]) - return olEdges - # if the wire is closed there is no end so choose 1st Vertex - #print "closed wire, starting from ",lEdges[0].Vertexes[0].Point - return sortEdges(lEdges, lEdges[0].Vertexes[0]) - else : - #print "looking ",aVertex.Point - result = lookfor(aVertex,lEdges) - if result[0] != 0 : - del lEdges[result[1]] - next = sortEdges(lEdges, result[3].Vertexes[-((-result[2])^1)]) - #print "result ",result[3].Vertexes[0].Point," ",result[3].Vertexes[1].Point, " compared to ",aVertex.Point - if isSameVertex(aVertex,result[3].Vertexes[0]): - #print "keeping" - olEdges += [result[3]] + next + if isinstance(result[3].Curve,Part.Line): + return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()] + elif isinstance(result[3].Curve,Part.Circle): + mp = findMidpoint(result[3]) + return [Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape()] + elif isinstance(result[3].Curve,Part.BSplineCurve): + if isLine(result[3].Curve): + return [Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape()] else: - #print "inverting", result[3].Curve - if isinstance(result[3].Curve,Part.Line): - newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape() - olEdges += [newedge] + next - elif isinstance(result[3].Curve,Part.Circle): - mp = findMidpoint(result[3]) - newedge = Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape() - olEdges += [newedge] + next - elif isinstance(result[3].Curve,Part.BSplineCurve): - if isLine(result[3].Curve): - newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape() - olEdges += [newedge] + next - else: - olEdges += [result[3]] + next - else: - olEdges += [result[3]] + next - return olEdges - else : - return [] + return lEdges + else: + return lEdges + + olEdges = [] # ol stands for ordered list + if aVertex == None: + for i in range(len(lEdges)*2) : + if len(lEdges[i/2].Vertexes) > 1: + result = lookfor(lEdges[i/2].Vertexes[i%2],lEdges) + if result[0] == 1 : # Have we found an end ? + olEdges = sortEdges(lEdges, result[3].Vertexes[result[2]]) + return olEdges + # if the wire is closed there is no end so choose 1st Vertex + # print "closed wire, starting from ",lEdges[0].Vertexes[0].Point + return sortEdges(lEdges, lEdges[0].Vertexes[0]) + else : + #print "looking ",aVertex.Point + result = lookfor(aVertex,lEdges) + if result[0] != 0 : + del lEdges[result[1]] + next = sortEdges(lEdges, result[3].Vertexes[-((-result[2])^1)]) + #print "result ",result[3].Vertexes[0].Point," ",result[3].Vertexes[1].Point, " compared to ",aVertex.Point + if aVertex.Point == result[3].Vertexes[0].Point: + #print "keeping" + olEdges += [result[3]] + next + else: + #print "inverting", result[3].Curve + if isinstance(result[3].Curve,Part.Line): + newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape() + olEdges += [newedge] + next + elif isinstance(result[3].Curve,Part.Circle): + mp = findMidpoint(result[3]) + newedge = Part.Arc(aVertex.Point,mp,result[3].Vertexes[0].Point).toShape() + olEdges += [newedge] + next + elif isinstance(result[3].Curve,Part.BSplineCurve): + if isLine(result[3].Curve): + newedge = Part.Line(aVertex.Point,result[3].Vertexes[0].Point).toShape() + olEdges += [newedge] + next + else: + olEdges += [result[3]] + next + else: + olEdges += [result[3]] + next + return olEdges + else : + return [] def findWires(edgeslist): @@ -787,6 +786,31 @@ def getNormal(shape): if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n) return n +def getRotation(v1,v2=FreeCAD.Vector(0,0,1)): + '''Get the rotation Quaternion between 2 vectors''' + if (v1.dot(v2) > 0.999999) or (v1.dot(v2) < -0.999999): + # vectors are opposite + return None + axis = v1.cross(v2) + axis.normalize() + angle = math.degrees(math.sqrt((v1.Length ^ 2) * (v2.Length ^ 2)) + v1.dot(v2)) + return FreeCAD.Rotation(axis,angle) + +def calculatePlacement(shape): + '''calculatePlacement(shape): if the given shape is planar, this function + returns a placement located at the center of gravity of the shape, and oriented + towards the shape's normal. Otherwise, it returns a null placement.''' + if not isPlanar(shape): + return FreeCAD.Placement() + pos = shape.BoundBox.Center + norm = getNormal(shape) + pla = FreeCAD.Placement() + pla.Base = pos + r = getRotation(norm) + if r: + pla.Rotation = r + return pla + def offsetWire(wire,dvec,bind=False,occ=False): ''' offsetWire(wire,vector,[bind]): offsets the given wire along the @@ -982,11 +1006,13 @@ def isCoplanar(faces): "checks if all faces in the given list are coplanar" if len(faces) < 2: return True - base =faces[0].normalAt(.5,.5) + base =faces[0].normalAt(0,0) for i in range(1,len(faces)): - normal = faces[i].normalAt(.5,.5) - if (normal.getAngle(base) > .0001) and (normal.getAngle(base) < 3.1415): - return False + for v in faces[i].Vertexes: + chord = v.Point.sub(faces[0].Vertexes[0].Point) + dist = DraftVecUtils.project(chord,base) + if round(dist.Length,DraftVecUtils.precision()) > 0: + return False return True def isPlanar(shape): diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index 099041d0a..7a7c7056f 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -51,8 +51,8 @@ if open.__module__ == '__builtin__': pythonopen = open svgcolors = { - 'Pink': (255, 192, 203), - 'Blue': (0, 0, 255), + 'Pink': (255, 192, 203), + 'Blue': (0, 0, 255), 'Honeydew': (240, 255, 240), 'Purple': (128, 0, 128), 'Fuchsia': (255, 0, 255), @@ -269,7 +269,7 @@ def makewire(path,checkclosed=False,donttry=False): #ToDo Do not catch all exceptions if not donttry: try: - sh = Part.Wire(DraftGeomUtils.sortEdges(path)) + sh = Part.Wire(DraftGeomUtils.sortEdges(path)) #sh = Part.Wire(path) isok = (not checkclosed) or sh.isClosed() except:# BRep_API:command not done @@ -448,8 +448,7 @@ class svgHandler(xml.sax.ContentHandler): abh = getsize(h,unitmode) sx=abw/vbw sy=abh/vbh - preservearstr=data.get('preserveAspectRatio',\ - '').lower() + preservearstr=' '.join(data.get('preserveAspectRatio',[])).lower() uniformscaling = round(sx/sy,5) == 1 if uniformscaling: m.scale(Vector(sx,sy,1)) @@ -534,7 +533,8 @@ class svgHandler(xml.sax.ContentHandler): if path: #sh = Part.Wire(path) sh = makewire(path) - if self.fill: sh = Part.Face(sh) + if self.fill and sh.isClosed(): + sh = Part.Face(sh) sh = self.applyTrans(sh) obj = self.doc.addObject("Part::Feature",pathname) obj.Shape = sh @@ -624,7 +624,8 @@ class svgHandler(xml.sax.ContentHandler): if sweepflag: #angledelta=-(-angledelta % (math.pi *2)) # Step4 #angledelta=(-angledelta % (math.pi *2)) # Step4 - angle1 = angle1-angledelta + angle1 = angle1+angledelta + angledelta = -angledelta #angle1 = math.pi - angle1 e1a = Part.Arc(e1,angle1-swapaxis*math.radians(90),\ @@ -750,7 +751,8 @@ class svgHandler(xml.sax.ContentHandler): if path: sh=makewire(path,checkclosed=False) #sh = Part.Wire(path) - if self.fill: sh = Part.Face(sh) + if self.fill and sh.isClosed(): + sh = Part.Face(sh) sh = self.applyTrans(sh) obj = self.doc.addObject("Part::Feature",pathname) obj.Shape = sh @@ -828,7 +830,6 @@ class svgHandler(xml.sax.ContentHandler): obj = self.doc.addObject("Part::Feature",pathname) obj.Shape = sh self.format(obj) - # processing lines if name == "line": @@ -864,7 +865,8 @@ class svgHandler(xml.sax.ContentHandler): path.append(seg) if path: sh = Part.Wire(path) - if self.fill: sh = Part.Face(sh) + if self.fill and sh.isClosed(): + sh = Part.Face(sh) sh = self.applyTrans(sh) obj = self.doc.addObject("Part::Feature",pathname) obj.Shape = sh diff --git a/src/Mod/Part/App/BSplineSurfacePy.xml b/src/Mod/Part/App/BSplineSurfacePy.xml index 413e94247..6bfebdb44 100644 --- a/src/Mod/Part/App/BSplineSurfacePy.xml +++ b/src/Mod/Part/App/BSplineSurfacePy.xml @@ -677,5 +677,10 @@ Returns a reparametrized copy of this surface + + + Replaces this B-Spline surface by interpolating a set of points. + + diff --git a/src/Mod/Part/App/BSplineSurfacePyImp.cpp b/src/Mod/Part/App/BSplineSurfacePyImp.cpp index c016f277a..f642662f4 100644 --- a/src/Mod/Part/App/BSplineSurfacePyImp.cpp +++ b/src/Mod/Part/App/BSplineSurfacePyImp.cpp @@ -31,6 +31,8 @@ # include # include # include +# include +# include #endif #include @@ -1242,6 +1244,55 @@ PyObject* BSplineSurfacePy::reparametrize(PyObject * args) } } +PyObject* BSplineSurfacePy::interpolate(PyObject *args) +{ + PyObject* obj; + double tol3d = Precision::Approximation(); + PyObject* closed = Py_False; + PyObject* t1=0; PyObject* t2=0; + if (!PyArg_ParseTuple(args, "O!",&(PyList_Type), &obj)) + return 0; + try { + Py::List list(obj); + Standard_Integer lu = list.size(); + Py::List col(list.getItem(0)); + Standard_Integer lv = col.size(); + TColgp_Array2OfPnt interpolationPoints(1, lu, 1, lv); + + Standard_Integer index1 = 0; + Standard_Integer index2 = 0; + for (Py::List::iterator it1 = list.begin(); it1 != list.end(); ++it1) { + index1++; + index2=0; + Py::List row(*it1); + for (Py::List::iterator it2 = row.begin(); it2 != row.end(); ++it2) { + index2++; + Py::Vector v(*it2); + Base::Vector3d pnt = v.toVector(); + gp_Pnt newPoint(pnt.x,pnt.y,pnt.z); + interpolationPoints.SetValue(index1, index2, newPoint); + } + } + + if (interpolationPoints.RowLength() < 2 || interpolationPoints.ColLength() < 2) { + Standard_Failure::Raise("not enough points given"); + } + + GeomAPI_PointsToBSplineSurface surInterpolation; + surInterpolation.Interpolate (interpolationPoints); + Handle_Geom_BSplineSurface sur(surInterpolation.Surface()); + this->getGeomBSplineSurfacePtr()->setHandle(sur); + Py_Return; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + std::string err = e->GetMessageString(); + if (err.empty()) err = e->DynamicType()->Name(); + PyErr_SetString(PyExc_Exception, err.c_str()); + return 0; + } +} + Py::Int BSplineSurfacePy::getUDegree(void) const { Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast diff --git a/src/Mod/Part/App/Geometry.cpp b/src/Mod/Part/App/Geometry.cpp index 7f3b9f71b..2f8450d3a 100644 --- a/src/Mod/Part/App/Geometry.cpp +++ b/src/Mod/Part/App/Geometry.cpp @@ -1362,6 +1362,11 @@ GeomBSplineSurface::~GeomBSplineSurface() { } +void GeomBSplineSurface::setHandle(const Handle_Geom_BSplineSurface& s) +{ + mySurface = Handle_Geom_BSplineSurface::DownCast(s->Copy()); +} + const Handle_Geom_Geometry& GeomBSplineSurface::handle() const { return mySurface; diff --git a/src/Mod/Part/App/Geometry.h b/src/Mod/Part/App/Geometry.h index f8a8efa5e..d04797083 100644 --- a/src/Mod/Part/App/Geometry.h +++ b/src/Mod/Part/App/Geometry.h @@ -448,6 +448,7 @@ public: // Base implementer ---------------------------- virtual PyObject *getPyObject(void); + void setHandle(const Handle_Geom_BSplineSurface&); const Handle_Geom_Geometry& handle() const; private: diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 8ebac8242..d8a5a13e2 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -726,6 +726,11 @@ void TopoShape::exportBrep(const char *filename) const throw Base::Exception("Writing of BREP failed"); } +void TopoShape::exportBrep(std::ostream& out) +{ + BRepTools::Write(this->_Shape, out); +} + void TopoShape::exportStl(const char *filename) const { StlAPI_Writer writer; diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index aaf521e05..26e891a9c 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -126,6 +126,7 @@ public: void exportIges(const char *FileName) const; void exportStep(const char *FileName) const; void exportBrep(const char *FileName) const; + void exportBrep(std::ostream&); void exportStl (const char *FileName) const; void exportFaceSet(double, double, std::ostream&) const; void exportLineSet(std::ostream&) const; diff --git a/src/Mod/Part/App/TopoShapeEdgePy.xml b/src/Mod/Part/App/TopoShapeEdgePy.xml index 40def1030..fe0b5b0f7 100644 --- a/src/Mod/Part/App/TopoShapeEdgePy.xml +++ b/src/Mod/Part/App/TopoShapeEdgePy.xml @@ -88,11 +88,23 @@ - Returns a 4 tuple with the parameter range + Returns a 2 tuple with the parameter range - + + + Returns the start value of the parameter range + + + + + + Returns the end value of the parameter range + + + + Returns the 3D curve of the edge diff --git a/src/Mod/Part/App/TopoShapeEdgePyImp.cpp b/src/Mod/Part/App/TopoShapeEdgePyImp.cpp index 329c6bd6c..16807df2e 100644 --- a/src/Mod/Part/App/TopoShapeEdgePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeEdgePyImp.cpp @@ -660,6 +660,22 @@ Py::Tuple TopoShapeEdgePy::getParameterRange(void) const return t; } +Py::Float TopoShapeEdgePy::getFirstParameter(void) const +{ + const TopoDS_Edge& e = TopoDS::Edge(getTopoShapePtr()->_Shape); + BRepAdaptor_Curve adapt(e); + double t = adapt.FirstParameter(); + return Py::Float(t); +} + +Py::Float TopoShapeEdgePy::getLastParameter(void) const +{ + const TopoDS_Edge& e = TopoDS::Edge(getTopoShapePtr()->_Shape); + BRepAdaptor_Curve adapt(e); + double t = adapt.LastParameter(); + return Py::Float(t); +} + Py::Object TopoShapeEdgePy::getCenterOfMass(void) const { GProp_GProps props; diff --git a/src/Mod/Part/App/TopoShapePy.xml b/src/Mod/Part/App/TopoShapePy.xml index 34522f5f9..c144c1986 100644 --- a/src/Mod/Part/App/TopoShapePy.xml +++ b/src/Mod/Part/App/TopoShapePy.xml @@ -43,6 +43,11 @@ Sub-elements such as vertices, edges or faces are accessible as: Export the content of this shape to an BREP file. BREP is a CasCade native format. + + + Export the content of this shape to a string in BREP format. BREP is a CasCade native format. + + Export the content of this shape to an STL mesh file. @@ -53,6 +58,11 @@ Sub-elements such as vertices, edges or faces are accessible as: Import the content to this shape of a string in BREP format. + + + Import the content to this shape from a string in BREP format. + + Extrude the shape along a direction. diff --git a/src/Mod/Part/App/TopoShapePyImp.cpp b/src/Mod/Part/App/TopoShapePyImp.cpp index 8f641a2f7..1dc8bfc3a 100644 --- a/src/Mod/Part/App/TopoShapePyImp.cpp +++ b/src/Mod/Part/App/TopoShapePyImp.cpp @@ -311,6 +311,32 @@ PyObject* TopoShapePy::exportBrep(PyObject *args) Py_Return; } +PyObject* TopoShapePy::exportBrepToString(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + + try { + // write brep file + std::stringstream str; + getTopoShapePtr()->exportBrep(str); + return Py::new_reference_to(Py::String(str.str())); + } + catch (const Base::Exception& e) { + PyErr_SetString(PyExc_Exception,e.what()); + return NULL; + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_Exception,e.what()); + return NULL; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } +} + PyObject* TopoShapePy::importBrep(PyObject *args) { PyObject* input; @@ -335,6 +361,34 @@ PyObject* TopoShapePy::importBrep(PyObject *args) Py_Return; } +PyObject* TopoShapePy::importBrepFromString(PyObject *args) +{ + char* input; + if (!PyArg_ParseTuple(args, "s", &input)) + return NULL; + + try { + // read brep + std::stringstream str(input); + getTopoShapePtr()->importBrep(str); + } + catch (const Base::Exception& e) { + PyErr_SetString(PyExc_Exception,e.what()); + return NULL; + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_Exception,e.what()); + return NULL; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } + + Py_Return; +} + PyObject* TopoShapePy::exportStl(PyObject *args) { char* filename; diff --git a/src/Mod/Part/Gui/DlgPrimitives.cpp b/src/Mod/Part/Gui/DlgPrimitives.cpp index 3e4628646..7ef822edf 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.cpp +++ b/src/Mod/Part/Gui/DlgPrimitives.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -270,6 +271,9 @@ DlgPrimitives::~DlgPrimitives() void DlgPrimitives::pickCallback(void * ud, SoEventCallback * n) { const SoMouseButtonEvent * mbe = static_cast(n->getEvent()); + Picker* pick = reinterpret_cast(ud); + if (pick->exitCode >= 0) + pick->loop.exit(pick->exitCode); // Mark all incoming mouse button events as handled, especially, to deactivate the selection node n->setHandled(); @@ -277,16 +281,14 @@ void DlgPrimitives::pickCallback(void * ud, SoEventCallback * n) if (mbe->getState() == SoButtonEvent::DOWN) { const SoPickedPoint * point = n->getPickedPoint(); if (point) { - Picker* pick = reinterpret_cast(ud); if (pick->pickedPoint(point)) { - pick->loop.exit(0); + pick->exitCode = 0; } } } } else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2) { if (mbe->getState() == SoButtonEvent::UP) { - Picker* pick = reinterpret_cast(ud); pick->loop.exit(1); } } @@ -305,9 +307,17 @@ void DlgPrimitives::executeCallback(Picker* p) if (!viewer->isEditing()) { viewer->setEditing(true); viewer->setRedirectToSceneGraph(true); + SoNode* root = viewer->getSceneGraph(); + int mode; + if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) { + mode = static_cast(root)->selectionMode.getValue(); + static_cast(root)->selectionMode.setValue(Gui::SoFCUnifiedSelection::OFF); + } viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, p); this->setDisabled(true); int ret = p->loop.exec(); + if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) + static_cast(root)->selectionMode.setValue(mode); this->setEnabled(true); viewer->setEditing(false); viewer->setRedirectToSceneGraph(false); @@ -587,6 +597,9 @@ Location::~Location() viewer->setEditing(false); viewer->setRedirectToSceneGraph(false); viewer->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,this); + SoNode* root = viewer->getSceneGraph(); + if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) + static_cast(root)->selectionMode.setValue(this->mode); } } @@ -605,6 +618,11 @@ void Location::on_viewPositionButton_clicked() viewer->setEditing(true); viewer->setRedirectToSceneGraph(true); viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback, this); + SoNode* root = viewer->getSceneGraph(); + if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) { + this->mode = static_cast(root)->selectionMode.getValue(); + static_cast(root)->selectionMode.setValue(Gui::SoFCUnifiedSelection::OFF); + } } } } @@ -617,15 +635,7 @@ void Location::pickCallback(void * ud, SoEventCallback * n) // Mark all incoming mouse button events as handled, especially, to deactivate the selection node n->getAction()->setHandled(); if (mbe->getButton() == SoMouseButtonEvent::BUTTON1) { - if (mbe->getState() == SoButtonEvent::UP) { - n->setHandled(); - view->setEditing(false); - view->setRedirectToSceneGraph(false); - Location* dlg = reinterpret_cast(ud); - dlg->activeView = 0; - view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud); - } - else if (mbe->getState() == SoButtonEvent::DOWN) { + if (mbe->getState() == SoButtonEvent::DOWN) { const SoPickedPoint * point = n->getPickedPoint(); if (point) { SbVec3f pnt = point->getPoint(); @@ -637,6 +647,19 @@ void Location::pickCallback(void * ud, SoEventCallback * n) } } } + else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2) { + if (mbe->getState() == SoButtonEvent::UP) { + n->setHandled(); + view->setEditing(false); + view->setRedirectToSceneGraph(false); + Location* dlg = reinterpret_cast(ud); + dlg->activeView = 0; + view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), pickCallback,ud); + SoNode* root = view->getSceneGraph(); + if (root && root->getTypeId().isDerivedFrom(Gui::SoFCUnifiedSelection::getClassTypeId())) + static_cast(root)->selectionMode.setValue(static_cast(ud)->mode); + } + } } QString Location::toPlacement() const diff --git a/src/Mod/Part/Gui/DlgPrimitives.h b/src/Mod/Part/Gui/DlgPrimitives.h index 178dff08a..4be65c31a 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.h +++ b/src/Mod/Part/Gui/DlgPrimitives.h @@ -39,7 +39,7 @@ namespace PartGui { class Picker { public: - Picker() + Picker() : exitCode(-1) { } virtual ~Picker() @@ -51,6 +51,7 @@ public: void createPrimitive(QWidget* widget, const QString&, Gui::Document*); QString toPlacement(const gp_Ax2&) const; + int exitCode; QEventLoop loop; }; @@ -88,6 +89,7 @@ private Q_SLOTS: private: static void pickCallback(void * ud, SoEventCallback * n); + int mode; QPointer activeView; Ui_Location ui; }; diff --git a/src/Mod/Part/Gui/DlgSettingsGeneral.ui b/src/Mod/Part/Gui/DlgSettingsGeneral.ui index 276f4acd7..26a04f6bf 100644 --- a/src/Mod/Part/Gui/DlgSettingsGeneral.ui +++ b/src/Mod/Part/Gui/DlgSettingsGeneral.ui @@ -71,7 +71,7 @@ - Model refinement + Model settings diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 837189bb1..d33676379 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -15,6 +15,7 @@ include_directories( link_directories(${OCC_LIBRARY_DIR}) set(PartDesign_LIBS + ${OCC_LIBRARIES} Part FreeCADApp ) diff --git a/src/Mod/Raytracing/Gui/Command.cpp b/src/Mod/Raytracing/Gui/Command.cpp index ef2affe17..aeebf3d24 100644 --- a/src/Mod/Raytracing/Gui/Command.cpp +++ b/src/Mod/Raytracing/Gui/Command.cpp @@ -102,8 +102,6 @@ void CmdRaytracingWriteCamera::activated(int iMsg) SoInput in; in.setBuffer((void*)ppReturn,std::strlen(ppReturn)); - //if (!in.openFile(filename)) { exit(1); } - SoNode* rootNode; SoDB::read(&in,rootNode); diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 02e508e76..fa9679fe2 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -731,9 +731,8 @@ public: virtual void mouseMove(Base::Vector2D onSketchPos) { - setPositionText(onSketchPos); - if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr1); return; @@ -750,6 +749,16 @@ public: EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - dx, EditCurve[0].fY - dy); } EditCurve[33] = EditCurve[1]; + + // Display radius and start angle + float radius = (onSketchPos - EditCurve[0]).Length(); + float angle = atan2f(dy_ , dx_) * 180 / M_PI; + + char buf[40]; + sprintf( buf, " (R%.1f,%.1f)", radius, angle); + std::string text = buf; + setPositionText(onSketchPos, text); + sketchgui->drawEdit(EditCurve); if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr2); @@ -767,6 +776,15 @@ public: float dy = rx * sin(angle) + ry * cos(angle); EditCurve[i] = Base::Vector2D(CenterPoint.fX + dx, CenterPoint.fY + dy); } + + // Display radius and end angle + float radius = (onSketchPos - EditCurve[0]).Length(); + + char buf[40]; + sprintf( buf, " (R%.1f,%.1f)", radius, arcAngle * 180 / M_PI); + std::string text = buf; + setPositionText(onSketchPos, text); + sketchgui->drawEdit(EditCurve); if (seekAutoConstraint(sugConstr3, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr3); @@ -950,8 +968,8 @@ public: virtual void mouseMove(Base::Vector2D onSketchPos) { - setPositionText(onSketchPos); if (Mode==STATUS_SEEK_First) { + setPositionText(onSketchPos); if (seekAutoConstraint(sugConstr1, onSketchPos, Base::Vector2D(0.f,0.f))) { renderSuggestConstraintsCursor(sugConstr1); return; @@ -968,6 +986,15 @@ public: EditCurve[17+i] = Base::Vector2D(EditCurve[0].fX - rx, EditCurve[0].fY - ry); } EditCurve[33] = EditCurve[1]; + + // Display radius for user + float radius = (onSketchPos - EditCurve[0]).Length(); + + char buf[40]; + sprintf( buf, "R%.1f", radius); + std::string text = buf; + setPositionText(onSketchPos, text); + sketchgui->drawEdit(EditCurve); if (seekAutoConstraint(sugConstr2, onSketchPos, Base::Vector2D(0.f,0.f), CURVE)) { renderSuggestConstraintsCursor(sugConstr2); diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp index f75cc8329..06018b5ca 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.cpp @@ -385,6 +385,12 @@ void DrawSketchHandler::renderSuggestConstraintsCursor(std::vectorsetPositionText(Pos, text); +} + + void DrawSketchHandler::setPositionText(const Base::Vector2D &Pos) { sketchgui->setPositionText(Pos); diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandler.h b/src/Mod/Sketcher/Gui/DrawSketchHandler.h index f5ccfa975..68ba93d2a 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandler.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandler.h @@ -87,6 +87,7 @@ public: void createAutoConstraints(const std::vector &autoConstrs, int geoId, Sketcher::PointPos pointPos=Sketcher::none); + void setPositionText(const Base::Vector2D &Pos, const std::string &text); void setPositionText(const Base::Vector2D &Pos); void resetPositionText(void); void renderSuggestConstraintsCursor(std::vector &suggestedConstraints); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 4b6cc1988..36c22a0db 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -3026,6 +3026,12 @@ void ViewProviderSketch::unsetEditViewer(Gui::View3DInventorViewer* viewer) static_cast(root)->selectionRole.setValue(TRUE); } +void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos, const std::string &text) +{ + edit->textX->string = text.c_str(); + edit->textPos->translation = SbVec3f(Pos.fX,Pos.fY,zText); +} + void ViewProviderSketch::setPositionText(const Base::Vector2D &Pos) { char buf[40]; diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 2c98d71eb..356d4414d 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -200,6 +200,7 @@ protected: /// build up the visual of the constraints void rebuildConstraintsVisual(void); + void setPositionText(const Base::Vector2D &Pos, const std::string &txt); void setPositionText(const Base::Vector2D &Pos); void resetPositionText(void);