diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ac2f98e51..f44c39c259 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,10 @@ if(CMAKE_COMPILER_IS_GNUCXX) add_definitions(-Wno-write-strings) add_definitions(-Wno-deprecated) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + # get linker errors as soon as possible and not at runtime e.g. for modules + if(UNIX) + # SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") + endif(UNIX) endif(CMAKE_COMPILER_IS_GNUCXX) @@ -96,7 +100,16 @@ OPTION(FREECAD_MAINTAINERS_BUILD "Build FreeCAD for Maintainers, with Docu and 3 OPTION(FREECAD_BUILD_CAM "Build the FreeCAD CAM module and the needed libs, be aware, unfinished code!" OFF) OPTION(FREECAD_BUILD_FEM "Build the FreeCAD FEM module, be aware, unfinished code!" ON) OPTION(FREECAD_BUILD_SANDBOX "Build the FreeCAD Sandbox module which is only for testing purposes" OFF) +OPTION(FREECAD_BUILD_TEMPLATE "Build the FreeCAD template module which is only for testing purposes" OFF) OPTION(FREECAD_BUILD_DEBIAN "Prepare for a build of a Debian package" OFF) +OPTION(FREECAD_USE_EXTERNAL_ZIPIOS "Use system installed zipios++ instead of the bundled." OFF) +OPTION(FREECAD_USE_EXTERNAL_PIVY "Use system installed python-pivy instead of the bundled." OFF) + +# if this is set override some options +if (FREECAD_BUILD_DEBIAN) + set(FREECAD_USE_EXTERNAL_ZIPIOS ON) + set(FREECAD_USE_EXTERNAL_PIVY ON) +endif (FREECAD_BUILD_DEBIAN) # ============================================================================== @@ -256,21 +269,21 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) # -------------------------------- ODE ---------------------------------- find_package(ODE) - + # -------------------------------- Qt -------------------------------- # sets ${QT_LIBRARIES} - SET(QT_MIN_VERSION 4.1.4) + SET(QT_MIN_VERSION 4.5.0) set(QT_USE_QTNETWORK TRUE) set(QT_USE_QTXML TRUE) - if(FREECAD_BUILD_GUI) - set(QT_USE_QTOPENGL TRUE) - set(QT_USE_QTSVG TRUE) - set(QT_USE_QTUITOOLS TRUE) - set(QT_USE_QTWEBKIT TRUE) - endif(FREECAD_BUILD_GUI) - find_package(Qt4) + if(FREECAD_BUILD_GUI) + set(QT_USE_QTOPENGL TRUE) + set(QT_USE_QTSVG TRUE) + set(QT_USE_QTUITOOLS TRUE) + set(QT_USE_QTWEBKIT TRUE) + endif(FREECAD_BUILD_GUI) + find_package(Qt4 REQUIRED) include(${QT_USE_FILE}) @@ -279,7 +292,7 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) ENDIF(NOT QT4_FOUND) IF(NOT QT_QTWEBKIT_FOUND) - MESSAGE("QT Webkit not found, will not build browser integration!") + MESSAGE("Qt Webkit not found, will not build browser integration!") ENDIF(NOT QT_QTWEBKIT_FOUND) @@ -290,22 +303,24 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) # There is probably a cleaner solution than this macro(fc_wrap_cpp outfiles ) # get include dirs - QT4_GET_MOC_FLAGS(moc_includes) + QT4_GET_MOC_FLAGS(moc_flags) QT4_EXTRACT_OPTIONS(moc_files moc_options ${ARGN}) + # fixes bug 0000585: bug with boost 1.48 + SET(moc_options ${moc_options} -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) foreach(it ${moc_files}) get_filename_component(it ${it} ABSOLUTE) QT4_MAKE_OUTPUT_FILE(${it} moc_ cpp outfile) - QT4_CREATE_MOC_COMMAND(${it} ${outfile} "${moc_includes}" "${moc_options}") + QT4_CREATE_MOC_COMMAND(${it} ${outfile} "${moc_flags}" "${moc_options}") set(${outfiles} ${${outfiles}} ${outfile}) add_file_dependencies(${it} ${outfile}) endforeach(it) endmacro(fc_wrap_cpp) - + if(FREECAD_BUILD_GUI) # -------------------------------- OpenGL -------------------------------- - find_package(OpenGL) + find_package(OpenGL) include(FindPackageMessage) if(OPENGL_GLU_FOUND) find_package_message(OPENGL_GLU @@ -317,16 +332,16 @@ MARK_AS_ADVANCED(FORCE FREECAD_LIBPACK_CHECKFILE6X FREECAD_LIBPACK_CHECKFILE7X) # -------------------------------- Coin3D -------------------------------- - find_package(Coin3D REQUIRED) - find_package(SoQt REQUIRED) + find_package(Coin3D REQUIRED) + find_package(SoQt REQUIRED) # ------------------------------ Spaceball ------------------------------- - if (WIN32) - #future - else(WIN32) - find_package(Spnav) - endif(WIN32) + if (WIN32) + #future + else(WIN32) + find_package(Spnav) + endif(WIN32) # ------------------------------------------------------------------------ @@ -391,6 +406,10 @@ IF(MINGW) SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mthreads -Wl,--export-all-symbols") LINK_LIBRARIES(-lgdi32) ENDIF(MINGW) +# 0000661: cmake build on Mac OS: dealing with dylib versus so +IF(APPLE) + SET(CMAKE_SHARED_LIBRARY_SUFFIX ".so") +ENDIF(APPLE) add_subdirectory(src) add_subdirectory(data) diff --git a/configure.ac b/configure.ac index 0484ab2744..6883a2f396 100644 --- a/configure.ac +++ b/configure.ac @@ -795,6 +795,26 @@ AC_ARG_ENABLE([sandbox], AM_CONDITIONAL(BUILD_SANDBOX, test x"$fc_set_sandbox" = xtrue) +AC_ARG_ENABLE([assembly], + AC_HELP_STRING([--enable-assembly], [Enable the build of the Assembly module (disabled by default)]), + [case $enableval in + no | false) fc_set_assembly=false ;; + *) fc_set_assembly=true ;; + esac], + [fc_set_assembly=false]) + +AM_CONDITIONAL(BUILD_ASSEMBLY, test x"$fc_set_assembly" = xtrue) + +AC_ARG_ENABLE([cam], + AC_HELP_STRING([--enable-cam], [Enable the build of the Cam module (disabled by default)]), + [case $enableval in + no | false) fc_set_cam=false ;; + *) fc_set_cam=true ;; + esac], + [fc_set_cam=false]) + +AM_CONDITIONAL(BUILD_CAM, test x"$fc_set_cam" = xtrue) + dnl Check if you want debug information enabled, or not dnl ************************************************************************** @@ -952,6 +972,13 @@ src/Main/Makefile src/Doc/Makefile src/Doc/BuildDevDoc.cfg src/Mod/Makefile +src/Mod/Assembly/App/Makefile +src/Mod/Assembly/Gui/Resources/Makefile +src/Mod/Assembly/Gui/Makefile +src/Mod/Assembly/Makefile +src/Mod/Cam/App/Makefile +src/Mod/Cam/Gui/Makefile +src/Mod/Cam/Makefile src/Mod/Part/Makefile src/Mod/Part/App/Makefile src/Mod/Part/Gui/Makefile @@ -1055,7 +1082,10 @@ AC_MSG_NOTICE([ RTTI enabled (forced): true Compiler warnings enabled: $fc_set_warn installation prefix: $prefix - + eneble-assembly: $fc_set_assembly + eneble-cam: $fc_set_cam + enable-sandbox: $fc_set_sandbox + eneble-template: $fc_set_template Now, run 'make' to build FreeCAD. ************************************************************************** diff --git a/data/examples/PartDesignExample.FCStd b/data/examples/PartDesignExample.FCStd index c49fd4ce3b..f3a4e24ce5 100644 Binary files a/data/examples/PartDesignExample.FCStd and b/data/examples/PartDesignExample.FCStd differ diff --git a/data/tests/PadTest.fcstd b/data/tests/PadTest.fcstd new file mode 100644 index 0000000000..8a7223083d Binary files /dev/null and b/data/tests/PadTest.fcstd differ diff --git a/data/tests/PocketTest.fcstd b/data/tests/PocketTest.fcstd new file mode 100644 index 0000000000..6acf91ba05 Binary files /dev/null and b/data/tests/PocketTest.fcstd differ diff --git a/src/3rdParty/CMakeLists.txt b/src/3rdParty/CMakeLists.txt index 5309c7a1fa..456c1f3253 100644 --- a/src/3rdParty/CMakeLists.txt +++ b/src/3rdParty/CMakeLists.txt @@ -20,7 +20,7 @@ elseif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE7X) #endif(MINGW) # applies for Unix, MinGW and Windows with custom LibPack elseif(FREECAD_BUILD_GUI) - if (NOT FREECAD_BUILD_DEBIAN) + if (NOT FREECAD_USE_EXTERNAL_PIVY) find_path(COIN_VERSION3 Inventor/scxml/ScXML.h ${COIN3D_INCLUDE_DIR}) if (COIN_VERSION3) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy-0.5) @@ -31,7 +31,7 @@ elseif(FREECAD_BUILD_GUI) add_subdirectory(Pivy) endif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Pivy) endif(COIN_VERSION3) - endif (NOT FREECAD_BUILD_DEBIAN) + endif (NOT FREECAD_USE_EXTERNAL_PIVY) endif(FREECAD_BUILD_GUI AND FREECAD_LIBPACK_CHECKFILE6X) # For Windows we have all stuff in the LibPack diff --git a/src/3rdParty/Pivy-0.5/CMakeLists.txt b/src/3rdParty/Pivy-0.5/CMakeLists.txt index 3b71e24a17..fc810fb790 100644 --- a/src/3rdParty/Pivy-0.5/CMakeLists.txt +++ b/src/3rdParty/Pivy-0.5/CMakeLists.txt @@ -88,7 +88,7 @@ if(MSVC) debug ${PYTHON_DEBUG_LIBRARY} optimized ${PYTHON_LIBRARY}) else(MSVC) - set(CoinPy_LIBS + set(SoQtPy_LIBS ${SOQT_LIBRARIES} ${COIN3D_LIBRARY} ${PYTHON_LIBRARY}) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 7f9eeea17f..17b99601fb 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -1220,6 +1220,32 @@ void Application::processCmdLineFiles(void) Console().Error("Unknown exception while processing file: %s \n", File.filePath().c_str()); } } + + 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() @@ -1419,9 +1445,14 @@ void Application::ParseOptions(int ac, char ** av) // in 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") + ("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") @@ -1444,11 +1475,35 @@ void Application::ParseOptions(int ac, char ** av) //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 args; copy(tok.begin(), tok.end(), back_inserter(args)); // Parse the file and store the options - store( boost::program_options::command_line_parser(ac, av). + store( boost::program_options::command_line_parser(args). options(cmdline_options).positional(p).extra_parser(customSyntax).run(), vm); } @@ -1548,6 +1604,15 @@ void Application::ParseOptions(int ac, char ** av) 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(); diff --git a/src/App/ApplicationPy.cpp b/src/App/ApplicationPy.cpp index d74b1b4a75..15781cc3d0 100644 --- a/src/App/ApplicationPy.cpp +++ b/src/App/ApplicationPy.cpp @@ -383,23 +383,36 @@ PyObject* Application::sGetVersion(PyObject * /*self*/, PyObject *args,PyObject if (!PyArg_ParseTuple(args, "")) // convert args: Python->C return NULL; // NULL triggers exception - PyObject* pList = PyList_New(5); - PyObject *pItem; - pItem = PyString_FromString(Application::Config()["BuildVersionMajor"].c_str()); - PyList_SetItem(pList, 0, pItem); - pItem = PyString_FromString(Application::Config()["BuildVersionMinor"].c_str()); - PyList_SetItem(pList, 1, pItem); - pItem = PyString_FromString(Application::Config()["BuildRevision"].c_str()); - PyList_SetItem(pList, 2, pItem); - pItem = PyString_FromString(Application::Config()["BuildRepositoryURL"].c_str()); - PyList_SetItem(pList, 4, pItem); - pItem = PyString_FromString(Application::Config()["BuildCurrentDate"].c_str()); - PyList_SetItem(pList, 6, pItem); + Py::List list; + const std::map& cfg = Application::Config(); + std::map::const_iterator it; - return pList; + it = cfg.find("BuildVersionMajor"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildVersionMinor"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRevision"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRepositoryURL"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRevisionDate"); + list.append(Py::String(it != cfg.end() ? it->second : "")); + + it = cfg.find("BuildRevisionBranch"); + if (it != cfg.end()) + list.append(Py::String(it->second)); + + it = cfg.find("BuildRevisionHash"); + if (it != cfg.end()) + list.append(Py::String(it->second)); + + return Py::new_reference_to(list); } - PyObject* Application::sAddImportType(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) { char *psKey,*psMod; diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 1b9879ee61..61d1b7921e 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -52,6 +52,7 @@ recompute path. Also enables more complicated dependencies beyond trees. #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include #endif @@ -62,6 +63,7 @@ recompute path. Also enables more complicated dependencies beyond trees. #include #include #include +#include #include "Document.h" @@ -1452,20 +1454,48 @@ void Document::breakDependency(DocumentObject* pcObject, bool clear) } } } + else if (pt->second->getTypeId().isDerivedFrom(PropertyLinkSubList::getClassTypeId())) { + PropertyLinkSubList* link = static_cast(pt->second); + if (link->getContainer() == pcObject && clear) { + link->setValues(std::vector(), std::vector()); + } + else { + const std::vector& links = link->getValues(); + const std::vector& sub = link->getSubValues(); + std::vector newLinks; + std::vector newSub; + + if (std::find(links.begin(), links.end(), pcObject) != links.end()) { + std::vector::const_iterator jt; + std::vector::const_iterator kt; + for (jt = links.begin(),kt = sub.begin(); jt != links.end() && kt != sub.end(); ++jt, ++kt) { + if (*jt != pcObject) { + newLinks.push_back(*jt); + newSub.push_back(*kt); + } + } + + link->setValues(newLinks, newSub); + } + } + } } } } DocumentObject* Document::_copyObject(DocumentObject* obj, std::map& copy_map, bool recursive) + DocumentObject*>& copy_map, bool recursive, + bool keepdigitsatend) { if (!obj) return 0; // remove number from end to avoid lengthy names std::string objname = obj->getNameInDocument(); + if (!keepdigitsatend) { size_t lastpos = objname.length()-1; while (objname[lastpos] >= 48 && objname[lastpos] <= 57) lastpos--; objname = objname.substr(0, lastpos+1); + } DocumentObject* copy = addObject(obj->getTypeId().getName(),objname.c_str()); if (!copy) return 0; copy->addDynamicProperties(obj); @@ -1485,7 +1515,7 @@ DocumentObject* Document::_copyObject(DocumentObject* obj, std::map(it->second)->setValue(pt->second); } else if (recursive) { - DocumentObject* link_copy = _copyObject(link, copy_map, recursive); + DocumentObject* link_copy = _copyObject(link, copy_map, recursive, keepdigitsatend); copy_map[link] = link_copy; static_cast(it->second)->setValue(link_copy); } @@ -1504,7 +1534,7 @@ DocumentObject* Document::_copyObject(DocumentObject* obj, std::mapsecond); } else { - links_copy.push_back(_copyObject(*jt, copy_map, recursive)); + links_copy.push_back(_copyObject(*jt, copy_map, recursive, keepdigitsatend)); copy_map[*jt] = links_copy.back(); } } @@ -1534,10 +1564,10 @@ DocumentObject* Document::_copyObject(DocumentObject* obj, std::map copy_map; - DocumentObject* copy = _copyObject(obj, copy_map, recursive); + DocumentObject* copy = _copyObject(obj, copy_map, recursive, keepdigitsatend); return copy; } @@ -1663,6 +1693,20 @@ std::vector Document::getObjectsOfType(const Base::Type& typeId return Objects; } +std::vector Document::findObjects(const Base::Type& typeId, const char* objname) const +{ + boost::regex rx(objname); + boost::cmatch what; + std::vector Objects; + for (std::vector::const_iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(typeId)) { + if (boost::regex_match((*it)->getNameInDocument(), what, rx)) + Objects.push_back(*it); + } + } + return Objects; +} + int Document::countObjectsOfType(const Base::Type& typeId) const { int ct=0; diff --git a/src/App/Document.h b/src/App/Document.h index dcf56d670d..38b247a20e 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -140,7 +140,7 @@ public: * are copied as well. By default \a recursive is false. * Returns the copy of the object or 0 if the creation failed. */ - DocumentObject* copyObject(DocumentObject* obj, bool recursive=false); + DocumentObject* copyObject(DocumentObject* obj, bool recursive=false, bool keepdigitsatend=false); /** Move an object from another document to this document * If \a recursive is true then all objects this object depends on * are moved as well. By default \a recursive is false. @@ -161,6 +161,7 @@ public: /// Returns a list of all Objects std::vector getObjects() const; std::vector getObjectsOfType(const Base::Type& typeId) const; + std::vector findObjects(const Base::Type& typeId, const char* objname) const; /// Returns an array with the correct types already. template inline std::vector getObjectsOfType() const; int countObjectsOfType(const Base::Type& typeId) const; @@ -260,7 +261,7 @@ protected: void _remObject(DocumentObject* pcObject); void _addObject(DocumentObject* pcObject, const char* pObjectName); DocumentObject* _copyObject(DocumentObject* obj, std::map&, bool recursive=false); + DocumentObject*>&, bool recursive=false, bool keepdigitsatend=false); /// checks if a valid transaction is open void _checkTransaction(void); void breakDependency(DocumentObject* pcObject, bool clear); diff --git a/src/App/DocumentObjectGroup.cpp b/src/App/DocumentObjectGroup.cpp index ceb0fca726..1c16e0e513 100644 --- a/src/App/DocumentObjectGroup.cpp +++ b/src/App/DocumentObjectGroup.cpp @@ -37,7 +37,7 @@ PROPERTY_SOURCE(App::DocumentObjectGroup, App::DocumentObject) DocumentObjectGroup::DocumentObjectGroup() { - ADD_PROPERTY_TYPE(Group,(0),"Base",(App::PropertyType)(Prop_ReadOnly|Prop_Output),"List of referenced objects"); + ADD_PROPERTY_TYPE(Group,(0),"Base",(App::PropertyType)(Prop_Output),"List of referenced objects"); } DocumentObjectGroup::~DocumentObjectGroup() @@ -179,13 +179,13 @@ PyObject *DocumentObjectGroup::getPyObject() return Py::new_reference_to(PythonObject); } -// Python Sketcher feature --------------------------------------------------------- +// Python feature --------------------------------------------------------- namespace App { /// @cond DOXERR PROPERTY_SOURCE_TEMPLATE(App::DocumentObjectGroupPython, App::DocumentObjectGroup) template<> const char* App::DocumentObjectGroupPython::getViewProviderName(void) const { - return "Gui::ViewProviderDocumentObjectGroup"; + return "Gui::ViewProviderDocumentObjectGroupPython"; } /// @endcond diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index 3b7fdd289d..64b04d8b99 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -163,12 +163,12 @@ PyObject* DocumentPy::removeObject(PyObject *args) PyObject* DocumentPy::copyObject(PyObject *args) { - PyObject *obj, *rec=0; - if (!PyArg_ParseTuple(args, "O!|O!",&(DocumentObjectPy::Type),&obj,&PyBool_Type,&rec)) + PyObject *obj, *rec=0, *keep=0; + if (!PyArg_ParseTuple(args, "O!|O!O!",&(DocumentObjectPy::Type),&obj,&PyBool_Type,&rec,&PyBool_Type,&keep)) return NULL; // NULL triggers exception DocumentObjectPy* docObj = static_cast(obj); - DocumentObject* copy = getDocumentPtr()->copyObject(docObj->getDocumentObjectPtr(), rec==Py_True); + DocumentObject* copy = getDocumentPtr()->copyObject(docObj->getDocumentObjectPtr(), rec==Py_True, keep==Py_True); if (copy) { return copy->getPyObject(); } @@ -290,42 +290,36 @@ PyObject* DocumentPy::findObjects(PyObject *args) char *sType="App::DocumentObject", *sName=0; if (!PyArg_ParseTuple(args, "|ss",&sType, &sName)) // convert args: Python->C return NULL; // NULL triggers exception - - Base::Type type = Base::Type::fromName(sType); - if (type == Base::Type::badType()) { - PyErr_Format(PyExc_Exception, "'%s' is not a valid type", sType); - return NULL; - } - - if (!type.isDerivedFrom(App::DocumentObject::getClassTypeId())) { - PyErr_Format(PyExc_Exception, "Type '%s' does not inherit from 'App::DocumentObject'", sType); - return NULL; - } - - std::vector res; - std::vector objs = getDocumentPtr()->getObjectsOfType(type); - - if (sName) { - try { - boost::regex rx(sName); - boost::cmatch what; - for (std::vector::const_iterator It = objs.begin();It != objs.end();++It) { - if (boost::regex_match((*It)->getNameInDocument(), what, rx)) - res.push_back(*It); - } - } - catch (const boost::regex_error& e) { - PyErr_SetString(PyExc_RuntimeError, e.what()); - return 0; - } - } - else { - res = objs; - } - - Py_ssize_t index=0; - PyObject* list = PyList_New((Py_ssize_t)res.size()); - for (std::vector::const_iterator It = res.begin();It != res.end();++It, index++) + + Base::Type type = Base::Type::fromName(sType); + if (type == Base::Type::badType()) { + PyErr_Format(PyExc_Exception, "'%s' is not a valid type", sType); + return NULL; + } + + if (!type.isDerivedFrom(App::DocumentObject::getClassTypeId())) { + PyErr_Format(PyExc_Exception, "Type '%s' does not inherit from 'App::DocumentObject'", sType); + return NULL; + } + + std::vector res; + + if (sName) { + try { + res = getDocumentPtr()->findObjects(type, sName); + } + catch (const boost::regex_error& e) { + PyErr_SetString(PyExc_RuntimeError, e.what()); + return 0; + } + } + else { + res = getDocumentPtr()->getObjectsOfType(type); + } + + Py_ssize_t index=0; + PyObject* list = PyList_New((Py_ssize_t)res.size()); + for (std::vector::const_iterator It = res.begin();It != res.end();++It, index++) PyList_SetItem(list, index, (*It)->getPyObject()); return list; } diff --git a/src/App/PropertyFile.cpp b/src/App/PropertyFile.cpp index 70b0f7edac..52278ea991 100644 --- a/src/App/PropertyFile.cpp +++ b/src/App/PropertyFile.cpp @@ -257,13 +257,18 @@ void PropertyFileIncluded::setPyObject(PyObject *value) void PropertyFileIncluded::Save (Base::Writer &writer) const { if (writer.isForceXML()) { - writer.Stream() << writer.ind() << "" << endl; - - // write the file in the XML stream - if (!_cValue.empty()) + if (!_cValue.empty()) { + Base::FileInfo file(_cValue.c_str()); + writer.Stream() << writer.ind() << "" << std::endl; + // write the file in the XML stream + writer.incInd(); writer.insertBinFile(_cValue.c_str()); - - writer.Stream() << writer.ind() <<"" << endl ; + writer.decInd(); + writer.Stream() << writer.ind() <<"" << endl; + } + else + writer.Stream() << writer.ind() << "" << std::endl; } else { // instead initiate an extra file @@ -280,23 +285,36 @@ void PropertyFileIncluded::Save (Base::Writer &writer) const void PropertyFileIncluded::Restore(Base::XMLReader &reader) { reader.readElement("FileIncluded"); - string file (reader.getAttribute("file") ); - - if (!file.empty()) { - // initate a file read - reader.addFile(file.c_str(),this); - - // is in the document transient path - aboutToSetValue(); - _cValue = getDocTransientPath() + "/" + file; - _BaseFileName = file; - hasSetValue(); + if (reader.hasAttribute("file")) { + string file (reader.getAttribute("file") ); + if (!file.empty()) { + // initate a file read + reader.addFile(file.c_str(),this); + // is in the document transient path + aboutToSetValue(); + _cValue = getDocTransientPath() + "/" + file; + _BaseFileName = file; + hasSetValue(); + } + } + // section is XML stream + else if (reader.hasAttribute("data")) { + string file (reader.getAttribute("data") ); + if (!file.empty()) { + // is in the document transient path + aboutToSetValue(); + _cValue = getDocTransientPath() + "/" + file; + reader.readBinFile(_cValue.c_str()); + reader.readEndElement("FileIncluded"); + _BaseFileName = file; + hasSetValue(); + } } } void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const { - std::ifstream from(_cValue.c_str()); + Base::ifstream from(Base::FileInfo(_cValue.c_str())); if (!from) throw Base::Exception("PropertyFileIncluded::SaveDocFile() " "File in document transient dir deleted"); @@ -311,7 +329,7 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader) { - std::ofstream to(_cValue.c_str()); + Base::ofstream to(Base::FileInfo(_cValue.c_str())); if (!to) throw Base::Exception("PropertyFileIncluded::RestoreDocFile() " "File in document transient dir deleted"); @@ -343,7 +361,7 @@ Property *PropertyFileIncluded::Copy(void) const bool done = file.renameFile(NewName.filePath().c_str()); assert(done); // remember the new name for the Undo - Base::Console().Log("Copy this=%p Befor=%s After=%s\n",p,p->_cValue.c_str(),NewName.filePath().c_str()); + Base::Console().Log("Copy this=%p Before=%s After=%s\n",p,p->_cValue.c_str(),NewName.filePath().c_str()); p->_cValue = NewName.filePath().c_str(); } diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index 6cc1058083..9ffb1d0336 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -130,12 +130,18 @@ void PropertyLink::Restore(Base::XMLReader &reader) assert(getContainer()->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId()) ); if (name != "") { - DocumentObject *pcObject = static_cast(getContainer())-> - getDocument()->getObject(name.c_str()); - if (!pcObject) + DocumentObject* parent = static_cast(getContainer()); + DocumentObject* object = parent->getDocument()->getObject(name.c_str()); + if (!object) { Base::Console().Warning("Lost link to '%s' while loading, maybe " "an object was not loaded correctly\n",name.c_str()); - setValue(pcObject); + } + else if (parent == object) { + Base::Console().Warning("Object '%s' links to itself, nullify it\n",name.c_str()); + object = 0; + } + + setValue(object); } else { setValue(0); diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h index bff973cb26..fc29893794 100644 --- a/src/App/PropertyStandard.h +++ b/src/App/PropertyStandard.h @@ -394,9 +394,6 @@ protected: const Constraints* _ConstStruct; }; - - - class AppExport PropertyFloatList: public PropertyLists { TYPESYSTEM_HEADER(); @@ -470,10 +467,11 @@ public: */ virtual ~PropertyString(); - void setValue(const char* sString); void setValue(const std::string &sString); const char* getValue(void) const; + const std::string& getStrValue(void) const + { return _cValue; } bool isEmpty(void){return _cValue.empty();} virtual const char* getEditorName(void) const { return "Gui::PropertyEditor::PropertyStringItem"; } diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index 21f91d3ca9..3cab433544 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -68,7 +68,7 @@ if(SWIG_FOUND) add_definitions(-DHAVE_SWIG=1) endif(SWIG_FOUND) -if (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++ AND NOT FREECAD_BUILD_DEBIAN) +if (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++ AND NOT FREECAD_USE_EXTERNAL_ZIPIOS) SET(zipios_SRCS ../zipios++/backbuffer.h ../zipios++/basicentry.cpp @@ -122,12 +122,7 @@ SET(zipios_SRCS ../zipios++/zipoutputstream.h ) SOURCE_GROUP("zipios" FILES ${zipios_SRCS}) -else (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++ AND NOT FREECAD_BUILD_DEBIAN) - set(FreeCADBase_LIBS - ${FreeCADBase_LIBS} - -lzipios - ) -endif (EXISTS ${CMAKE_SOURCE_DIR}/src/zipios++ AND NOT FREECAD_BUILD_DEBIAN) +endif () SET(pycxx_SRCS ../CXX/Config.hxx @@ -281,7 +276,6 @@ SET(FreeCADBase_HPP_SRCS ) SET(FreeCADBase_SRCS - ${zipios_SRCS} ${pycxx_SRCS} ${FreeCADBase_CPP_SRCS} ${FreeCADBase_HPP_SRCS} @@ -293,6 +287,27 @@ SET(FreeCADBase_SRCS PreCompiled.h ) +# Use external zipios++ if specified. +if(FREECAD_USE_EXTERNAL_ZIPIOS) + find_library(ZIPIOS_LIBRARY zipios) + find_path(ZIPIOS_INCLUDES zipios++/zipios-config.h) + if(ZIPIOS_LIBRARY) + message(STATUS "Found zipios++: ${ZIPIOS}") + endif() + if(ZIPIOS_INCLUDES) + message(STATUS "Found zipios++ headers.") + endif() + if(ZIPIOS_LIBRARY AND ZIPIOS_INCLUDES) + list(APPEND FreeCADBase_LIBS ${ZIPIOS_LIBRARY}) + include_directories(${ZIPIOS_INCLUDES}) + else() + message(FATAL_ERROR "Using external zipios++ was specified but was not found.") + endif() +else(FREECAD_USE_EXTERNAL_ZIPIOS) + list(APPEND FreeCADBase_SRCS ${zipios_SRCS}) +endif(FREECAD_USE_EXTERNAL_ZIPIOS) + + if(MSVC) add_definitions(-D_PreComp_) ADD_MSVC_PRECOMPILED_HEADER("PreCompiled.h" "PreCompiled.cpp" FreeCADBase_CPP_SRCS) diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index 6e31a38103..0a8c4b9e8b 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -598,21 +598,21 @@ bool InterpreterSingleton::convertSWIGPointerObj(const char* Module, const char* int result = 0; PyGILStateLocker locker; int version = getSWIGVersionFromModule(Module); - switch (version&0xff) + switch (version) { - case 25: + case 66329: result = Swig_1_3_25::convertSWIGPointerObj_T(TypeName, obj, ptr, flags); break; - case 33: + case 66337: result = Swig_1_3_33::convertSWIGPointerObj_T(TypeName, obj, ptr, flags); break; - case 36: + case 66340: result = Swig_1_3_36::convertSWIGPointerObj_T(TypeName, obj, ptr, flags); break; - case 38: + case 66342: result = Swig_1_3_38::convertSWIGPointerObj_T(TypeName, obj, ptr, flags); break; - case 40: + case 66344: result = Swig_1_3_40::convertSWIGPointerObj_T(TypeName, obj, ptr, flags); break; default: diff --git a/src/Base/MatrixPy.xml b/src/Base/MatrixPy.xml index c91da2aa2d..23b5b15e4c 100644 --- a/src/Base/MatrixPy.xml +++ b/src/Base/MatrixPy.xml @@ -110,9 +110,10 @@ Compute the determinant of the matrix -isOrthogonal() -> Float +isOrthogonal([Float]) -> Float Checks if the matrix is orthogonal, i.e. M * M^T = k*I and returns the multiple of the identity matrix. If it's not orthogonal 0 is returned. +As argument you can set a tolerance which by default is 1.0e-6. diff --git a/src/Base/MatrixPyImp.cpp b/src/Base/MatrixPyImp.cpp index 9186f15167..a5408bb181 100644 --- a/src/Base/MatrixPyImp.cpp +++ b/src/Base/MatrixPyImp.cpp @@ -24,6 +24,7 @@ #include "PreCompiled.h" #include +#include #include "Base/Matrix.h" // inclusion of the generated files (generated out of MatrixPy.xml) @@ -158,8 +159,9 @@ PyObject* MatrixPy::richCompare(PyObject *v, PyObject *w, int op) } } else { - PyErr_SetString(PyExc_TypeError, "Cannot compare Matrix with other type"); - return 0; + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } } @@ -415,32 +417,34 @@ PyObject* MatrixPy::submatrix(PyObject * args) PyObject* MatrixPy::isOrthogonal(PyObject * args) { - if (!PyArg_ParseTuple(args, "")) + double eps=1.0e-06; + if (!PyArg_ParseTuple(args, "|d",&eps)) return 0; const Base::Matrix4D& mat = *getMatrixPtr(); Base::Matrix4D trp = mat; trp.transpose(); trp = trp * mat; + bool ok = true; double mult = trp[0][0]; - for (int i=0; (i<4) && (mult!=0.0); i++) { - for (int j=0; (j<4) && (mult!=0.0); j++) { + for (int i=0; i<4 && ok; i++) { + for (int j=0; j<4 && ok; j++) { if (i != j) { - if (trp[i][j] != 0.0) { - mult = 0.0; + if (fabs(trp[i][j]) > eps) { + ok = false; break; } } - else { // the diagonal - if (trp[i][j] != mult) { - mult = 0.0; + else { // the main diagonal + if (fabs(trp[i][j]-mult) > eps) { + ok = false; break; } } } } - return Py::new_reference_to(Py::Float(mult)); + return Py::new_reference_to(Py::Float(ok ? mult : 0.0)); } PyObject* MatrixPy::transposed(PyObject * args) diff --git a/src/Base/PlacementPy.xml b/src/Base/PlacementPy.xml index 3ccb012a32..9a78c23671 100644 --- a/src/Base/PlacementPy.xml +++ b/src/Base/PlacementPy.xml @@ -75,6 +75,14 @@ Placement(Base, Axis, Angle) -- define position and rotation + + + + isNull() -> Bool + returns True if the placement has no displacement and no rotation + + + Vector to the Base Position of the Placement diff --git a/src/Base/PlacementPyImp.cpp b/src/Base/PlacementPyImp.cpp index 7e1dece97c..6a3f7956e9 100644 --- a/src/Base/PlacementPyImp.cpp +++ b/src/Base/PlacementPyImp.cpp @@ -83,9 +83,9 @@ int PlacementPy::PyInit(PyObject* args, PyObject* /*kwd*/) PyObject* d; double angle; if (PyArg_ParseTuple(args, "O!O!d", &(Base::VectorPy::Type), &o, - &(Base::VectorPy::Type), &d, &angle)) { - // NOTE: The first parameter defines the translation, the second the rotation axis - // and the last parameter defines the rotation angle in degree. + &(Base::VectorPy::Type), &d, &angle)) { + // NOTE: The first parameter defines the translation, the second the rotation axis + // and the last parameter defines the rotation angle in degree. Base::Rotation rot(static_cast(d)->value(), angle/180.0*D_PI); *getPlacementPtr() = Base::Placement(static_cast(o)->value(),rot); return 0; @@ -145,13 +145,13 @@ PyObject* PlacementPy::multVec(PyObject * args) getPlacementPtr()->multVec(pnt, pnt); return new VectorPy(new Vector3d(pnt)); } - -PyObject* PlacementPy::copy(PyObject * args) -{ - if (!PyArg_ParseTuple(args, "")) - return NULL; - return new PlacementPy(new Placement(*getPlacementPtr())); -} + +PyObject* PlacementPy::copy(PyObject * args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + return new PlacementPy(new Placement(*getPlacementPtr())); +} PyObject* PlacementPy::toMatrix(PyObject * args) { @@ -169,6 +169,19 @@ PyObject* PlacementPy::inverse(PyObject * args) return new PlacementPy(new Placement(p)); } +PyObject* PlacementPy::isNull(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + Base::Vector3d pos = getPlacementPtr()->getPosition(); + Base::Rotation rot = getPlacementPtr()->getRotation(); + Base::Vector3d nullvec(0,0,0); + Base::Rotation nullrot(0,0,0,1); + Base::Rotation nullrotinv(0,0,0,-1); + bool null = (pos == nullvec) & ((rot == nullrot) | (rot == nullrotinv)); + return Py_BuildValue("O", (null ? Py_True : Py_False)); +} + Py::Object PlacementPy::getBase(void) const { return Py::Vector(getPlacementPtr()->getPosition()); diff --git a/src/Base/PyTools.c b/src/Base/PyTools.c index 2346f80cc3..d204ae72d2 100644 --- a/src/Base/PyTools.c +++ b/src/Base/PyTools.c @@ -377,8 +377,10 @@ const char *PP_Init(const char *modname) { //#ifdef FC_OS_LINUX /* cannot convert `const char *' to `char *' in assignment */ if (modname!=NULL) return modname; { /* we assume here that the caller frees allocated memory */ - char* __main__=(char *)malloc(sizeof("__main__")); - return __main__="__main__"; + // #0000716: strange assignment and a memory leak + return "__main__"; + //char* __main__=(char *)malloc(sizeof("__main__")); + //return __main__="__main__"; } //#else // return modname == NULL ? "__main__" : modname; /* default to '__main__' */ diff --git a/src/Base/Reader.cpp b/src/Base/Reader.cpp index db355f723f..6791b99f62 100644 --- a/src/Base/Reader.cpp +++ b/src/Base/Reader.cpp @@ -34,6 +34,7 @@ /// Here the FreeCAD includes sorted by Base,App,Gui...... #include "Reader.h" +#include "Base64.h" #include "Exception.h" #include "Persistence.h" #include "InputSource.h" @@ -79,6 +80,7 @@ Base::XMLReader::XMLReader(const char* FileName, std::istream& str) //parser->setFeature(XMLUni::fgXercesDynamic, true); parser->setContentHandler(this); + parser->setLexicalHandler(this); parser->setErrorHandler(this); try { @@ -127,7 +129,7 @@ long Base::XMLReader::getAttributeAsInteger(const char* AttrName) const if (pos != AttrMap.end()) return atol(pos->second.c_str()); else - // wrong name, use hasAttribute if not shure! + // wrong name, use hasAttribute if not sure! assert(0); return 0; @@ -140,7 +142,7 @@ unsigned long Base::XMLReader::getAttributeAsUnsigned(const char* AttrName) cons if (pos != AttrMap.end()) return strtoul(pos->second.c_str(),0,10); else - // wrong name, use hasAttribute if not shure! + // wrong name, use hasAttribute if not sure! assert(0); return 0; @@ -153,7 +155,7 @@ double Base::XMLReader::getAttributeAsFloat (const char* AttrName) const if (pos != AttrMap.end()) return atof(pos->second.c_str()); else - // wrong name, use hasAttribute if not shure! + // wrong name, use hasAttribute if not sure! assert(0); return 0.0; @@ -166,7 +168,7 @@ const char* Base::XMLReader::getAttribute (const char* AttrName) const if (pos != AttrMap.end()) return pos->second.c_str(); else - // wrong name, use hasAttribute if not shure! + // wrong name, use hasAttribute if not sure! assert(0); return ""; @@ -255,6 +257,22 @@ void Base::XMLReader::readCharacters(void) { } +void Base::XMLReader::readBinFile(const char* filename) +{ + Base::FileInfo fi(filename); + Base::ofstream to(fi, std::ios::out | std::ios::binary); + if (!to) + throw Base::Exception("XMLReader::readBinFile() Could not open file!"); + + bool ok; + do { + ok = read(); if (!ok) break; + } while (ReadType != EndCDATA); + + to << Base::base64_decode(Characters); + to.close(); +} + void Base::XMLReader::readFiles(zipios::ZipInputStream &zipstream) const { // It's possible that not all objects inside the document could be created, e.g. if a module @@ -370,15 +388,32 @@ void Base::XMLReader::endElement (const XMLCh* const /*uri*/, const XMLCh *cons ReadType = EndElement; } +void Base::XMLReader::startCDATA () +{ + ReadType = StartCDATA; +} +void Base::XMLReader::endCDATA () +{ + ReadType = EndCDATA; +} + +#if (XERCES_VERSION_MAJOR == 2) void Base::XMLReader::characters(const XMLCh* const chars, const unsigned int length) +#else +void Base::XMLReader::characters(const XMLCh* const chars, const XMLSize_t length) +#endif { Characters = StrX(chars).c_str(); ReadType = Chars; CharacterCount += length; } +#if (XERCES_VERSION_MAJOR == 2) void Base::XMLReader::ignorableWhitespace( const XMLCh* const /*chars*/, const unsigned int /*length*/) +#else +void Base::XMLReader::ignorableWhitespace( const XMLCh* const /*chars*/, const XMLSize_t /*length*/) +#endif { //fSpaceCount += length; } diff --git a/src/Base/Reader.h b/src/Base/Reader.h index 3ced7241b5..7e55575d42 100644 --- a/src/Base/Reader.h +++ b/src/Base/Reader.h @@ -131,6 +131,8 @@ public: void readEndElement(const char* ElementName=0); /// read until characters are found void readCharacters(void); + /// read binary file + void readBinFile(const char*); //@} /** @name Attribute handling */ @@ -171,8 +173,15 @@ protected: // ----------------------------------------------------------------------- virtual void startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const XERCES_CPP_NAMESPACE_QUALIFIER Attributes& attrs); virtual void endElement (const XMLCh* const uri, const XMLCh *const localname, const XMLCh *const qname); - virtual void characters (const XMLCh* const chars, const unsigned int length); + virtual void startCDATA (); + virtual void endCDATA (); +#if (XERCES_VERSION_MAJOR == 2) + virtual void characters (const XMLCh* const chars, const unsigned int length); virtual void ignorableWhitespace(const XMLCh* const chars, const unsigned int length); +#else + virtual void characters (const XMLCh* const chars, const XMLSize_t length); + virtual void ignorableWhitespace(const XMLCh* const chars, const XMLSize_t length); +#endif virtual void resetDocument(); @@ -198,7 +207,9 @@ protected: Chars, StartElement, StartEndElement, - EndElement + EndElement, + StartCDATA, + EndCDATA } ReadType; diff --git a/src/Base/RotationPy.xml b/src/Base/RotationPy.xml index 02dc34ee84..111cfb74c7 100644 --- a/src/Base/RotationPy.xml +++ b/src/Base/RotationPy.xml @@ -48,6 +48,14 @@ + + + + isNull() -> Bool + returns True if the rotation equals the unity matrix + + + The rotation elements (as quaternion) diff --git a/src/Base/RotationPyImp.cpp b/src/Base/RotationPyImp.cpp index 7abede54c7..159952c7e0 100644 --- a/src/Base/RotationPyImp.cpp +++ b/src/Base/RotationPyImp.cpp @@ -144,6 +144,17 @@ PyObject* RotationPy::toEuler(PyObject * args) return Py::new_reference_to(tuple); } +PyObject* RotationPy::isNull(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + Base::Rotation rot = * getRotationPtr(); + Base::Rotation nullrot(0,0,0,1); + Base::Rotation nullrotinv(0,0,0,-1); + bool null = (rot == nullrot) | (rot == nullrotinv); + return Py_BuildValue("O", (null ? Py_True : Py_False)); +} + Py::Tuple RotationPy::getQ(void) const { double q0, q1, q2, q3; diff --git a/src/Base/UnitsApi.cpp b/src/Base/UnitsApi.cpp index ceb7734737..91b71eba87 100644 --- a/src/Base/UnitsApi.cpp +++ b/src/Base/UnitsApi.cpp @@ -85,6 +85,7 @@ UnitsSchema *UnitsApi::UserPrefSystem = new UnitsSchemaInternal(); double UnitsApi::UserPrefFactor [50]; QString UnitsApi::UserPrefUnit [50]; +int UnitsApi::UserPrefDecimals = 2; UnitsApi::UnitsApi(const char* filter) { @@ -196,6 +197,16 @@ const double UnitsApi::getPrefFactorOf(QuantityType t) return UserPrefFactor[t]; } +void UnitsApi::setDecimals(int prec) +{ + UserPrefDecimals = prec; +} + +int UnitsApi::getDecimals() +{ + return UserPrefDecimals; +} + void UnitsApi::setDefaults(void) { setPrefOf( Length ,"mm" ); diff --git a/src/Base/UnitsApi.h b/src/Base/UnitsApi.h index e3beae5d5f..1b2fdcd64f 100644 --- a/src/Base/UnitsApi.h +++ b/src/Base/UnitsApi.h @@ -101,6 +101,10 @@ public: static const QString getQuantityName(QuantityType t); /// get the translation factor for the default unit of a quantity static const double getPrefFactorOf(QuantityType t); + // set the number of decimals + static void setDecimals(int); + // fet the number of decimals + static int getDecimals(); /// set the application defaults static void setDefaults(void); //@} @@ -119,6 +123,8 @@ protected: static double UserPrefFactor [50] ; /// name of the unit the user wants to use as quantities static QString UserPrefUnit [50] ; + /// number of decimals for floats + static int UserPrefDecimals; // do the real work static double parse(const char*,bool &UsedUnit); diff --git a/src/Base/VectorPy.xml b/src/Base/VectorPy.xml index 4171ac2a14..6286e4b27b 100644 --- a/src/Base/VectorPy.xml +++ b/src/Base/VectorPy.xml @@ -20,90 +20,127 @@ - add(Vector) - return the sum of the two vectors + add(Vector) + returns the sum of this and another vector + - sub(Vector) - return the difference of the two vectors + sub(Vector) + returns the difference of this and another vector + - scale(Float,Float,Float) - scale (multiplies) this vector by a factor + scale(Float,Float,Float) + scales (multiplies) this vector by a factor + - multiply(Float) - multiplies (scales) this vector by a single factor + multiply(Float) + multiplies (scales) this vector by a single factor + - dot(Vector) - return the dot product of the two vectors + dot(Vector) + returns the dot product of the this vector with another one + - cross(Vector) - return the cross product of the two vectors + cross(Vector) + returns the cross product between this and another vector + - getAngle(Vector) - return the angle in radians between the two vectors + getAngle(Vector) + returns the angle in radians between this and another vector + - Normalize the vector to the length of 1.0 + normalize() + normalizes the vector to the length of 1.0 + - Deliver the projection point to a given line + projectToLine(Vector,Vector) + projects the vector on a line defined by a base point and a direction + - Deliver the projection point to a given plane + projectToPlane(Vector,Vector) + projects the vector on a plane defined by a base point and a normal + - Deliver the distance of the point to a given line + distanceToLine(Vector,Vector) + returns the distance between this vector and a line defined by + a base point and a direction + - Deliver the distance of the point to a given line segment + distanceToLineSegment(Vector,Vector) + returns the distance between this vector and a line segment defined by + a base point and a direction + - Deliver the distance of the point to a given plane + distanceToPlane(Vector,Vector) + returns the distance between this vector and a plane defined by + a base point and a normal + - To read or modifiy the length of the vector + Length([Float]) -> Float + gets or sets the length of this vector + - The X component of the vector + x([Float]) -> Float + gets or sets the X component of this vector + - The Y component of the vector + y([Float]) -> Float + gets or sets the Y component of this vector + - The Z component of the vector + z([Float]) -> Float + gets or sets the Z component of this vector + @@ -128,4 +165,4 @@ { return *(getVectorPtr()); } - + diff --git a/src/Base/VectorPyImp.cpp b/src/Base/VectorPyImp.cpp index 3476ac06a5..da2bb58311 100644 --- a/src/Base/VectorPyImp.cpp +++ b/src/Base/VectorPyImp.cpp @@ -237,8 +237,9 @@ PyObject* VectorPy::richCompare(PyObject *v, PyObject *w, int op) } } else { - PyErr_SetString(PyExc_TypeError, "Cannot compare Matrix with other type"); - return 0; + // This always returns False + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; } } diff --git a/src/Base/Writer.cpp b/src/Base/Writer.cpp index 74742f2a6f..621893a8a3 100644 --- a/src/Base/Writer.cpp +++ b/src/Base/Writer.cpp @@ -32,6 +32,7 @@ #include "Exception.h" #include "Base64.h" #include "FileInfo.h" +#include "Stream.h" #include "Tools.h" #include @@ -59,32 +60,31 @@ Writer::~Writer() void Writer::insertAsciiFile(const char* FileName) { - std::ifstream from(FileName); - if (!from) throw Base::Exception("Writer::insertAsciiFile() Could not open file!"); + Base::FileInfo fi(FileName); + Base::ifstream from(fi); + if (!from) + throw Base::Exception("Writer::insertAsciiFile() Could not open file!"); - Stream() << "" << endl; + while (from.get(ch)) + Stream().put(ch); + Stream() << "]]>" << endl; } void Writer::insertBinFile(const char* FileName) { - std::ifstream from(FileName); - if (!from) throw Base::Exception("Writer::insertAsciiFile() Could not open file!"); - - Stream() << " bytes(fileSize); + from.read((char*)&bytes[0], fileSize); + Stream() << Base::base64_encode(&bytes[0], fileSize); Stream() << "]]>" << endl; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 88a57d35b4..6d440389ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,6 +12,10 @@ if(FREECAD_BUILD_GUI) configure_file(Doc/freecad.qch ${CMAKE_BINARY_DIR}/doc/freecad.qch COPYONLY) endif(FREECAD_BUILD_GUI) +if(FREECAD_BUILD_TEMPLATE) + add_subdirectory(Tools/_TEMPLATE_) +endif(FREECAD_BUILD_TEMPLATE) + if(FREECAD_MAINTAINERS_BUILD) add_subdirectory(Doc) endif(FREECAD_MAINTAINERS_BUILD) diff --git a/src/Doc/sphinx/Arch.rst b/src/Doc/sphinx/Arch.rst index c126eb3271..e89fca847b 100644 --- a/src/Doc/sphinx/Arch.rst +++ b/src/Doc/sphinx/Arch.rst @@ -1,7 +1,7 @@ The Arch module =============== -The Arch module is a metamodule that imports useful methods from several of the Arch submodules. +The Arch module is a metamodule that imports useful methods from several of the Arch submodules. You can invoke the following methods either from their specific submodule (ArchWall.areSameWallTypes()) or from the Arch module itself (Arch.areSameWallTypes()). .. toctree:: :maxdepth: 4 @@ -9,29 +9,32 @@ The Arch module is a metamodule that imports useful methods from several of the .. automodule:: Arch :members: -.. automodule:: Wall +.. automodule:: ArchWall :members: -.. automodule:: Cell +.. automodule:: ArchCell :members: -.. automodule:: Floor +.. automodule:: ArchFloor :members: -.. automodule:: Site +.. automodule:: ArchSite :members: -.. automodule:: Structure +.. automodule:: ArchStructure :members: -.. automodule:: Window +.. automodule:: ArchWindow :members: -.. automodule:: SectionPlane +.. automodule:: ArchSectionPlane :members: -.. automodule:: Building +.. automodule:: ArchBuilding :members: -.. automodule:: Commands +.. automodule:: ArchCommands + :members: + +.. automodule:: ArchAxis :members: diff --git a/src/Doc/sphinx/Draft.rst b/src/Doc/sphinx/Draft.rst index 542acff0bc..4479028b14 100644 --- a/src/Doc/sphinx/Draft.rst +++ b/src/Doc/sphinx/Draft.rst @@ -1,19 +1,26 @@ The Draft module ================ -The Draft module offer several convenient functions to work with simple 2D and 3D objects. -These functions can be used in scripts and macros or from the python interpreter, once the Draft module has been imported. - -Example:: - - import FreeCAD - from Draft import * - myrect = makeRectangle(4,3) - mydistance = FreeCAD.Vector(2,2,0) - move(myrect,mydistance) +The Draft module offer several convenient functions to work with simple objects. .. toctree:: :maxdepth: 4 .. automodule:: Draft :members: + +.. automodule:: DraftSnap + :members: + +The Draft module also contains two submodules, widely used throughout the Draft and Arch modules: DraftVecUtils, which contains useful methods for dealing with vectors, and DraftGeomUtils, which offers many tools for working with OpenCascade geometry. + +.. automodule:: DraftVecUtils + :members: + +.. automodule:: DraftGeomUtils + :members: + +The Draft module also features a module that contains trackers, special objects made to display 3D temporary geometry in the 3D scene, that have no real existence in the FreeCAD document. + +.. automodule:: DraftTrackers + :members: diff --git a/src/Doc/sphinx/FreeCAD.rst b/src/Doc/sphinx/FreeCAD.rst index cb37b3c4d2..eff8e09cfe 100644 --- a/src/Doc/sphinx/FreeCAD.rst +++ b/src/Doc/sphinx/FreeCAD.rst @@ -6,7 +6,6 @@ The FreeCAD module .. automodule:: FreeCAD :members: - :show-inheritance: .. autoclass:: Vector :members: @@ -16,3 +15,6 @@ The FreeCAD module .. autoclass:: Placement :members: + + .. autoclass:: Console + :members: diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index 7086c82c76..5e39c8a518 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -28,6 +28,7 @@ # include # include # include +# include # include # include # include @@ -345,6 +346,18 @@ WorkbenchComboBox::~WorkbenchComboBox() { } +void WorkbenchComboBox::showPopup() +{ + int rows = count(); + if (rows > 0) { + int height = view()->sizeHintForRow(0); + int maxHeight = QApplication::desktop()->height(); + view()->setMinimumHeight(qMin(height * rows, maxHeight/2)); + } + + QComboBox::showPopup(); +} + void WorkbenchComboBox::actionEvent ( QActionEvent* e ) { QAction *action = e->action(); diff --git a/src/Gui/Action.h b/src/Gui/Action.h index 4a0dc7a6eb..0b33f57ece 100644 --- a/src/Gui/Action.h +++ b/src/Gui/Action.h @@ -124,6 +124,7 @@ class GuiExport WorkbenchComboBox : public QComboBox public: WorkbenchComboBox(WorkbenchGroup* wb, QWidget* parent=0); virtual ~WorkbenchComboBox(); + void showPopup(); public Q_SLOTS: void onActivated(int); diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 8c3ff25c67..ad56639024 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ #include "DlgOnlineHelpImp.h" #include "SpaceballEvent.h" +#include "SplitView3DInventor.h" #include "View3DInventor.h" #include "ViewProvider.h" #include "ViewProviderExtern.h" @@ -327,6 +329,10 @@ Application::Application(bool GUIenabled) Translator::instance()->activateLanguage(hPGrp->GetASCII("Language", (const char*)lang.toAscii()).c_str()); GetWidgetFactorySupplier(); + ParameterGrp::handle hUnits = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/Units"); + Base::UnitsApi::setDecimals(hUnits->GetInt("Decimals", Base::UnitsApi::getDecimals())); + // setting up Python binding Base::PyGILStateLocker lock; PyObject* module = Py_InitModule3("FreeCADGui", Application::Methods, @@ -340,6 +346,10 @@ Application::Application(bool GUIenabled) "workbenches."); Py::Module(module).setAttr(std::string("ActiveDocument"),Py::None()); + UiLoaderPy::init_type(); + Base::Interpreter().addType(UiLoaderPy::type_object(), + module,"UiLoader"); + //insert Selection module PyObject* pSelectionModule = Py_InitModule3("Selection", SelectionSingleton::Methods, "Selection module"); @@ -708,6 +718,14 @@ void Application::setActiveDocument(Gui::Document* pcDocument) { if (d->activeDocument == pcDocument) return; // nothing needs to be done + if (pcDocument) { + // This happens if a document with more than one view is about being + // closed and a second view is activated. The document is still not + // removed from the map. + App::Document* doc = pcDocument->getDocument(); + if (d->documents.find(doc) == d->documents.end()) + return; + } d->activeDocument = pcDocument; std::string name; @@ -851,8 +869,13 @@ void Application::tryClose(QCloseEvent * e) // ask all documents if closable std::map::iterator It; for (It = d->documents.begin();It!=d->documents.end();It++) { + // a document may have several views attached, so ask it directly +#if 0 MDIView* active = It->second->getActiveView(); e->setAccepted(active->canClose()); +#else + e->setAccepted(It->second->canClose()); +#endif if (!e->isAccepted()) return; } @@ -938,6 +961,13 @@ bool Application::activateWorkbench(const char* name) // import the matching module first Py::Callable activate(handler.getAttr(std::string("Initialize"))); activate.apply(args); + + // Dependent on the implementation of a workbench handler the type + // can be defined after the call of Initialize() + if (type.empty()) { + Py::String result(method.apply(args)); + type = result.as_std_string(); + } } // does the Python workbench handler have changed the workbench? @@ -1391,12 +1421,15 @@ void Application::initTypes(void) Gui::BaseView ::init(); Gui::MDIView ::init(); Gui::View3DInventor ::init(); + Gui::AbstractSplitView ::init(); + Gui::SplitView3DInventor ::init(); // View Provider Gui::ViewProvider ::init(); Gui::ViewProviderExtern ::init(); Gui::ViewProviderDocumentObject ::init(); Gui::ViewProviderFeature ::init(); Gui::ViewProviderDocumentObjectGroup ::init(); + Gui::ViewProviderDocumentObjectGroupPython ::init(); Gui::ViewProviderGeometryObject ::init(); Gui::ViewProviderInventorObject ::init(); Gui::ViewProviderVRMLObject ::init(); @@ -1602,9 +1635,15 @@ void Application::runApplication(void) logo->setFrameShape(QFrame::NoFrame); } } + bool hidden = false; + it = cfg.find("StartHidden"); + if (it != cfg.end()) { + hidden = true; + } // show splasher while initializing the GUI - mw.startSplasher(); + if (!hidden) + mw.startSplasher(); // running the GUI init script try { @@ -1638,8 +1677,10 @@ void Application::runApplication(void) app.activateWorkbench(start.c_str()); // show the main window - Base::Console().Log("Init: Showing main window\n"); - mw.loadWindowSettings(); + if (!hidden) { + Base::Console().Log("Init: Showing main window\n"); + mw.loadWindowSettings(); + } //initialize spaceball. mainApp.initSpaceball(&mw); diff --git a/src/Gui/Application.h b/src/Gui/Application.h index 74b3dbb64b..44a73d0c67 100644 --- a/src/Gui/Application.h +++ b/src/Gui/Application.h @@ -231,6 +231,8 @@ public: PYFUNCDEF_S(sActiveDocument); PYFUNCDEF_S(sGetDocument); + PYFUNCDEF_S(sDoCommand); + static PyMethodDef Methods[]; private: diff --git a/src/Gui/ApplicationPy.cpp b/src/Gui/ApplicationPy.cpp index 2703823fae..6f0bfd5ba2 100644 --- a/src/Gui/ApplicationPy.cpp +++ b/src/Gui/ApplicationPy.cpp @@ -26,6 +26,7 @@ #ifndef _PreComp_ # include # include +# include #endif @@ -36,6 +37,7 @@ #include "MainWindow.h" #include "EditorView.h" #include "PythonEditor.h" +#include "View3DInventor.h" #include "WidgetFactory.h" #include "Workbench.h" #include "WorkbenchManager.h" @@ -126,6 +128,9 @@ PyMethodDef Application::Methods[] = { {"getDocument", (PyCFunction) Application::sGetDocument, 1, "getDocument(string) -> object\n\n" "Get a document by its name"}, + {"doCommand", (PyCFunction) Application::sDoCommand, 1, + "doCommand(string) -> None\n\n" + "Prints the given string in the python console and runs it"}, {NULL, NULL} /* Sentinel */ }; @@ -357,10 +362,33 @@ PyObject* Application::sExport(PyObject * /*self*/, PyObject *args,PyObject * /* if (ext == QLatin1String("iv") || ext == QLatin1String("wrl") || ext == QLatin1String("vrml") || ext == QLatin1String("wrz") || ext == QLatin1String("svg") || ext == QLatin1String("idtf")) { - QString cmd = QString::fromLatin1( - "Gui.getDocument(\"%1\").ActiveView.dump(\"%2\")" - ).arg(QLatin1String(doc->getName())).arg(fi.absoluteFilePath()); - Base::Interpreter().runString(cmd.toUtf8()); + Gui::Document* gui_doc = Application::Instance->getDocument(doc); + std::list view3d = gui_doc->getMDIViewsOfType(View3DInventor::getClassTypeId()); + if (view3d.empty()) { + PyErr_SetString(PyExc_Exception, "Cannot export to SVG because document doesn't have a 3d view"); + return 0; + } + else { + QString cmd = QString::fromLatin1( + "Gui.getDocument(\"%1\").mdiViewsOfType('Gui::View3DInventor')[0].dump(\"%2\")" + ).arg(QLatin1String(doc->getName())).arg(fi.absoluteFilePath()); + Base::Interpreter().runString(cmd.toUtf8()); + } + } + else if (ext == QLatin1String("pdf")) { + Gui::Document* gui_doc = Application::Instance->getDocument(doc); + if (gui_doc) { + Gui::MDIView* view = gui_doc->getActiveView(); + if (view) { + View3DInventor* view3d = qobject_cast(view); + if (view3d) + view3d->viewAll(); + QPrinter printer(QPrinter::ScreenResolution); + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setOutputFileName(fileName); + view->print(&printer); + } + } } } } PY_CATCH; @@ -748,3 +776,12 @@ PyObject* Application::sRunCommand(PyObject * /*self*/, PyObject *args,PyObject return 0; } } + +PyObject* Application::sDoCommand(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) +{ + char *pstr=0; + if (!PyArg_ParseTuple(args, "s", &pstr)) // convert args: Python->C + return NULL; // NULL triggers exception + Command::doCommand(Command::Doc,pstr); + return Py_None; +} diff --git a/src/Gui/BitmapFactory.cpp b/src/Gui/BitmapFactory.cpp index 0b2699bf26..9b781a4d07 100644 --- a/src/Gui/BitmapFactory.cpp +++ b/src/Gui/BitmapFactory.cpp @@ -87,10 +87,10 @@ BitmapFactoryInst& BitmapFactoryInst::instance(void) } _pcSingleton->addPath(path); } + _pcSingleton->addPath(QString::fromAscii("%1/icons").arg(QString::fromUtf8(App::GetApplication().GetHomePath()))); + _pcSingleton->addPath(QString::fromAscii("%1/icons").arg(QString::fromUtf8(App::GetApplication().Config()["UserAppData"].c_str()))); _pcSingleton->addPath(QLatin1String(":/icons/")); _pcSingleton->addPath(QLatin1String(":/Icons/")); - _pcSingleton->addPath(QString::fromUtf8(App::GetApplication().GetHomePath())); - _pcSingleton->addPath(QString::fromUtf8(App::GetApplication().Config()["UserAppData"].c_str())); RegisterIcons(); } @@ -189,6 +189,27 @@ bool BitmapFactoryInst::findPixmapInCache(const char* name, QPixmap& px) const return false; } +bool BitmapFactoryInst::loadPixmap(const QString& filename, QPixmap& icon) const +{ + QFileInfo fi(filename); + if (fi.exists()) { + // first check if it's an SVG because Qt's qsvg4 module shouldn't be used therefore + if (fi.suffix().toLower() == QLatin1String("svg")) { + QFile svgFile(filename); + if (svgFile.open(QFile::ReadOnly | QFile::Text)) { + QByteArray content = svgFile.readAll(); + icon = pixmapFromSvg(content, QSize(64,64)); + } + } + else { + // try with Qt plugins + icon.load(filename); + } + } + + return !icon.isNull(); +} + QPixmap BitmapFactoryInst::pixmap(const char* name) const { if (!name || *name == '\0') @@ -205,33 +226,29 @@ QPixmap BitmapFactoryInst::pixmap(const char* name) const if (It != d->xpmMap.end()) icon = QPixmap(It.value()); - // If an absolute path is given + // Try whether an absolute path is given QString fn = QString::fromUtf8(name); - if (icon.isNull() && QFile(fn).exists()) - icon.load(fn); - - // first check if it's an SVG because Qt's qsvg4 module shouldn't be used therefore - if (icon.isNull()) { - icon = pixmapFromSvg(name, QSize(64,64)); - } + if (icon.isNull()) + loadPixmap(fn, icon); // try to find it in the given directories if (icon.isNull()) { bool found = false; QList formats = QImageReader::supportedImageFormats(); + formats.prepend("SVG"); // check first for SVG to use special import mechanism for (QStringList::ConstIterator pt = d->paths.begin(); pt != d->paths.end() && !found; ++pt) { QDir d(*pt); QString fileName = d.filePath(fn); - if (QFile(fileName).exists()) { - icon.load(fileName); + if (loadPixmap(fileName, icon)) { found = true; break; - } else { + } + else { + // Go through supported file formats for (QList::iterator fm = formats.begin(); fm != formats.end(); ++fm) { QString path = QString::fromAscii("%1.%2").arg(fileName). arg(QString::fromAscii((*fm).toLower().constData())); - if (QFile(path).exists()) { - icon.load(path); + if (loadPixmap(path, icon)) { found = true; break; } diff --git a/src/Gui/BitmapFactory.h b/src/Gui/BitmapFactory.h index 822156ab7b..4579c7b741 100644 --- a/src/Gui/BitmapFactory.h +++ b/src/Gui/BitmapFactory.h @@ -124,6 +124,7 @@ public: void convert(const SoSFImage& img, QImage& out) const; private: + bool loadPixmap(const QString& path, QPixmap&) const; void restoreCustomPaths(); static BitmapFactoryInst* _pcSingleton; diff --git a/src/Gui/BlenderNavigationStyle.cpp b/src/Gui/BlenderNavigationStyle.cpp index d40ab1acc7..1541800722 100644 --- a/src/Gui/BlenderNavigationStyle.cpp +++ b/src/Gui/BlenderNavigationStyle.cpp @@ -79,10 +79,10 @@ const char* BlenderNavigationStyle::mouseButtons(ViewerMode mode) SbBool BlenderNavigationStyle::processSoEvent(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 inherited::processSoEvent(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 inherited::processSoEvent(ev); } const SoType type(ev->getTypeId()); @@ -291,20 +291,9 @@ SbBool BlenderNavigationStyle::processSoEvent(const SoEvent * const ev) // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { - SoMotion3Event * const event = (SoMotion3Event *) ev; - SoCamera * const camera = viewer->getCamera(); - - SbVec3f dir = event->getTranslation(); - if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){ - static float zoomConstant(-.03f); - dir[2] = 0.0;//don't move the cam for z translation. - - SoOrthographicCamera *oCam = static_cast(camera); - oCam->scaleHeight(1.0-event->getTranslation()[2] * zoomConstant); - } - camera->orientation.getValue().multVec(dir,dir); - camera->position = camera->position.getValue() + dir; - camera->orientation = event->getRotation() * camera->orientation.getValue(); + const SoMotion3Event * const event = static_cast(ev); + if (event) + this->processMotionEvent(event); processed = TRUE; } diff --git a/src/Gui/CADNavigationStyle.cpp b/src/Gui/CADNavigationStyle.cpp index 99f0d5919a..a85124a022 100644 --- a/src/Gui/CADNavigationStyle.cpp +++ b/src/Gui/CADNavigationStyle.cpp @@ -320,20 +320,9 @@ SbBool CADNavigationStyle::processSoEvent(const SoEvent * const ev) // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { - SoMotion3Event * const event = (SoMotion3Event *) ev; - SoCamera * const camera = viewer->getCamera(); - - SbVec3f dir = event->getTranslation(); - if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){ - static float zoomConstant(-.03f); - dir[2] = 0.0;//don't move the cam for z translation. - - SoOrthographicCamera *oCam = static_cast(camera); - oCam->scaleHeight(1.0-event->getTranslation()[2] * zoomConstant); - } - camera->orientation.getValue().multVec(dir,dir); - camera->position = camera->position.getValue() + dir; - camera->orientation = event->getRotation() * camera->orientation.getValue(); + const SoMotion3Event * const event = static_cast(ev); + if (event) + this->processMotionEvent(event); processed = TRUE; } diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 133d81a540..b7788cfcd7 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -125,6 +125,7 @@ set(Gui_MOC_HDRS HelpView.h InputVector.h MainWindow.h + ManualAlignment.h MDIView.h NetworkRetriever.h OnlineDocumentation.h @@ -627,7 +628,7 @@ SET(Inventor_CPP_SRCS SoFCInteractiveElement.cpp SoFCOffscreenRenderer.cpp SoFCSelection.cpp - SoFCUnifiedSelection.cpp + SoFCUnifiedSelection.cpp SoFCSelectionAction.cpp SoFCVectorizeSVGAction.cpp SoFCVectorizeU3DAction.cpp @@ -647,7 +648,7 @@ SET(Inventor_SRCS SoFCInteractiveElement.h SoFCOffscreenRenderer.h SoFCSelection.h - SoFCUnifiedSelection.h + SoFCUnifiedSelection.h SoFCSelectionAction.h SoFCVectorizeSVGAction.h SoFCVectorizeU3DAction.h @@ -743,6 +744,7 @@ SET(FreeCADGui_CPP_SRCS Thumbnail.cpp Utilities.cpp WaitCursor.cpp + ManualAlignment.cpp ) SET(FreeCADGui_SRCS Application.h @@ -763,6 +765,7 @@ SET(FreeCADGui_SRCS Thumbnail.h Utilities.h WaitCursor.h + ManualAlignment.h ) SET(FreeCADGui_SRCS diff --git a/src/Gui/CombiView.cpp b/src/Gui/CombiView.cpp index 1632c4a749..b7cdb1f7f9 100644 --- a/src/Gui/CombiView.cpp +++ b/src/Gui/CombiView.cpp @@ -64,6 +64,8 @@ CombiView::CombiView(Gui::Document* pcDocument, QWidget *parent) // tree widget tree = new TreeWidget(this); //tree->setRootIsDecorated(false); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/TreeView"); + tree->setIndentation(hGrp->GetInt("Indentation", tree->indentation())); splitter->addWidget(tree); // property view diff --git a/src/Gui/CommandDoc.cpp b/src/Gui/CommandDoc.cpp index a0496abab3..b9d0ea68b0 100644 --- a/src/Gui/CommandDoc.cpp +++ b/src/Gui/CommandDoc.cpp @@ -50,11 +50,13 @@ #include "DlgProjectUtility.h" #include "Transform.h" #include "Placement.h" +#include "ManualAlignment.h" #include "WaitCursor.h" #include "ViewProvider.h" #include #include #include "MergeDocuments.h" +#include "NavigationStyle.h" using namespace Gui; @@ -279,7 +281,7 @@ void StdCmdMergeProjects::activated(int iMsg) { QString exe = QString::fromUtf8(App::GetApplication().getExecutableName()); QString project = QFileDialog::getOpenFileName(Gui::getMainWindow(), - QString::fromUtf8(QT_TR_NOOP("Merge project")), QString(), + QString::fromUtf8(QT_TR_NOOP("Merge project")), QDir::homePath(), QString::fromUtf8(QT_TR_NOOP("%1 document (*.fcstd)")).arg(exe)); if (!project.isEmpty()) { App::Document* doc = App::GetApplication().getActiveDocument(); @@ -292,9 +294,6 @@ void StdCmdMergeProjects::activated(int iMsg) return; } - QString dir1 = proj.absoluteDir().filePath(proj.baseName()); - QString dir2 = info.absoluteDir().filePath(info.baseName()); - Base::FileInfo fi((const char*)project.toUtf8()); Base::ifstream str(fi, std::ios::in | std::ios::binary); MergeDocuments md(doc); @@ -1013,6 +1012,63 @@ bool StdCmdPlacement::isActive(void) return (Gui::Control().activeDialog()==0); } +//=========================================================================== +// Std_Alignment +//=========================================================================== +DEF_STD_CMD_A(StdCmdAlignment); + +StdCmdAlignment::StdCmdAlignment() + : Command("Std_Alignment") +{ + sGroup = QT_TR_NOOP("Edit"); + sMenuText = QT_TR_NOOP("Alignment..."); + sToolTipText = QT_TR_NOOP("Align the selected objects"); + sStatusTip = QT_TR_NOOP("Align the selected objects"); + sWhatsThis = "Std_Alignment"; +} + +void StdCmdAlignment::activated(int iMsg) +{ + std::vector sel = Gui::Selection().getObjectsOfType + (App::GeoFeature::getClassTypeId()); + ManualAlignment* align = ManualAlignment::instance(); + QObject::connect(align, SIGNAL(emitCanceled()), align, SLOT(deleteLater())); + QObject::connect(align, SIGNAL(emitFinished()), align, SLOT(deleteLater())); + + // Get the fixed and moving meshes + FixedGroup fixedGroup; + std::map groupMap; + fixedGroup.addView(sel[0]); + groupMap[0].addView(sel[1]); + + // add the fixed group + align->setFixedGroup(fixedGroup); + + // create the model of movable groups + MovableGroupModel model; + model.addGroups(groupMap); + align->setModel(model); + Base::Type style = Base::Type::fromName("Gui::CADNavigationStyle"); + Gui::Document* doc = Application::Instance->activeDocument(); + if (doc) { + View3DInventor* mdi = qobject_cast(doc->getActiveView()); + if (mdi) { + style = mdi->getViewer()->navigationStyle()->getTypeId(); + } + } + + align->setMinPoints(1); + align->startAlignment(style); + Gui::Selection().clearSelection(); +} + +bool StdCmdAlignment::isActive(void) +{ + if (ManualAlignment::hasInstance()) + return false; + return Gui::Selection().countObjectsOfType(App::GeoFeature::getClassTypeId()) == 2; +} + //=========================================================================== // Std_Edit //=========================================================================== @@ -1022,7 +1078,7 @@ StdCmdEdit::StdCmdEdit() :Command("Std_Edit") { sGroup = QT_TR_NOOP("Edit"); - sMenuText = QT_TR_NOOP("Toggle &Editmode"); + sMenuText = QT_TR_NOOP("Toggle &Edit mode"); sToolTipText = QT_TR_NOOP("Toggles the selected object's edit mode"); sWhatsThis = "Std_Edit"; sStatusTip = QT_TR_NOOP("Enters or leaves the selected object's edit mode"); @@ -1085,6 +1141,7 @@ void CreateDocCommands(void) rcCmdMgr.addCommand(new StdCmdRefresh()); rcCmdMgr.addCommand(new StdCmdTransform()); rcCmdMgr.addCommand(new StdCmdPlacement()); + rcCmdMgr.addCommand(new StdCmdAlignment()); rcCmdMgr.addCommand(new StdCmdEdit()); } diff --git a/src/Gui/CommandStd.cpp b/src/Gui/CommandStd.cpp index f0c3210a6c..3861e1e647 100644 --- a/src/Gui/CommandStd.cpp +++ b/src/Gui/CommandStd.cpp @@ -521,7 +521,7 @@ StdCmdMeasurementSimple::StdCmdMeasurementSimple() :Command("Std_MeasurementSimple") { sGroup = QT_TR_NOOP("Tools"); - sMenuText = QT_TR_NOOP("Mesure distance"); + sMenuText = QT_TR_NOOP("Measure distance"); sToolTipText = QT_TR_NOOP("Measures distance between two selected objects"); sWhatsThis = QT_TR_NOOP("Measures distance between two selected objects"); sStatusTip = QT_TR_NOOP("Measures distance between two selected objects"); diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index e8c580ca49..33da94c7c1 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -58,6 +58,8 @@ #include "SceneInspector.h" #include "DemoMode.h" #include "TextureMapping.h" +#include "Utilities.h" +#include "NavigationStyle.h" #include #include @@ -1171,7 +1173,7 @@ StdViewDockUndockFullscreen::StdViewDockUndockFullscreen() : Command("Std_ViewDockUndockFullscreen") { sGroup = QT_TR_NOOP("Standard-View"); - sMenuText = QT_TR_NOOP("Display mode"); + sMenuText = QT_TR_NOOP("Document window"); sToolTipText= QT_TR_NOOP("Display the active view either in fullscreen, in undocked or docked mode"); sWhatsThis = "Std_ViewDockUndockFullscreen"; sStatusTip = QT_TR_NOOP("Display the active view either in fullscreen, in undocked or docked mode"); @@ -1816,13 +1818,7 @@ void StdViewZoomIn::activated(int iMsg) View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if ( view ) { View3DInventorViewer* viewer = view->getViewer(); - - // send an event to the GL widget to use the internal View3DInventorViewer::zoom() method - // do only one step to zoom in - SoMouseButtonEvent e; - e.setButton(SoMouseButtonEvent::BUTTON5); - e.setState(SoMouseButtonEvent::DOWN); - viewer->sendSoEvent(&e); + viewer->navigationStyle()->zoomIn(); } } @@ -1856,12 +1852,7 @@ void StdViewZoomOut::activated(int iMsg) View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); if (view) { View3DInventorViewer* viewer = view->getViewer(); - // send an event to the GL widget to use the internal View3DInventorViewer::zoom() method - // do only one step to zoom out - SoMouseButtonEvent e; - e.setButton(SoMouseButtonEvent::BUTTON4); - e.setState(SoMouseButtonEvent::DOWN); - viewer->sendSoEvent(&e); + viewer->navigationStyle()->zoomOut(); } } @@ -1900,6 +1891,83 @@ void StdViewBoxZoom::activated(int iMsg) } } +//=========================================================================== +// Std_BoxSelection +//=========================================================================== +DEF_3DV_CMD(StdBoxSelection); + +StdBoxSelection::StdBoxSelection() + : Command("Std_BoxSelection") +{ + sGroup = QT_TR_NOOP("Standard-View"); + sMenuText = QT_TR_NOOP("Box selection"); + sToolTipText = QT_TR_NOOP("Box selection"); + sWhatsThis = "Std_ViewBoxZoom"; + sStatusTip = QT_TR_NOOP("Box selection"); +#if QT_VERSION >= 0x040200 + sPixmap = "edit-select-box"; +#endif + sAccel = "Shift+B"; + eType = AlterSelection; +} + +static void selectionCallback(void * ud, SoEventCallback * cb) +{ + Gui::View3DInventorViewer* view = reinterpret_cast(cb->getUserData()); + view->removeEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback, ud); + std::vector picked = view->getGLPolygon(); + SoCamera* cam = view->getCamera(); + SbViewVolume vv = cam->getViewVolume(); + Gui::ViewVolumeProjection proj(vv); + Base::Polygon2D polygon; + if (picked.size() == 2) { + SbVec2f pt1 = picked[0]; + SbVec2f pt2 = picked[1]; + polygon.Add(Base::Vector2D(pt1[0], pt1[1])); + polygon.Add(Base::Vector2D(pt1[0], pt2[1])); + polygon.Add(Base::Vector2D(pt2[0], pt2[1])); + polygon.Add(Base::Vector2D(pt2[0], pt1[1])); + } + else { + for (std::vector::const_iterator it = picked.begin(); it != picked.end(); ++it) + polygon.Add(Base::Vector2D((*it)[0],(*it)[1])); + } + + App::Document* doc = App::GetApplication().getActiveDocument(); + if (doc) { + cb->setHandled(); + std::vector geom = doc->getObjectsOfType(); + for (std::vector::iterator it = geom.begin(); it != geom.end(); ++it) { + std::vector props; + (*it)->getPropertyList(props); + for (std::vector::iterator jt = props.begin(); jt != props.end(); ++jt) { + if ((*jt)->isDerivedFrom(App::PropertyGeometry::getClassTypeId())) { + App::PropertyGeometry* prop = static_cast(*jt); + Base::BoundBox3d bbox = prop->getBoundingBox(); + Base::Vector3d pt2d; + pt2d = proj(bbox.CalcCenter()); + if (polygon.Contains(Base::Vector2D(pt2d.x, pt2d.y))) { + Gui::Selection().addSelection(doc->getName(), (*it)->getNameInDocument()); + } + break; + } + } + } + } +} + +void StdBoxSelection::activated(int iMsg) +{ + View3DInventor* view = qobject_cast(getMainWindow()->activeWindow()); + if ( view ) { + View3DInventorViewer* viewer = view->getViewer(); + if (!viewer->isSelecting()) { + viewer->startSelection(View3DInventorViewer::Rectangle); + viewer->addEventCallback(SoMouseButtonEvent::getClassTypeId(), selectionCallback); + } + } +} + //=========================================================================== // Std_TreeSelection //=========================================================================== @@ -2113,6 +2181,7 @@ void CreateViewStdCommands(void) rcCmdMgr.addCommand(new StdViewZoomIn()); rcCmdMgr.addCommand(new StdViewZoomOut()); rcCmdMgr.addCommand(new StdViewBoxZoom()); + rcCmdMgr.addCommand(new StdBoxSelection()); rcCmdMgr.addCommand(new StdCmdTreeSelection()); rcCmdMgr.addCommand(new StdCmdMeasureDistance()); rcCmdMgr.addCommand(new StdCmdSceneInspector()); diff --git a/src/Gui/DlgDisplayProperties.ui b/src/Gui/DlgDisplayProperties.ui index 5143bf2a8a..58f4b62358 100644 --- a/src/Gui/DlgDisplayProperties.ui +++ b/src/Gui/DlgDisplayProperties.ui @@ -34,7 +34,7 @@ - Display mode: + Document window: diff --git a/src/Gui/DlgEditorImp.cpp b/src/Gui/DlgEditorImp.cpp index 7b23a1e219..c4d1d283df 100644 --- a/src/Gui/DlgEditorImp.cpp +++ b/src/Gui/DlgEditorImp.cpp @@ -115,6 +115,10 @@ DlgSettingsEditorImp::DlgSettingsEditorImp( QWidget* parent ) unsigned long lPyError = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8); d->colormap.push_back(QPair (QString::fromAscii(QT_TR_NOOP("Python error")), lPyError)); + col.setRgb(224, 224, 224); + unsigned long lCLine = (col.red() << 24) | (col.green() << 16) | (col.blue() << 8); + d->colormap.push_back(QPair + (QString::fromAscii(QT_TR_NOOP("Current line highlight")), lCLine)); QStringList labels; labels << tr("Items"); this->displayItems->setHeaderLabels(labels); diff --git a/src/Gui/DlgGeneralImp.cpp b/src/Gui/DlgGeneralImp.cpp index a908d04b9b..920baaa0ca 100644 --- a/src/Gui/DlgGeneralImp.cpp +++ b/src/Gui/DlgGeneralImp.cpp @@ -175,12 +175,22 @@ void DlgGeneralImp::loadSettings() ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("General"); QString lang = QLocale::languageToString(QLocale::system().language()); QByteArray language = hGrp->GetASCII("Language", (const char*)lang.toAscii()).c_str(); - Languages->addItem(Gui::Translator::tr("English"), QByteArray("English")); int index = 1; - TStringList list = Translator::instance()->supportedLanguages(); - for (TStringList::iterator it = list.begin(); it != list.end(); ++it, index++) { - QByteArray lang = it->c_str(); - Languages->addItem(Gui::Translator::tr(lang.constData()), lang); + Languages->addItem(QString::fromAscii("English"), QByteArray("English")); + TStringMap list = Translator::instance()->supportedLocales(); + for (TStringMap::iterator it = list.begin(); it != list.end(); ++it, index++) { + QLocale locale(QString::fromAscii(it->second.c_str())); + QByteArray lang = it->first.c_str(); + QString langname = QString::fromAscii(lang.constData()); +#if QT_VERSION >= 0x040800 + QString native = locale.nativeLanguageName(); + if (!native.isEmpty()) { + if (native[0].isLetter()) + native[0] = native[0].toUpper(); + langname = native; + } +#endif + Languages->addItem(langname, lang); if (language == lang) { Languages->setCurrentIndex(index); } diff --git a/src/Gui/DlgSettingsViewColor.ui b/src/Gui/DlgSettingsViewColor.ui index c90498e618..e17848a4e8 100644 --- a/src/Gui/DlgSettingsViewColor.ui +++ b/src/Gui/DlgSettingsViewColor.ui @@ -406,7 +406,7 @@ - The color of construction geometry in editmode + The color of construction geometry in edit mode @@ -426,7 +426,7 @@ - The color of fully constrained geometry in editmode + The color of fully constrained geometry in edit mode diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 18447b2e10..0192d3e86e 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -55,7 +55,6 @@ #include "BitmapFactory.h" #include "ViewProviderDocumentObject.h" #include "Selection.h" -#include "SoFCSelection.h" #include "WaitCursor.h" #include "Thumbnail.h" @@ -406,17 +405,18 @@ void Document::slotDeletedObject(const App::DocumentObject& Obj) // cycling to all views of the document ViewProvider* viewProvider = getViewProvider(&Obj); - for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) { - View3DInventor *activeView = dynamic_cast(*vIt); - if (activeView && viewProvider) { - if (d->_pcInEdit == viewProvider) - resetEdit(); - activeView->getViewer()->removeViewProvider(viewProvider); + if (viewProvider && viewProvider->getTypeId().isDerivedFrom + (ViewProviderDocumentObject::getClassTypeId())) { + // go through the views + for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) { + View3DInventor *activeView = dynamic_cast(*vIt); + if (activeView) { + if (d->_pcInEdit == viewProvider) + resetEdit(); + activeView->getViewer()->removeViewProvider(viewProvider); + } } - } - if (viewProvider && viewProvider->getTypeId().isDerivedFrom( - ViewProviderDocumentObject::getClassTypeId())) { // removing from tree signalDeletedObject(*(static_cast(viewProvider))); @@ -642,8 +642,13 @@ void Document::RestoreDocFile(Base::Reader &reader) std::string sMsg = "SetCamera "; sMsg += ppReturn; if (strcmp(ppReturn, "") != 0) { // non-empty attribute - if (d->_pcAppWnd->sendHasMsgToActiveView("SetCamera")) - d->_pcAppWnd->sendMsgToActiveView(sMsg.c_str()); + try { + if (d->_pcAppWnd->sendHasMsgToActiveView("SetCamera")) + d->_pcAppWnd->sendMsgToActiveView(sMsg.c_str()); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + } } } @@ -743,7 +748,7 @@ void Document::exportObjects(const std::vector& obj, Base: << views.size() <<"\">" << std::endl; bool xml = writer.isForceXML(); - writer.setForceXML(true); + //writer.setForceXML(true); writer.incInd(); // indention for 'ViewProvider name' std::map::const_iterator jt; for (jt = views.begin(); jt != views.end(); ++jt) { @@ -826,6 +831,7 @@ void Document::createView(const char* sType) .arg(QString::fromUtf8(name)).arg(d->_iWinCount++); view3D->setWindowTitle(title); + view3D->setWindowModified(this->isModified()); view3D->setWindowIcon(QApplication::windowIcon()); view3D->resize(400, 300); getMainWindow()->addWindow(view3D); @@ -967,6 +973,19 @@ std::list Document::getMDIViews() const return views; } +std::list Document::getMDIViewsOfType(const Base::Type& typeId) const +{ + std::list views; + for (std::list::const_iterator it = d->baseViews.begin(); + it != d->baseViews.end(); ++it) { + MDIView* view = dynamic_cast(*it); + if (view && view->isDerivedFrom(typeId)) + views.push_back(view); + } + + return views; +} + /// send messages to the active view bool Document::sendMsgToViews(const char* pMsg) { @@ -1006,9 +1025,9 @@ MDIView* Document::getActiveView(void) const } } - // the active view is not part of this document, just use the first view + // the active view is not part of this document, just use the last view if (!ok && !mdis.empty()) - active = mdis.front(); + active = mdis.back(); return active; } diff --git a/src/Gui/Document.h b/src/Gui/Document.h index 55053c8d55..9382c33bdb 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -140,6 +140,8 @@ public: void onRelabel(void); /// returns a list of all attached MDI views std::list getMDIViews() const; + /// returns a list of all MDI views of a certain type + std::list getMDIViewsOfType(const Base::Type& typeId) const; //@} /** @name View provider handling */ diff --git a/src/Gui/DocumentPy.xml b/src/Gui/DocumentPy.xml index e73893f107..c76e101cf0 100644 --- a/src/Gui/DocumentPy.xml +++ b/src/Gui/DocumentPy.xml @@ -68,6 +68,21 @@ deprecated -- use ActiveView + + + Return a list if mdi views of a given type + + + + + Send a message to all views of the document + + + + + Merges this document with another project file + + The active object of the document diff --git a/src/Gui/DocumentPyImp.cpp b/src/Gui/DocumentPyImp.cpp index bc05a0e216..67b66f36a7 100644 --- a/src/Gui/DocumentPyImp.cpp +++ b/src/Gui/DocumentPyImp.cpp @@ -32,6 +32,7 @@ #include #include "Document.h" +#include "MergeDocuments.h" #include "ViewProviderExtern.h" // inclusion of the generated files (generated out of DocumentPy.xml) @@ -201,6 +202,55 @@ PyObject* DocumentPy::activeView(PyObject *args) } PY_CATCH; } +PyObject* DocumentPy::mdiViewsOfType(PyObject *args) +{ + char* sType; + if (!PyArg_ParseTuple(args, "s", &sType)) // convert args: Python->C + return NULL; // NULL triggers exception + + Base::Type type = Base::Type::fromName(sType); + if (type == Base::Type::badType()) { + PyErr_Format(PyExc_Exception, "'%s' is not a valid type", sType); + return NULL; + } + + PY_TRY { + std::list views = getDocumentPtr()->getMDIViewsOfType(type); + Py::List list; + for (std::list::iterator it = views.begin(); it != views.end(); ++it) + list.append(Py::asObject((*it)->getPyObject())); + return Py::new_reference_to(list); + } PY_CATCH; +} + +PyObject* DocumentPy::sendMsgToViews(PyObject *args) +{ + char* msg; + if (!PyArg_ParseTuple(args, "s", &msg)) // convert args: Python->C + return NULL; // NULL triggers exception + + PY_TRY { + getDocumentPtr()->sendMsgToViews(msg); + Py_Return; + } PY_CATCH; +} + +PyObject* DocumentPy::mergeProject(PyObject *args) +{ + char* filename; + if (!PyArg_ParseTuple(args, "s", &filename)) // convert args: Python->C + return NULL; // NULL triggers exception + + PY_TRY { + Base::FileInfo fi(filename); + Base::ifstream str(fi, std::ios::in | std::ios::binary); + App::Document* doc = getDocumentPtr()->getDocument(); + MergeDocuments md(doc); + md.importObjects(str); + Py_Return; + } PY_CATCH; +} + Py::Object DocumentPy::getActiveObject(void) const { App::DocumentObject *object = getDocumentPtr()->getDocument()->getActiveObject(); diff --git a/src/Gui/EditorView.h b/src/Gui/EditorView.h index d726308668..096733ba9f 100644 --- a/src/Gui/EditorView.h +++ b/src/Gui/EditorView.h @@ -74,6 +74,7 @@ public: void print (); void printPdf(); void printPreview(); + void print(QPrinter*); //@} QStringList undoActions() const; @@ -88,7 +89,6 @@ private Q_SLOTS: void contentsChange(int position, int charsRemoved, int charsAdded); void undoAvailable(bool); void redoAvailable(bool); - void print(QPrinter*); private: void setCurrentFileName(const QString &fileName); diff --git a/src/Gui/FreeCADGuiInit.py b/src/Gui/FreeCADGuiInit.py index 4f60213f0d..68296d2f1d 100644 --- a/src/Gui/FreeCADGuiInit.py +++ b/src/Gui/FreeCADGuiInit.py @@ -169,6 +169,7 @@ FreeCAD.addExportType("Inventor V2.1 (*.iv)","FreeCADGui") FreeCAD.addExportType("VRML V2.0 (*.wrl *.vrml *.wrz *.wrl.gz)","FreeCADGui") #FreeCAD.addExportType("IDTF (for 3D PDF) (*.idtf)","FreeCADGui") FreeCAD.addExportType("3D View (*.svg)","FreeCADGui") +FreeCAD.addExportType("Portable Document Format (*.pdf)","FreeCADGui") del(InitApplications) del(NoneWorkbench) diff --git a/src/Gui/Icons/Makefile.am b/src/Gui/Icons/Makefile.am index 70c30f0f4b..9be01aa6cb 100644 --- a/src/Gui/Icons/Makefile.am +++ b/src/Gui/Icons/Makefile.am @@ -58,6 +58,7 @@ EXTRA_DIST = \ edit-delete.svg \ edit-paste.svg \ edit-select-all.svg \ + edit-select-box.svg \ edit-redo.svg \ edit-undo.svg \ preferences-system.svg \ diff --git a/src/Gui/Icons/edit-select-all.svg b/src/Gui/Icons/edit-select-all.svg old mode 100644 new mode 100755 index b875ff920a..bbc95140dd --- a/src/Gui/Icons/edit-select-all.svg +++ b/src/Gui/Icons/edit-select-all.svg @@ -1,347 +1,264 @@ + + inkscape:version="0.48.3.1 r9886" + sodipodi:docname="edit-select-all.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + version="1.1"> - + id="defs2982"> + id="linearGradient4590"> + id="stop4592" /> + id="stop4594" /> + + + + + + + + - - - - - - - - - - + gradientTransform="matrix(0.6028459,1.0471639,-1.9794021,1.1395295,127.9588,-74.456907)" + cx="51.328892" + cy="31.074146" + fx="51.328892" + fy="31.074146" + r="19.571428" /> + + + xlink:href="#linearGradient3864" + id="radialGradient2890" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.58019421,1.0078171,-1.9050269,1.0967121,-8.5316607,-197.0902)" + cx="51.328892" + cy="31.074146" + fx="51.328892" + fy="31.074146" + r="19.571428" /> + + + inkscape:collect="always" + xlink:href="#linearGradient3811" + id="linearGradient3817" + x1="36.870125" + y1="30.196993" + x2="3.3695574" + y2="39.373768" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.27764843,-1.1190823,1.1190823,0.27764843,-10.424279,50.285999)" /> + + + id="stop3813-8" /> - + id="stop3815-7" /> + gradientTransform="translate(0,8)" /> + + + + + + + + + + + + inkscape:window-height="758" + inkscape:window-x="0" + inkscape:window-y="19" + inkscape:window-maximized="0" /> + id="metadata2985"> image/svg+xml - Select All - - - - Andreas Nilsson - - - - - select - all - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + diff --git a/src/Gui/Icons/edit-select-box.svg b/src/Gui/Icons/edit-select-box.svg new file mode 100755 index 0000000000..abaf58cbe0 --- /dev/null +++ b/src/Gui/Icons/edit-select-box.svg @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc index 82548cd396..2114905a6d 100644 --- a/src/Gui/Icons/resource.qrc +++ b/src/Gui/Icons/resource.qrc @@ -43,6 +43,7 @@ edit-delete.svg edit-paste.svg edit-select-all.svg + edit-select-box.svg edit-redo.svg edit-undo.svg edit-edit.svg diff --git a/src/Gui/InputVector.h b/src/Gui/InputVector.h index b5c1012516..bdb9036d9b 100644 --- a/src/Gui/InputVector.h +++ b/src/Gui/InputVector.h @@ -275,6 +275,13 @@ public: } } + void setPosition(const Base::Vector3f& v) + { + this->xPos->setValue(v.x); + this->yPos->setValue(v.y); + this->zPos->setValue(v.z); + } + Base::Vector3f getPosition() const { return Base::Vector3f((float)this->xPos->value(), diff --git a/src/Gui/InventorNavigationStyle.cpp b/src/Gui/InventorNavigationStyle.cpp index 5fb72f9893..e1e6f47557 100644 --- a/src/Gui/InventorNavigationStyle.cpp +++ b/src/Gui/InventorNavigationStyle.cpp @@ -285,16 +285,10 @@ SbBool InventorNavigationStyle::processSoEvent(const SoEvent * const ev) // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { - SoMotion3Event * const event = (SoMotion3Event *) ev; - SoCamera * const camera = viewer->getCamera(); - if (camera) { - SbVec3f dir = event->getTranslation(); - camera->orientation.getValue().multVec(dir,dir); - camera->position = camera->position.getValue() + dir; - camera->orientation = - event->getRotation() * camera->orientation.getValue(); - processed = TRUE; - } + const SoMotion3Event * const event = static_cast(ev); + if (event) + this->processMotionEvent(event); + processed = TRUE; } enum { diff --git a/src/Gui/Language/FreeCAD.ts b/src/Gui/Language/FreeCAD.ts index 3b452a8607..024b5a7f1b 100644 --- a/src/Gui/Language/FreeCAD.ts +++ b/src/Gui/Language/FreeCAD.ts @@ -5302,7 +5302,7 @@ You either have to finish or cancel the editing in the task panel. - Display mode + Document window diff --git a/src/Gui/Language/FreeCAD_af.ts b/src/Gui/Language/FreeCAD_af.ts index 052ea4d8c1..4ba0e26ca1 100644 --- a/src/Gui/Language/FreeCAD_af.ts +++ b/src/Gui/Language/FreeCAD_af.ts @@ -5317,8 +5317,8 @@ You either have to finish or cancel the editing in the task panel. Standaardaansig - Display mode - Vertoningsmodus + Document window + Dokument venster Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_de.ts b/src/Gui/Language/FreeCAD_de.ts index be807a1b7e..79e5131c29 100644 --- a/src/Gui/Language/FreeCAD_de.ts +++ b/src/Gui/Language/FreeCAD_de.ts @@ -5325,8 +5325,8 @@ Sie müssen entweder den Bearbeitungsvorgang fertigstellen oder mittels des Aufg Standardansicht - Display mode - Anzeige-Modus + Document window + Dokumentfenster Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_es.ts b/src/Gui/Language/FreeCAD_es.ts index 173822aa00..089b96e95d 100644 --- a/src/Gui/Language/FreeCAD_es.ts +++ b/src/Gui/Language/FreeCAD_es.ts @@ -5323,8 +5323,8 @@ Tienes que finzalizar o cancelar la edición en el panel de tareas.Vista estándar - Display mode - Modo de visualización + Document window + Ventana de documento Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_fi.ts b/src/Gui/Language/FreeCAD_fi.ts index dab907d81d..ec9cde9a05 100644 --- a/src/Gui/Language/FreeCAD_fi.ts +++ b/src/Gui/Language/FreeCAD_fi.ts @@ -5314,8 +5314,8 @@ You either have to finish or cancel the editing in the task panel. Standardi-Näkymä - Display mode - Näyttötila + Document window + Asiakirjan ikkuna Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_fr.ts b/src/Gui/Language/FreeCAD_fr.ts index c65a10cdf9..f665da6bd2 100644 --- a/src/Gui/Language/FreeCAD_fr.ts +++ b/src/Gui/Language/FreeCAD_fr.ts @@ -5319,8 +5319,8 @@ You either have to finish or cancel the editing in the task panel. Vue standard - Display mode - Mode d'affichage + Document window + Fenêtre de document Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_hr.ts b/src/Gui/Language/FreeCAD_hr.ts index 790f209822..11e5c702ba 100644 --- a/src/Gui/Language/FreeCAD_hr.ts +++ b/src/Gui/Language/FreeCAD_hr.ts @@ -5311,8 +5311,8 @@ You either have to finish or cancel the editing in the task panel. Standardni pogled - Display mode - Način prikaza + Document window + Dokument prozor Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_hu.ts b/src/Gui/Language/FreeCAD_hu.ts index cf6433c3a8..74d0db3b56 100644 --- a/src/Gui/Language/FreeCAD_hu.ts +++ b/src/Gui/Language/FreeCAD_hu.ts @@ -5318,8 +5318,8 @@ You either have to finish or cancel the editing in the task panel. Standard-nézet - Display mode - Megjelenítési mód + Document window + Dokumentum ablak Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_it.ts b/src/Gui/Language/FreeCAD_it.ts index 64b5bd7c3a..cb266b1d00 100644 --- a/src/Gui/Language/FreeCAD_it.ts +++ b/src/Gui/Language/FreeCAD_it.ts @@ -5325,8 +5325,8 @@ You either have to finish or cancel the editing in the task panel. Vista standard - Display mode - Modalità di visualizzazione + Document window + Finestra del documento Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_ja.ts b/src/Gui/Language/FreeCAD_ja.ts index 5773577fd4..0406284a60 100644 --- a/src/Gui/Language/FreeCAD_ja.ts +++ b/src/Gui/Language/FreeCAD_ja.ts @@ -5319,8 +5319,8 @@ You either have to finish or cancel the editing in the task panel. 標準ビュー - Display mode - 表示モード + Document window + ドキュメントウィンドウ Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_nl.ts b/src/Gui/Language/FreeCAD_nl.ts index 0a57b99f55..ea7ae833c4 100644 --- a/src/Gui/Language/FreeCAD_nl.ts +++ b/src/Gui/Language/FreeCAD_nl.ts @@ -5314,8 +5314,8 @@ You either have to finish or cancel the editing in the task panel. Standaard-aanzicht - Display mode - Weergavemodus + Document window + Documentvenster Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_no.ts b/src/Gui/Language/FreeCAD_no.ts index 948c209da5..56087e8fac 100644 --- a/src/Gui/Language/FreeCAD_no.ts +++ b/src/Gui/Language/FreeCAD_no.ts @@ -5315,8 +5315,8 @@ You either have to finish or cancel the editing in the task panel. Standardvisning - Display mode - Visningsmodus + Document window + Dokument-vinduet Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_pl.ts b/src/Gui/Language/FreeCAD_pl.ts index 064d5e00ea..0a428556ba 100644 --- a/src/Gui/Language/FreeCAD_pl.ts +++ b/src/Gui/Language/FreeCAD_pl.ts @@ -5305,8 +5305,8 @@ You either have to finish or cancel the editing in the task panel. Normalny widok - Display mode - Tryb wyświetlania + Document window + Okno dokumentu Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_pt.ts b/src/Gui/Language/FreeCAD_pt.ts index 2ed9d6bf6b..fd0cde9227 100644 --- a/src/Gui/Language/FreeCAD_pt.ts +++ b/src/Gui/Language/FreeCAD_pt.ts @@ -5307,8 +5307,8 @@ You either have to finish or cancel the editing in the task panel. Vista padrão - Display mode - Modo de exibição + Document window + Janela do documento Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_ru.ts b/src/Gui/Language/FreeCAD_ru.ts index 40667e37ac..b1e39e830f 100644 --- a/src/Gui/Language/FreeCAD_ru.ts +++ b/src/Gui/Language/FreeCAD_ru.ts @@ -5310,8 +5310,8 @@ You either have to finish or cancel the editing in the task panel. Стандартный вид - Display mode - Режим отображения + Document window + окно документа Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_se.ts b/src/Gui/Language/FreeCAD_se.ts index 1f51d82428..9b777ffac2 100644 --- a/src/Gui/Language/FreeCAD_se.ts +++ b/src/Gui/Language/FreeCAD_se.ts @@ -5324,8 +5324,8 @@ You either have to finish or cancel the editing in the task panel. Standardvy - Display mode - Visningsläge + Document window + Dokumentfönstret Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_uk.ts b/src/Gui/Language/FreeCAD_uk.ts index b9dbe90997..5e0b27cb6c 100644 --- a/src/Gui/Language/FreeCAD_uk.ts +++ b/src/Gui/Language/FreeCAD_uk.ts @@ -5325,8 +5325,8 @@ You either have to finish or cancel the editing in the task panel. Стандартні вигляди - Display mode - Режим показу + Document window + вікно документа Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/FreeCAD_zh.ts b/src/Gui/Language/FreeCAD_zh.ts index 18e102a1ee..a63f7f181a 100644 --- a/src/Gui/Language/FreeCAD_zh.ts +++ b/src/Gui/Language/FreeCAD_zh.ts @@ -5313,8 +5313,8 @@ You either have to finish or cancel the editing in the task panel. 标准视图 - Display mode - 显示模式 + Document window + 文档窗口 Display the active view either in fullscreen, in undocked or docked mode diff --git a/src/Gui/Language/Makefile.am b/src/Gui/Language/Makefile.am index aec3aeb8ad..a72ca473f0 100644 --- a/src/Gui/Language/Makefile.am +++ b/src/Gui/Language/Makefile.am @@ -23,6 +23,7 @@ EXTRA_DIST = \ FreeCAD_it.qm \ FreeCAD_nl.qm \ FreeCAD_no.qm \ + FreeCAD_pl.qm \ FreeCAD_pt.qm \ FreeCAD_ru.qm \ FreeCAD_se.qm \ @@ -37,6 +38,7 @@ EXTRA_DIST = \ FreeCAD_it.ts \ FreeCAD_nl.ts \ FreeCAD_no.ts \ + FreeCAD_pl.ts \ FreeCAD_pt.ts \ FreeCAD_ru.ts \ FreeCAD_se.ts \ diff --git a/src/Gui/Language/Translator.cpp b/src/Gui/Language/Translator.cpp index 9f322afd8b..d48c1ec3fc 100644 --- a/src/Gui/Language/Translator.cpp +++ b/src/Gui/Language/Translator.cpp @@ -146,6 +146,7 @@ Translator::Translator() d->mapLanguageTopLevelDomain[QT_TR_NOOP("Ukrainian" )] = "uk"; d->mapLanguageTopLevelDomain[QT_TR_NOOP("Finnish" )] = "fi"; d->mapLanguageTopLevelDomain[QT_TR_NOOP("Croatian" )] = "hr"; + d->mapLanguageTopLevelDomain[QT_TR_NOOP("Polish" )] = "pl"; d->activatedLanguage = "English"; d->paths = directories(); @@ -173,6 +174,22 @@ TStringList Translator::supportedLanguages() const return languages; } +TStringMap Translator::supportedLocales() const +{ + // List all .qm files + TStringMap languages; + QDir dir(QLatin1String(":/translations")); + for (std::map::const_iterator it = d->mapLanguageTopLevelDomain.begin(); + it != d->mapLanguageTopLevelDomain.end(); ++it) { + QString filter = QString::fromAscii("*_%1.qm").arg(QLatin1String(it->second.c_str())); + QStringList fileNames = dir.entryList(QStringList(filter), QDir::Files, QDir::Name); + if (!fileNames.isEmpty()) + languages[it->first] = it->second; + } + + return languages; +} + void Translator::activateLanguage (const char* lang) { removeTranslators(); // remove the currently installed translators diff --git a/src/Gui/Language/Translator.h b/src/Gui/Language/Translator.h index 7ce7905bb8..30f4543c18 100644 --- a/src/Gui/Language/Translator.h +++ b/src/Gui/Language/Translator.h @@ -34,6 +34,7 @@ class QDir; namespace Gui { typedef std::list TStringList; +typedef std::map TStringMap; /** * The Translator class uses Qt's QTranslator objects to change the language of the application @@ -65,6 +66,8 @@ public: std::string activeLanguage() const; /** Returns a list of supported languages. */ TStringList supportedLanguages() const; + /** Returns a map of supported languages/locales. */ + TStringMap supportedLocales() const; /** Adds a path where localization files can be found */ void addPath(const QString& path); diff --git a/src/Gui/Language/translation.qrc b/src/Gui/Language/translation.qrc index 63d2e5d686..e2e81ad1e7 100644 --- a/src/Gui/Language/translation.qrc +++ b/src/Gui/Language/translation.qrc @@ -9,6 +9,7 @@ FreeCAD_it.qm FreeCAD_nl.qm FreeCAD_no.qm + FreeCAD_pl.qm FreeCAD_pt.qm FreeCAD_ru.qm FreeCAD_se.qm diff --git a/src/Gui/MDIView.cpp b/src/Gui/MDIView.cpp index 6aef8cd64e..c47e628f80 100644 --- a/src/Gui/MDIView.cpp +++ b/src/Gui/MDIView.cpp @@ -29,6 +29,7 @@ # include # include # include +#include #endif @@ -56,15 +57,17 @@ MDIView::~MDIView() //the application crashes when accessing this deleted view. //This effect only occurs if this widget is not in Child mode, because otherwise //the focus stuff is done correctly. - QWidget* foc = getMainWindow()->focusWidget(); - if (foc) { - QWidget* par = foc; - while (par) { - if (par == this) { - getMainWindow()->setFocus(); - break; + if (getMainWindow()) { + QWidget* foc = getMainWindow()->focusWidget(); + if (foc) { + QWidget* par = foc; + while (par) { + if (par == this) { + getMainWindow()->setFocus(); + break; + } + par = par->parentWidget(); } - par = par->parentWidget(); } } } @@ -166,22 +169,24 @@ void MDIView::windowStateChanged( MDIView* ) { } +void MDIView::print(QPrinter* printer) +{ + std::cerr << "Printing not implemented for " << this->metaObject()->className() << std::endl; +} + void MDIView::print() { - // print command specified but print method not overriden! - assert(0); + std::cerr << "Printing not implemented for " << this->metaObject()->className() << std::endl; } void MDIView::printPdf() { - // print command specified but print method not overriden! - assert(0); + std::cerr << "Printing PDF not implemented for " << this->metaObject()->className() << std::endl; } void MDIView::printPreview() { - // print command specified but print method not overriden! - assert(0); + std::cerr << "Printing preview not implemented for " << this->metaObject()->className() << std::endl; } QSize MDIView::minimumSizeHint () const diff --git a/src/Gui/MDIView.h b/src/Gui/MDIView.h index c96c4daa28..e96f7e172c 100644 --- a/src/Gui/MDIView.h +++ b/src/Gui/MDIView.h @@ -74,10 +74,18 @@ public: virtual bool canClose(void); /// delete itself virtual void deleteSelf(); - /// print function of the view + /** @name Printing */ + //@{ +public Q_SLOTS: + virtual void print(QPrinter* printer); +public: + /** Print content of view */ virtual void print(); + /** Print to PDF file */ virtual void printPdf(); + /** Show a preview dialog */ virtual void printPreview(); + //@} QSize minimumSizeHint () const; diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index 05f5c8f473..8c129d761d 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -272,9 +272,12 @@ MainWindow::MainWindow(QWidget * parent, Qt::WFlags f) d->mdiArea->setTabPosition(QTabWidget::South); d->mdiArea->setViewMode(QMdiArea::TabbedView); QTabBar* tab = d->mdiArea->findChild(); - if (tab) { + if (tab) { + // 0000636: Two documents close +#if QT_VERSION < 0x040800 connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int))); +#endif tab->setTabsClosable(true); // The tabs might be very wide tab->setExpanding(false); @@ -1151,6 +1154,13 @@ void MainWindow::delayedStartup() // processing all command line files App::Application::processCmdLineFiles(); + const std::map& cfg = App::Application::Config(); + std::map::const_iterator it = cfg.find("StartHidden"); + if (it != cfg.end()) { + QApplication::quit(); + return; + } + // Create new document? ParameterGrp::handle hGrp = WindowParameter::getDefaultParameter()->GetGroup("Document"); if (hGrp->GetBool("CreateNewDoc", false)) { diff --git a/src/Gui/Makefile.am b/src/Gui/Makefile.am index 1cf4fcc163..c714f4913b 100644 --- a/src/Gui/Makefile.am +++ b/src/Gui/Makefile.am @@ -48,6 +48,7 @@ BUILT_SOURCES=\ moc_HelpView.cpp \ moc_InputVector.cpp \ moc_MainWindow.cpp \ + moc_ManualAlignment.cpp \ moc_NetworkRetriever.cpp \ moc_OnlineDocumentation.cpp \ moc_Placement.cpp \ @@ -282,6 +283,8 @@ libFreeCADGui_la_SOURCES=\ Placement.h \ Macro.cpp \ MainWindow.cpp \ + ManualAlignment.cpp \ + ManualAlignment.h \ MDIView.cpp \ MenuManager.cpp \ MergeDocuments.cpp \ diff --git a/src/Gui/ManualAlignment.cpp b/src/Gui/ManualAlignment.cpp new file mode 100644 index 0000000000..d220922fa9 --- /dev/null +++ b/src/Gui/ManualAlignment.cpp @@ -0,0 +1,1246 @@ +/*************************************************************************** + * Copyright (c) 2012 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 +# 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 +#include +#include +#include +#include +#include +#include + +#include "ManualAlignment.h" +#include "BitmapFactory.h" +#include "SoAxisCrossKit.h" + + +using namespace Gui; + +AlignmentGroup::AlignmentGroup() +{ +} + +AlignmentGroup::~AlignmentGroup() +{ +} + +void AlignmentGroup::addView(App::DocumentObject* pView) +{ + if (pView) { + App::Document* rDoc = pView->getDocument(); + Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc); + Gui::ViewProviderDocumentObject* pProvider = static_cast + (pDoc->getViewProvider(pView)); + this->_views.push_back(pProvider); + } +} + +std::vector AlignmentGroup::getViews() const +{ + std::vector views; + + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + App::DocumentObject* pView = (*it)->getObject(); + views.push_back(pView); + } + + return views; +} + +bool AlignmentGroup::hasView(Gui::ViewProviderDocumentObject* pView) const +{ + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + if (*it == pView) + return true; + } + + return false; +} + +void AlignmentGroup::removeView(Gui::ViewProviderDocumentObject* pView) +{ + std::vector::iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + if (*it == pView) { + this->_views.erase(it); + break; + } + } +} + +void AlignmentGroup::addToViewer(Gui::View3DInventorViewer* viewer) const +{ + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) + viewer->addViewProvider(*it); + + viewer->viewAll(); +} + +void AlignmentGroup::removeFromViewer(Gui::View3DInventorViewer* viewer) const +{ + std::vector::const_iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) + viewer->removeViewProvider(*it); +} + +void AlignmentGroup::setRandomColor() +{ + std::vector::iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) { + float r = /*(float)rand()/(float)RAND_MAX*/0.0f; + float g = (float)rand()/(float)RAND_MAX; + float b = (float)rand()/(float)RAND_MAX; + if ((*it)->isDerivedFrom(Gui::ViewProviderGeometryObject::getClassTypeId())) { + SoSearchAction searchAction; + searchAction.setType(SoMaterial::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply((*it)->getRoot()); + SoPath* selectionPath = searchAction.getPath(); + + if (selectionPath) { + SoMaterial* material = static_cast(selectionPath->getTail()); + material->diffuseColor.setValue(r, g, b); + } + } + } +} + +Gui::Document* AlignmentGroup::getDocument() const +{ + if (this->_views.empty()) + return 0; + App::DocumentObject* pView = this->_views[0]->getObject(); + if (pView) { + App::Document* rDoc = pView->getDocument(); + Gui::Document* pDoc = Gui::Application::Instance->getDocument(rDoc); + return pDoc; + } + + return 0; +} + +void AlignmentGroup::addPoint(const Base::Vector3d& pnt) +{ + this->_pickedPoints.push_back(pnt); +} + +void AlignmentGroup::removeLastPoint() +{ + this->_pickedPoints.pop_back(); +} + +int AlignmentGroup::countPoints() const +{ + return this->_pickedPoints.size(); +} + +const std::vector& AlignmentGroup::getPoints() const +{ + return this->_pickedPoints; +} + +void AlignmentGroup::clearPoints() +{ + this->_pickedPoints.clear(); +} + +void AlignmentGroup::setAlignable(bool align) +{ + //std::vector::iterator it; + //for (it = this->_views.begin(); it != this->_views.end(); ++it) { + // if (!align){ + // App::PropertyColor* pColor = (App::PropertyColor*)(*it)->getPropertyByName("ShapeColor"); + // if (pColor) + // pColor->touch(); // resets to color defined by property + // } + //} +} + +void AlignmentGroup::moveTo(AlignmentGroup& that) +{ + std::vector::iterator it; + for (it = this->_views.begin(); it != this->_views.end(); ++it) + that._views.push_back(*it); + + this->_views.clear(); +} + +void AlignmentGroup::clear() +{ + this->_views.clear(); + this->_pickedPoints.clear(); +} + +bool AlignmentGroup::isEmpty() const +{ + return this->_views.empty(); +} + +int AlignmentGroup::count() const +{ + return this->_views.size(); +} + +// ------------------------------------------------------------------ + +MovableGroup::MovableGroup() +{ +} + +MovableGroup::~MovableGroup() +{ +} + +// ------------------------------------------------------------------ + +FixedGroup::FixedGroup() +{ +} + +FixedGroup::~FixedGroup() +{ +} + +// ------------------------------------------------------------------ + +MovableGroupModel::MovableGroupModel() +{ +} + +MovableGroupModel::~MovableGroupModel() +{ +} + +void MovableGroupModel::addGroup(const MovableGroup& grp) +{ + this->_groups.push_back(grp); +} + +void MovableGroupModel::addGroups(const std::map& grps) +{ + for (std::map::const_iterator it = grps.begin(); it != grps.end(); ++it) + this->_groups.push_back(it->second); +} + +void MovableGroupModel::removeActiveGroup() +{ + this->_groups.erase(this->_groups.begin()); +} + +MovableGroup& MovableGroupModel::activeGroup() +{ + // Make sure that the array is not empty + if (this->_groups.empty()) + throw Base::Exception("Empty group"); + return *(this->_groups.begin()); +} + +const MovableGroup& MovableGroupModel::activeGroup() const +{ + // Make sure that the array is not empty + if (this->_groups.empty()) + throw Base::Exception("Empty group"); + return *(this->_groups.begin()); +} + +void MovableGroupModel::continueAlignment() +{ + if (!isEmpty()) + removeActiveGroup(); +} + +void MovableGroupModel::clear() +{ + this->_groups.clear(); +} + +bool MovableGroupModel::isEmpty() const +{ + return this->_groups.empty(); +} + +int MovableGroupModel::count() const +{ + return this->_groups.size(); +} + +// ------------------------------------------------------------------ + +namespace Gui { +class AlignmentView : public Gui::AbstractSplitView +{ +public: + QLabel* myLabel; + + AlignmentView(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0) + : AbstractSplitView(pcDocument, parent, wflags) + { + QSplitter* mainSplitter=0; + mainSplitter = new QSplitter(Qt::Horizontal, this); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + + QFrame* vbox = new QFrame(this); + QVBoxLayout* layout = new QVBoxLayout(); + layout->setMargin(0); + layout->setSpacing(0); + vbox->setLayout(layout); + + myLabel = new QLabel(this); + myLabel->setAutoFillBackground(true); + QPalette pal = myLabel->palette(); + pal.setColor(QPalette::Window, Qt::darkGray); + pal.setColor(QPalette::WindowText, Qt::white); + myLabel->setPalette(pal); + mainSplitter->setPalette(pal); + myLabel->setAlignment(Qt::AlignCenter); + myLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + QFont font = myLabel->font(); + font.setPointSize(14); + myLabel->setFont(font); + layout->addWidget(myLabel); + layout->addWidget(mainSplitter); + + vbox->show(); + setCentralWidget(vbox); + + // apply the user settings + setupSettings(); + + static_cast(getViewer(0)->getSceneManager()->getSceneGraph())-> + addChild(setupHeadUpDisplay(tr("Movable object"))); + static_cast(getViewer(1)->getSceneManager()->getSceneGraph())-> + addChild(setupHeadUpDisplay(tr("Fixed object"))); + } + ~AlignmentView() + { + } + bool canClose() + { + return false; + } + SoNode* setupHeadUpDisplay(const QString& text) const + { + SoSeparator* hudRoot = new SoSeparator; + hudRoot->ref(); + + SoOrthographicCamera* hudCam = new SoOrthographicCamera(); + hudCam->viewportMapping = SoCamera::LEAVE_ALONE; + + // Set the position in the window. + // [0, 0] is in the center of the screen. + // + SoTranslation* hudTrans = new SoTranslation; + hudTrans->translation.setValue(-0.95f, -0.95f, 0.0f); + + QFont font = this->font(); + font.setPointSize(24); + QFontMetrics fm(font); + + QColor front; + front.setRgbF(0.8f, 0.8f, 0.8f); + + int w = fm.width(text); + int h = fm.height(); + + QImage image(w,h,QImage::Format_ARGB32_Premultiplied); + image.fill(0x00000000); + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing); + painter.setPen(front); + painter.setFont(font); + painter.drawText(0,0,w,h,Qt::AlignLeft,text); + painter.end(); + SoSFImage sfimage; + Gui::BitmapFactory().convert(image, sfimage); + SoImage* hudImage = new SoImage(); + hudImage->image = sfimage; + + // Assemble the parts... + // + hudRoot->addChild(hudCam); + hudRoot->addChild(hudTrans); + hudRoot->addChild(hudImage); + + return hudRoot; + } +}; +} + +class ManualAlignment::Private { +public: + SoSeparator * picksepLeft; + SoSeparator * picksepRight; + SoNodeSensor* sensorCam1; + SoNodeSensor* sensorCam2; + SbRotation rot_cam1, rot_cam2; + SbVec3f pos_cam1, pos_cam2; + + Private() + : sensorCam1(0), sensorCam2(0) + { + // left view + picksepLeft = new SoSeparator; + picksepLeft->ref(); + // right view + picksepRight = new SoSeparator; + picksepRight->ref(); + } + ~Private() + { + picksepLeft->unref(); + picksepRight->unref(); + delete sensorCam1; + delete sensorCam2; + } + + static + void reorientCamera(SoCamera * cam, const SbRotation & rot) + { + if (cam == NULL) return; + + // Find global coordinates of focal point. + SbVec3f direction; + cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); + SbVec3f focalpoint = cam->position.getValue() + + cam->focalDistance.getValue() * direction; + + // Set new orientation value by accumulating the new rotation. + cam->orientation = rot * cam->orientation.getValue(); + + // Reposition camera so we are still pointing at the same old focal point. + cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction); + cam->position = focalpoint - cam->focalDistance.getValue() * direction; + } + + static + void copyCameraSettings(SoCamera* cam1, SbRotation& rot_cam1, SbVec3f& pos_cam1, + SoCamera* cam2, SbRotation& rot_cam2, SbVec3f& pos_cam2) + { + // recompute the diff we have applied to the camera's orientation + SbRotation rot = cam1->orientation.getValue(); + SbRotation dif = rot * rot_cam1.inverse(); + rot_cam1 = rot; + + // copy the values + cam2->enableNotify(FALSE); + cam2->nearDistance = cam1->nearDistance; + cam2->farDistance = cam1->farDistance; + cam2->focalDistance = cam1->focalDistance; + reorientCamera(cam2,dif); + rot_cam2 = cam2->orientation.getValue(); + + // reverse engineer the translation part in wc + SbVec3f pos = cam1->position.getValue(); + SbVec3f difpos = pos - pos_cam1; + pos_cam1 = pos; + // the translation in pixel coords + cam1->orientation.getValue().inverse().multVec(difpos,difpos); + // the translation again in wc for the second camera + cam2->orientation.getValue().multVec(difpos,difpos); + cam2->position.setValue(cam2->position.getValue()+difpos); + + if (cam1->getTypeId() == cam2->getTypeId()) { + if (cam1->getTypeId() == SoOrthographicCamera::getClassTypeId()) + static_cast(cam2)->height = + static_cast(cam1)->height; + } + + cam2->enableNotify(TRUE); + } + static + void syncCameraCB(void * data, SoSensor * s) + { + ManualAlignment* self = reinterpret_cast(data); + if (!self->myViewer) + return; // already destroyed + SoCamera* cam1 = self->myViewer->getViewer(0)->getCamera(); + SoCamera* cam2 = self->myViewer->getViewer(1)->getCamera(); + if (!cam1 || !cam2) + return; // missing camera + SoNodeSensor* sensor = static_cast(s); + SoNode* node = sensor->getAttachedNode(); + if (node && node->getTypeId().isDerivedFrom(SoCamera::getClassTypeId())) { + if (node == cam1) { + Private::copyCameraSettings(cam1, self->d->rot_cam1, self->d->pos_cam1, + cam2, self->d->rot_cam2, self->d->pos_cam2); + self->myViewer->getViewer(1)->render(); + } + else if (node == cam2) { + Private::copyCameraSettings(cam2, self->d->rot_cam2, self->d->pos_cam2, + cam1, self->d->rot_cam1, self->d->pos_cam1); + self->myViewer->getViewer(0)->render(); + } + } + } + + static Base::Placement + transformation2x2(const Base::Vector3d& plane1_base, + const Base::Vector3d& plane1_xaxis, + const Base::Vector3d& plane2_base, + const Base::Vector3d& plane2_xaxis) + { + // the transformation is: + // * move from plane1_base to plane2_base + // * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point + Base::Rotation rot(plane1_xaxis, plane2_xaxis); + + Base::Vector3d pln_base; + rot.multVec(plane1_base,pln_base); + Base::Vector3d dif = plane2_base - pln_base; + return Base::Placement(dif, rot); + } + + static Base::Placement + transformation3x3(const Base::Vector3d& plane1_base, + const Base::Vector3d& plane1_zaxis, + const Base::Vector3d& plane1_xaxis, + const Base::Vector3d& plane2_base, + const Base::Vector3d& plane2_zaxis, + const Base::Vector3d& plane2_xaxis) + { + // the transformation is: + // * move from plane1_base to plane2_base + // * rotate from plane1_zaxis to plane2_zaxis around plane2_base as center point + Base::Rotation rot(plane1_zaxis, plane2_zaxis); + + // first transformation to align the plane normals and base points + Base::Vector3d dif1 = plane1_base; + rot.multVec(dif1,dif1); + dif1 = plane2_base - dif1; + Base::Placement plm1(dif1, rot); + + // second transformation to align the planes' x axes + Base::Vector3d pln_xaxis; + rot.multVec(plane1_xaxis,pln_xaxis); + Base::Rotation rot2(pln_xaxis, plane2_xaxis); + Base::Vector3d dif2 = plane2_base; + rot2.multVec(dif2,dif2); + dif2 = plane2_base - dif2; + Base::Placement plm2(dif2, rot2); + plm2 = plm2 * plm1; + return plm2; + } +}; + +/* TRANSLATOR Gui::ManualAlignment */ + +ManualAlignment* ManualAlignment::_instance = 0; + +/** + * Construction. + */ +ManualAlignment::ManualAlignment() + : myViewer(0), myDocument(0), myPickPoints(3), d(new Private) +{ + // connect with the application's signal for deletion of documents + this->connectApplicationDeletedDocument = Gui::Application::Instance->signalDeleteDocument + .connect(boost::bind(&ManualAlignment::slotDeletedDocument, this, _1)); + + // setup sensor connection + d->sensorCam1 = new SoNodeSensor(Private::syncCameraCB, this); + d->sensorCam2 = new SoNodeSensor(Private::syncCameraCB, this); +} + +/** + * Destruction. + */ +ManualAlignment::~ManualAlignment() +{ + this->connectDocumentDeletedObject.disconnect(); + this->connectApplicationDeletedDocument.disconnect(); + closeViewer(); + delete d; + _instance = 0; +} + +/** + * Creates the one and only instance of this class. + */ +ManualAlignment* ManualAlignment::instance() +{ + // not initialized? + if (!_instance) + _instance = new ManualAlignment(); + return _instance; +} + +/** + * Destructs the one and only instance of this class. + */ +void ManualAlignment::destruct() +{ + if (_instance) { + ManualAlignment* tmp = _instance; + _instance = 0; + delete tmp; + } +} + +/** + * Checks whether the one instance exists. + */ +bool ManualAlignment::hasInstance() +{ + return _instance != 0; +} + +void ManualAlignment::setMinPoints(int minPoints) +{ + if ((minPoints > 0) && (minPoints <= 3)) + myPickPoints = minPoints; +} + +void ManualAlignment::setFixedGroup(const FixedGroup& fixed) +{ + this->myFixedGroup = fixed; + this->myDocument = fixed.getDocument(); +} + +void ManualAlignment::setModel(const MovableGroupModel& model) +{ + this->myAlignModel = model; +} + +void ManualAlignment::clearAll() +{ + myFixedGroup.clear(); + myAlignModel.clear(); + myDocument = 0; +} + +void ManualAlignment::setViewingDirections(const Base::Vector3d& view1, const Base::Vector3d& up1, + const Base::Vector3d& view2, const Base::Vector3d& up2) +{ + if (myViewer.isNull()) + return; + + { + SbRotation rot; + rot.setValue(SbVec3f(0.0f, 0.0f, 1.0f), SbVec3f(-view1.x,-view1.y,-view1.z)); + + SbRotation rot2; + SbVec3f up(0.0f, 1.0f, 0.0f); + rot.multVec(up, up); + rot2.setValue(up, SbVec3f(up1.x, up1.y, up1.z)); + myViewer->getViewer(0)->getCamera()->orientation.setValue(rot * rot2); + myViewer->getViewer(0)->viewAll(); + } + + { + SbRotation rot; + rot.setValue(SbVec3f(0.0f, 0.0f, 1.0f), SbVec3f(-view2.x,-view2.y,-view2.z)); + + SbRotation rot2; + SbVec3f up(0.0f, 1.0f, 0.0f); + rot.multVec(up, up); + rot2.setValue(up, SbVec3f(up2.x, up2.y, up2.z)); + myViewer->getViewer(1)->getCamera()->orientation.setValue(rot * rot2); + myViewer->getViewer(1)->viewAll(); + } +} + +/** + * Performs the alignment for the specified aligned and non-aligned views specified by setModel() and setFixedGroup(). + */ +void ManualAlignment::startAlignment(Base::Type mousemodel) +{ + // allow only one alignment at a time + if (!myViewer.isNull()) { + QMessageBox::warning(qApp->activeWindow(), tr("Manual alignment"), tr("The alignment is already in progress.")); + return; + } + + myTransform = Base::Placement(); + + if (myFixedGroup.isEmpty()) + return; + if (myAlignModel.isEmpty()) + return; + + // create a splitted window for picking the points + myViewer = new AlignmentView(myDocument,Gui::getMainWindow()); + myViewer->setWindowTitle(tr("Alignment[*]")); + myViewer->setWindowIcon(QApplication::windowIcon()); + myViewer->resize(400, 300); + Gui::getMainWindow()->addWindow(myViewer); + myViewer->showMaximized(); + int n = this->myPickPoints; + QString msg = n == 1 + ? tr("Please, select at least one point in the left and the right view") + : tr("Please, select at least %1 points in the left and the right view").arg(n); + myViewer->myLabel->setText(msg); + + connect(myViewer, SIGNAL(destroyed()), this, SLOT(reset())); + + // show all aligned views in the 2nd view + myFixedGroup.addToViewer(myViewer->getViewer(1)); + myFixedGroup.setAlignable(true); + + // set picked points root + SoNode* node1 = myViewer->getViewer(0)->getSceneGraph(); + if (node1->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){ + ((SoGroup*)node1)->addChild(d->picksepLeft); + } + SoNode* node2 = myViewer->getViewer(1)->getSceneGraph(); + if (node2->getTypeId().isDerivedFrom(SoGroup::getClassTypeId())){ + ((SoGroup*)node2)->addChild(d->picksepRight); + } + + myViewer->getViewer(0)->setEditing(true); + myViewer->getViewer(0)->addEventCallback(SoMouseButtonEvent::getClassTypeId(), + ManualAlignment::probePickedCallback); + myViewer->getViewer(1)->setEditing(true); + myViewer->getViewer(1)->addEventCallback(SoMouseButtonEvent::getClassTypeId(), + ManualAlignment::probePickedCallback); + // apply the mouse model + myViewer->getViewer(0)->setNavigationType(mousemodel); + myViewer->getViewer(1)->setNavigationType(mousemodel); + + // Connect to the document's signal as we want to be notified when something happens + if (this->connectDocumentDeletedObject.connected()) + this->connectDocumentDeletedObject.disconnect(); + this->connectDocumentDeletedObject = myDocument->signalDeletedObject.connect(boost::bind + (&ManualAlignment::slotDeletedObject, this, _1)); + + continueAlignment(); +} + +/** + * If still one view needs to be aligned then it is shown in the first window. If all views are aligned the process will be terminated. + */ +void ManualAlignment::continueAlignment() +{ + myFixedGroup.clearPoints(); + d->picksepLeft->removeAllChildren(); + d->picksepRight->removeAllChildren(); + + if (!myAlignModel.isEmpty()) { + AlignmentGroup& grp = myAlignModel.activeGroup(); + grp.clearPoints(); + grp.addToViewer(myViewer->getViewer(0)); + grp.setAlignable(true); + + Gui::getMainWindow()->statusBar()->showMessage(tr("Please pick points in the left and right view")); + + myViewer->getViewer(0)->setEditingCursor(QCursor(Qt::PointingHandCursor)); + myViewer->getViewer(1)->setEditingCursor(QCursor(Qt::PointingHandCursor)); + } + else { + finish(); + } +} + +void ManualAlignment::closeViewer() +{ + if (!myViewer) + return; + // Close the viewer +#if !defined(NO_USE_QT_MDI_AREA) + if (myViewer->parentWidget()) + myViewer->parentWidget()->deleteLater(); +#else + myViewer->deleteLater(); +#endif + myViewer = 0; +} + +/** + * Make all views unpickable and resets internal data. + */ +void ManualAlignment::reset() +{ + if (!myAlignModel.isEmpty()) { + myAlignModel.activeGroup().setAlignable(false); + myAlignModel.activeGroup().clear(); + myAlignModel.clear(); + } + + myFixedGroup.setAlignable(false); + myFixedGroup.clear(); + + d->picksepLeft->removeAllChildren(); + d->picksepRight->removeAllChildren(); + + if (myDocument) { + this->connectDocumentDeletedObject.disconnect(); + myDocument = 0; + } +} + +/** + * Terminates the process and closes the windows. + */ +void ManualAlignment::finish() +{ + if (myViewer.isNull()) + return; + + if (myDocument) + myDocument->getDocument()->recompute(); + closeViewer(); + reset(); + + Gui::getMainWindow()->statusBar()->showMessage(tr("The alignment has finished")); + + // If an event receiver has been defined send the manual alignment finished event to it + emitFinished(); +} + +/** + * Cancels the process and clses the windows without performing an alignment. + */ +void ManualAlignment::cancel() +{ + if (myViewer.isNull()) + return; + + closeViewer(); + myTransform = Base::Placement(); + reset(); + + Gui::getMainWindow()->statusBar()->showMessage(tr("The alignment has been canceled")); + + // If an event receiver has been defined send the manual alignment cancelled event to it + emitCanceled(); +} + +void ManualAlignment::align() +{ + // Now we can start the actual alignment + if (myAlignModel.activeGroup().countPoints() < myPickPoints) { + QMessageBox::warning(myViewer, tr("Manual alignment"), + tr("Too few points picked in the left view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myFixedGroup.countPoints() < myPickPoints) { + QMessageBox::warning(myViewer, tr("Manual alignment"), + tr("Too few points picked in the right view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) { + QMessageBox::warning(myViewer, tr("Manual alignment"), + tr("Different number of points picked in left and right view.\n" + "On the left view %1 points are picked,\n" + "on the right view %2 points are picked.") + .arg(myAlignModel.activeGroup().countPoints()) + .arg(myFixedGroup.countPoints())); + } + else { + // do not allow to pick further points + myAlignModel.activeGroup().removeFromViewer(myViewer->getViewer(0)); + myAlignModel.activeGroup().setAlignable(false); + std::vector pViews = myAlignModel.activeGroup().getViews(); + Gui::getMainWindow()->statusBar()->showMessage(tr("Try to align group of views")); + + // Compute alignment + bool ok = computeAlignment(myAlignModel.activeGroup().getPoints(), myFixedGroup.getPoints()); + if (ok && myDocument) { + // Align views + myDocument->openCommand("Align"); + for (std::vector::iterator it = pViews.begin(); it != pViews.end(); ++it) + alignObject(*it); + myDocument->commitCommand(); + + // the alignment was successful so show it in the right view now + //myAlignModel.activeGroup().setRandomColor(); + myAlignModel.activeGroup().setAlignable(true); + myAlignModel.activeGroup().addToViewer(myViewer->getViewer(1)); + myAlignModel.activeGroup().moveTo(myFixedGroup); + myAlignModel.continueAlignment(); + } + else { + // Inform user that alignment failed + int ret = QMessageBox::critical(myViewer, tr("Manual alignment"), + tr("The alignment failed.\nHow do you want to proceed?"), + tr("Retry"), tr("Ignore"), tr("Abort")); + if ( ret == 1 ) { + myAlignModel.continueAlignment(); + } + else if ( ret == 2 ) { + finish(); + return; + } + } + + continueAlignment(); + } +} + +void ManualAlignment::showInstructions() +{ + // Now we can start the actual alignment + if (myAlignModel.activeGroup().countPoints() < myPickPoints) { + Gui::getMainWindow()->statusBar()->showMessage( + tr("Too few points picked in the left view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myFixedGroup.countPoints() < myPickPoints) { + Gui::getMainWindow()->statusBar()->showMessage( + tr("Too few points picked in the right view." + " At least %1 points are needed.").arg(myPickPoints)); + } + else if (myAlignModel.activeGroup().countPoints() != myFixedGroup.countPoints()) { + Gui::getMainWindow()->statusBar()->showMessage( + tr("Different number of points picked in left and right view. " + "On the left view %1 points are picked, " + "on the right view %2 points are picked.") + .arg(myAlignModel.activeGroup().countPoints()) + .arg(myFixedGroup.countPoints())); + } +} + +bool ManualAlignment::canAlign() const +{ + if (myAlignModel.activeGroup().countPoints() == myFixedGroup.countPoints()) { + if (myFixedGroup.countPoints() >= myPickPoints) + return true; + } + + return false; +} + +/** + * This method computes the alignment. For the calculation of the alignment the picked points of both views + * are taken. If the alignment fails false is returned, true otherwise. + */ +bool ManualAlignment::computeAlignment(const std::vector& movPts, + const std::vector& fixPts) +{ + assert((int)movPts.size() >= myPickPoints); + assert((int)fixPts.size() >= myPickPoints); + assert((int)movPts.size() == (int)fixPts.size()); + myTransform = Base::Placement(); + + if (movPts.size() == 1) { + // 1 point partial solution: Simple translation only + myTransform.setPosition(fixPts[0] - movPts[0]); + } + else if (movPts.size() == 2) { + const Base::Vector3d& p1 = movPts[0]; + const Base::Vector3d& p2 = movPts[1]; + Base::Vector3d d1 = p2-p1; + d1.Normalize(); + + const Base::Vector3d& q1 = fixPts[0]; + const Base::Vector3d& q2 = fixPts[1]; + Base::Vector3d d2 = q2-q1; + d2.Normalize(); + + myTransform = Private::transformation2x2(p1, d1, q1, d2); + } + else if (movPts.size() >= 3) { + const Base::Vector3d& p1 = movPts[0]; + const Base::Vector3d& p2 = movPts[1]; + const Base::Vector3d& p3 = movPts[2]; + Base::Vector3d d1 = p2-p1; + d1.Normalize(); + Base::Vector3d n1 = (p2-p1) % (p3-p1); + n1.Normalize(); + + const Base::Vector3d& q1 = fixPts[0]; + const Base::Vector3d& q2 = fixPts[1]; + const Base::Vector3d& q3 = fixPts[2]; + Base::Vector3d d2 = q2-q1; + d2.Normalize(); + Base::Vector3d n2 = (q2-q1) % (q3-q1); + n2.Normalize(); + + myTransform = Private::transformation3x3(p1, d1, n1, q1, d2, n2); + } + + return true; +} + +/** + * This method performs the actual alignment of view \a pView. + */ +void ManualAlignment::alignObject(App::DocumentObject *obj) +{ + if (obj->getTypeId().isDerivedFrom(App::GeoFeature::getClassTypeId())) { + App::GeoFeature* geom = static_cast(obj); + Base::Placement plm = geom->Placement.getValue(); + plm = this->myTransform * plm; + geom->Placement.setValue(plm); + } +} + +/** + * Creates a point element as visible feedback for the user. + */ +SoNode* ManualAlignment::pickedPointsSubGraph(const SbVec3f& p, const SbVec3f& n, int id) +{ + static const float color_table [10][3] = { + {1.0f,0.0f,0.0f}, // red + {0.0f,1.0f,0.0f}, // green + {0.0f,0.0f,1.0f}, // blue + {1.0f,1.0f,0.0f}, // yellow + {0.0f,1.0f,1.0f}, // cyan + {0.7f,0.0f,0.0f}, + {0.0f,0.7f,0.0f}, + {0.7f,0.7f,0.0f}, + {0.7f,0.0f,0.5f}, + {1.0f,0.7f,0.0f} + }; + + int index = (id-1) % 10; + + SoRegPoint* probe = new SoRegPoint(); + probe->base.setValue(p); + probe->normal.setValue(n); + probe->color.setValue(color_table[index][0],color_table[index][1],color_table[index][2]); + SbString s; + probe->text.setValue(s.sprintf("RegPoint_%d", id)); + return probe; +} + +/** + * Handle if the current document is about to being closed. + */ +void ManualAlignment::slotDeletedDocument(const Gui::Document& Doc) +{ + if (&Doc == this->myDocument) + reset(); +} + +/** + * Handle if the a view provider is about to being destroyed. + */ +void ManualAlignment::slotDeletedObject(const Gui::ViewProvider& Obj) +{ + // remove the view provider either from the left or the right view + if (Obj.getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) { + // remove the view provider immediately from the split window + bool found = false; + Gui::ViewProviderDocumentObject* vp = const_cast + (static_cast(&Obj)); + if (myAlignModel.activeGroup().hasView(vp)) { + myViewer->getViewer(0)->removeViewProvider(vp); + found = true; + } + if (myFixedGroup.hasView(vp)) { + myViewer->getViewer(1)->removeViewProvider(vp); + found = true; + } + + if (found) + cancel(); + } +} + +void ManualAlignment::onAlign() +{ + align(); +} + +void ManualAlignment::onRemoveLastPointMoveable() +{ + int nPoints = myAlignModel.activeGroup().countPoints(); + if (nPoints > 0) { + myAlignModel.activeGroup().removeLastPoint(); + d->picksepLeft->removeChild(nPoints-1); + } +} + +void ManualAlignment::onRemoveLastPointFixed() +{ + int nPoints = myFixedGroup.countPoints(); + if (nPoints > 0) { + myFixedGroup.removeLastPoint(); + d->picksepRight->removeChild(nPoints-1); + } +} + +void ManualAlignment::onClear() +{ + myAlignModel.activeGroup().clear(); + myFixedGroup.clear(); + + d->picksepLeft->removeAllChildren(); + d->picksepRight->removeAllChildren(); +} + +void ManualAlignment::onCancel() +{ + cancel(); +} + +void ManualAlignment::probePickedCallback(void * ud, SoEventCallback * n) +{ + Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData()); + const SoEvent* ev = n->getEvent(); + if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) { + // set as handled + n->getAction()->setHandled(); + n->setHandled(); + + const SoMouseButtonEvent * mbe = static_cast(ev); + if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) { + // if we are in 'align' mode then handle the click event + ManualAlignment* self = ManualAlignment::instance(); + // Get the closest point to the camera of the whole scene. + // This point doesn't need to be part of this view provider. + Gui::WaitCursor wc; + const SoPickedPoint * point = n->getPickedPoint(); + if (point) { + Gui::ViewProvider* vp = static_cast(view->getViewProviderByPath(point->getPath())); + if (vp && vp->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId())) { + Gui::ViewProviderDocumentObject* that = static_cast(vp); + self->applyPickedProbe(that, point); + + const SbVec3f& vec = point->getPoint(); + Gui::getMainWindow()->statusBar()->showMessage( + tr("Point picked at (%1,%2,%3)") + .arg(vec[0]).arg(vec[1]).arg(vec[2])); + } + } + else { + Gui::getMainWindow()->statusBar()->showMessage( + tr("No point was picked")); + } + } + else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) { + ManualAlignment* self = ManualAlignment::instance(); + if (self->myAlignModel.isEmpty() || self->myFixedGroup.isEmpty()) + return; + self->showInstructions(); + int nPoints; + if (view == self->myViewer->getViewer(0)) + nPoints = self->myAlignModel.activeGroup().countPoints(); + else + nPoints = self->myFixedGroup.countPoints(); + QMenu menu; + QAction* fi = menu.addAction(QLatin1String("&Align")); + QAction* rem = menu.addAction(QLatin1String("&Remove last point")); + //QAction* cl = menu.addAction("C&lear"); + QAction* ca = menu.addAction(QLatin1String("&Cancel")); + fi->setEnabled(self->canAlign()); + rem->setEnabled(nPoints > 0); + menu.addSeparator(); + QAction* sync = menu.addAction(QLatin1String("&Synchronize views")); + sync->setCheckable(true); + if (self->d->sensorCam1->getAttachedNode()) + sync->setChecked(true); + QAction* id = menu.exec(QCursor::pos()); + if (id == fi) { + // call align->align(); + QTimer::singleShot(300, self, SLOT(onAlign())); + } + else if ((id == rem) && (view == self->myViewer->getViewer(0))) { + QTimer::singleShot(300, self, SLOT(onRemoveLastPointMoveable())); + } + else if ((id == rem) && (view == self->myViewer->getViewer(1))) { + QTimer::singleShot(300, self, SLOT(onRemoveLastPointFixed())); + } + //else if (id == cl) { + // // call align->clear(); + // QTimer::singleShot(300, self, SLOT(onClear())); + //} + else if (id == ca) { + // call align->cancel(); + QTimer::singleShot(300, self, SLOT(onCancel())); + } + else if (id == sync) { + // setup sensor connection + if (sync->isChecked()) { + SoCamera* cam1 = self->myViewer->getViewer(0)->getCamera(); + SoCamera* cam2 = self->myViewer->getViewer(1)->getCamera(); + if (cam1 && cam2) { + self->d->sensorCam1->attach(cam1); + self->d->rot_cam1 = cam1->orientation.getValue(); + self->d->pos_cam1 = cam1->position.getValue(); + self->d->sensorCam2->attach(cam2); + self->d->rot_cam2 = cam2->orientation.getValue(); + self->d->pos_cam2 = cam2->position.getValue(); + } + } + else { + self->d->sensorCam1->detach(); + self->d->sensorCam2->detach(); + } + } + } + } +} + +/** + * This method stores the picked point \a pnt from the view provider \a prov. If enough points in both windows have been picked + * the alignment gets invoked. + */ +void ManualAlignment::applyPickedProbe(Gui::ViewProviderDocumentObject* prov, const SoPickedPoint* pnt) +{ + const SbVec3f& vec = pnt->getPoint(); + const SbVec3f& nor = pnt->getNormal(); + + // add to the list for the non-aligned view in the left view + if (myAlignModel.activeGroup().hasView(prov)) { + myAlignModel.activeGroup().addPoint(Base::Vector3d(vec[0],vec[1],vec[2])); + // Adds a point marker for the picked point. + d->picksepLeft->addChild(pickedPointsSubGraph(vec, nor, myAlignModel.activeGroup().countPoints())); + } + else if (myFixedGroup.hasView(prov)) { + myFixedGroup.addPoint(Base::Vector3d(vec[0],vec[1],vec[2])); + // Adds a point marker for the picked point. + d->picksepRight->addChild(pickedPointsSubGraph(vec, nor, myFixedGroup.countPoints())); + } +} + +#include "moc_ManualAlignment.cpp" + diff --git a/src/Gui/ManualAlignment.h b/src/Gui/ManualAlignment.h new file mode 100644 index 0000000000..78a93391fe --- /dev/null +++ b/src/Gui/ManualAlignment.h @@ -0,0 +1,257 @@ +/*************************************************************************** + * Copyright (c) 2012 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 * + * * + ***************************************************************************/ + + +#ifndef GUI_MANUALALIGNMENT_H +#define GUI_MANUALALIGNMENT_H + +#include +#include +#include +#include +#include +#include + +class SbVec3f; +class SoPickedPoint; +class SoEventCallback; + +namespace Gui { +class Document; +class AlignmentView; +class View3DInventorViewer; + +/** + * The AlignemntGroup class is the base for fixed and movable groups. + * @author Werner Mayer + */ +class GuiExport AlignmentGroup +{ +protected: + AlignmentGroup(); + ~AlignmentGroup(); + +public: + /** + * Add a mesh to the group. + */ + void addView(App::DocumentObject*); + std::vector getViews() const; + /** + * Checks for the view provider of one of the added views. + */ + bool hasView(Gui::ViewProviderDocumentObject*) const; + /** + * Remove a previously added view by its view provider. + */ + void removeView(Gui::ViewProviderDocumentObject*); + /** + * Add the group and therefore all its added view providers to the Inventor tree. + */ + void addToViewer(Gui::View3DInventorViewer*) const; + /** + * Remove all the view providers from the Inventor tree. + */ + void removeFromViewer(Gui::View3DInventorViewer*) const; + void setRandomColor(); + /** + * Returns the document of the added views. + */ + Gui::Document* getDocument() const; + /** + * Add a point to an array of picked points. + */ + void addPoint(const Base::Vector3d&); + /** + * Remove last point from array of picked points. + */ + void removeLastPoint(); + /** + * Count the number of picked points. + */ + int countPoints() const; + /** + * Return an array of picked points. + */ + const std::vector& getPoints() const; + /** + * Clear all picked points. + */ + void clearPoints(); + /** + * Set or unset the alignable mode for the added views. If a view is not alignable it also not pickable. + */ + void setAlignable(bool); + void moveTo(AlignmentGroup&); + /** + * Clear the list of added views. + */ + void clear(); + /** + * Checks whether the list of added views is empty or not. + */ + bool isEmpty() const; + /** + * Return the number of added views. + */ + int count() const; + +protected: + std::vector _pickedPoints; + std::vector _views; +}; + +/** + * The FixedGroup class can be used for a fixed group of views. + * @author Werner Mayer + */ +class GuiExport MovableGroup : public AlignmentGroup +{ +public: + MovableGroup(); + ~MovableGroup(); +}; + +/** + * The FixedGroup class can be used for a fixed group of views. + * @author Werner Mayer + */ +class GuiExport FixedGroup : public AlignmentGroup +{ +public: + FixedGroup(); + ~FixedGroup(); +}; + +/** + * The MovableGroupModel class keeps an array of movable groups. + * @author Werner Mayer + */ +class GuiExport MovableGroupModel +{ +public: + MovableGroupModel(); + ~MovableGroupModel(); + + void addGroup(const MovableGroup&); + void addGroups(const std::map&); + MovableGroup& activeGroup(); + const MovableGroup& activeGroup() const; + void continueAlignment(); + void clear(); + bool isEmpty() const; + int count() const; + +protected: + void removeActiveGroup(); + +private: + std::vector _groups; +}; + +/** + * @author Werner Mayer + */ +class GuiExport ManualAlignment : public QObject +{ + Q_OBJECT + +protected: + ManualAlignment(); + ~ManualAlignment(); + +public: + static ManualAlignment* instance(); + static void destruct(); + static bool hasInstance(); + + void setMinPoints(int minPoints); + void setFixedGroup(const FixedGroup&); + void setModel(const MovableGroupModel&); + void clearAll(); + + void setViewingDirections(const Base::Vector3d& view1, const Base::Vector3d& up1, + const Base::Vector3d& view2, const Base::Vector3d& up2); + void startAlignment(Base::Type mousemodel); + void finish(); + void align(); + bool canAlign() const; + void cancel(); + + const Base::Placement & getTransform() const + { return myTransform; } + void alignObject(App::DocumentObject*); + + // Observer stuff + /// Checks if the given object is about to be removed + void slotDeletedDocument(const Gui::Document& Doc); + /// Checks if the given document is about to be closed + void slotDeletedObject(const Gui::ViewProvider& Obj); + +protected: + bool computeAlignment(const std::vector& unnavPts, const std::vector& navigPts); + void continueAlignment(); + void showInstructions(); + /** @name Probe picking */ + //@{ + static void probePickedCallback(void * ud, SoEventCallback * n); + void applyPickedProbe(Gui::ViewProviderDocumentObject*, const SoPickedPoint* pnt); + //@} + +protected Q_SLOTS: + void reset(); + void onAlign(); + void onRemoveLastPointMoveable(); + void onRemoveLastPointFixed(); + void onClear(); + void onCancel(); + +Q_SIGNALS: + void emitCanceled(); + void emitFinished(); + +private: + SoNode* pickedPointsSubGraph(const SbVec3f& p, const SbVec3f& n, int id); + void closeViewer(); + + static ManualAlignment* _instance; + + typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection; + Connection connectApplicationDeletedDocument; + Connection connectDocumentDeletedObject; + + FixedGroup myFixedGroup; + MovableGroupModel myAlignModel; + QPointer myViewer; + Gui::Document* myDocument; + int myPickPoints; + Base::Placement myTransform; + + class Private; + Private* d; +}; + +} // namespace Gui + + +#endif // GUI_MANUALALIGNMENT_H + diff --git a/src/Gui/MergeDocuments.cpp b/src/Gui/MergeDocuments.cpp index a1fc7172a7..52713fa474 100644 --- a/src/Gui/MergeDocuments.cpp +++ b/src/Gui/MergeDocuments.cpp @@ -122,16 +122,13 @@ MergeDocuments::importObjects(std::istream& input) reader.readElement("Object"); std::string type = reader.getAttribute("type"); std::string name = reader.getAttribute("name"); - std::string docn = name; - - // remove number from end to avoid lengthy names - size_t lastpos = docn.length()-1; - while (docn[lastpos] >= 48 && docn[lastpos] <= 57) - lastpos--; - docn = docn.substr(0, lastpos+1); try { - App::DocumentObject* o = appdoc->addObject(type.c_str(),docn.c_str()); + // Use name from XML as is and do NOT remove trailing digits because + // otherwise we may cause a dependency to itself + // Example: Object 'Cut001' references object 'Cut' and removing the + // digits we make an object 'Cut' referencing itself. + App::DocumentObject* o = appdoc->addObject(type.c_str(),name.c_str()); objs.push_back(o); // use this name for the later access because an object with // the given name may already exist @@ -235,4 +232,8 @@ void MergeDocuments::RestoreDocFile(Base::Reader & reader) } xmlReader.readEndElement("Document"); + + // In the file GuiDocument.xml new data files might be added + if (!xmlReader.getFilenames().empty()) + xmlReader.readFiles(static_cast(reader)); } diff --git a/src/Gui/MouseSelection.cpp b/src/Gui/MouseSelection.cpp index 065b885cc5..97262f6018 100644 --- a/src/Gui/MouseSelection.cpp +++ b/src/Gui/MouseSelection.cpp @@ -495,6 +495,7 @@ int RectangleSelection::mouseButtonEvent( const SoMouseButtonEvent * const e, co { releaseMouseModel(); m_bWorking = false; + _clPoly.push_back(e->getPosition()); ret = Finish; } break; default: diff --git a/src/Gui/MouseSelection.h b/src/Gui/MouseSelection.h index eeb41f2d19..fd8716e728 100644 --- a/src/Gui/MouseSelection.h +++ b/src/Gui/MouseSelection.h @@ -88,8 +88,6 @@ protected: int m_iXnew, m_iYnew; SbBool m_bInner; SbBool mustRedraw; - -private: std::vector _clPoly; }; diff --git a/src/Gui/NavigationStyle.cpp b/src/Gui/NavigationStyle.cpp index 8a44dd6677..30f5ecf402 100644 --- a/src/Gui/NavigationStyle.cpp +++ b/src/Gui/NavigationStyle.cpp @@ -721,6 +721,16 @@ void NavigationStyle::zoomByCursor(const SbVec2f & thispos, const SbVec2f & prev zoom(viewer->getCamera(), (thispos[1] - prevpos[1]) * 10.0f/*20.0f*/); } +void NavigationStyle::zoomIn() +{ + zoom(viewer->getCamera(), -this->zoomStep); +} + +void NavigationStyle::zoomOut() +{ + zoom(viewer->getCamera(), this->zoomStep); +} + void NavigationStyle::doZoom(SoCamera* camera, SbBool forward, const SbVec2f& pos) { SbBool zoomAtCur = this->zoomAtCursor; @@ -1140,6 +1150,37 @@ SbBool NavigationStyle::processSoEvent(const SoEvent * const ev) return viewer->processSoEventBase(ev); } +SbBool NavigationStyle::processMotionEvent(const SoMotion3Event * const ev) +{ + SoCamera * const camera = viewer->getCamera(); + if (!camera) + return FALSE; + + SbViewVolume volume(camera->getViewVolume()); + SbVec3f center(volume.getSightPoint(camera->focalDistance.getValue())); + float scale(volume.getWorldToScreenScale(center, 1.0)); + float translationFactor = scale * .0001; + + SbVec3f dir = ev->getTranslation(); + + if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){ + SoOrthographicCamera *oCam = static_cast(camera); + oCam->scaleHeight(1.0 + (dir[2] * 0.0001)); + dir[2] = 0.0;//don't move the cam for z translation. + } + + SbRotation newRotation(ev->getRotation() * camera->orientation.getValue()); + SbVec3f newPosition, newDirection; + newRotation.multVec(SbVec3f(0.0, 0.0, -1.0), newDirection); + newPosition = center - (newDirection * camera->focalDistance.getValue()); + + camera->orientation.setValue(newRotation); + camera->orientation.getValue().multVec(dir,dir); + camera->position = newPosition + (dir * translationFactor); + + return TRUE; +} + void NavigationStyle::setPopupMenuEnabled(const SbBool on) { this->menuenabled = on; diff --git a/src/Gui/NavigationStyle.h b/src/Gui/NavigationStyle.h index 846e65f869..b6d4e20e66 100644 --- a/src/Gui/NavigationStyle.h +++ b/src/Gui/NavigationStyle.h @@ -38,6 +38,7 @@ // forward declarations class SoEvent; +class SoMotion3Event; class SoQtViewer; class SoCamera; class SoSensor; @@ -90,10 +91,10 @@ public: Clip = 3, /**< Clip objects using a lasso. */ }; - enum OrbitStyle { - Turntable, - Trackball - }; + enum OrbitStyle { + Turntable, + Trackball + }; public: NavigationStyle(); @@ -114,6 +115,8 @@ public: void setZoomStep(float); void setZoomAtCursor(SbBool); SbBool isZoomAtCursor() const; + void zoomIn(); + void zoomOut(); void updateAnimation(); void redraw(); @@ -126,6 +129,7 @@ public: void setViewingMode(const ViewerMode newmode); int getViewingMode() const; virtual SbBool processEvent(const SoEvent * const ev); + virtual SbBool processMotionEvent(const SoMotion3Event * const ev); void setPopupMenuEnabled(const SbBool on); SbBool isPopupMenuEnabled(void) const; diff --git a/src/Gui/OnlineDocumentation.cpp b/src/Gui/OnlineDocumentation.cpp index 9f8032b893..985b9c0d12 100644 --- a/src/Gui/OnlineDocumentation.cpp +++ b/src/Gui/OnlineDocumentation.cpp @@ -232,9 +232,10 @@ QByteArray PythonOnlineHelp::loadResource(const QString& filename) const " return self.bigsection(dir, '#ffffff', '#ee77aa', contents)\n" "\n" "pydoc.html=FreeCADDoc()\n" + "title='FreeCAD Python Modules Index'\n" "\n" - "heading = pydoc.html.heading(\n" - "'Python: Index of Modules',\n" + "heading = pydoc.html.heading(" + "'Python: Index of Modules'," "'#ffffff', '#7799ee')\n" "def bltinlink(name):\n" " return '%s' % (name, name)\n" @@ -257,13 +258,16 @@ QByteArray PythonOnlineHelp::loadResource(const QString& filename) const " indices.append(ret)\n" "contents = heading + string.join(indices) + '''

\n" "\n" - "pydoc by Ka-Ping Yee <ping@lfw.org>'''\n"; + "pydoc by Ka-Ping Yee <ping@lfw.org>'''\n" + "htmldocument=pydoc.html.page(title,contents)\n"; PyObject* result = PyRun_String(cmd.constData(), Py_file_input, dict, dict); if (result) { Py_DECREF(result); - result = PyDict_GetItemString(dict, "contents"); + result = PyDict_GetItemString(dict, "htmldocument"); const char* contents = PyString_AsString(result); + res.append("HTTP/1.0 200 OK\n"); + res.append("Content-type: text/html\n"); res.append(contents); return res; } @@ -293,6 +297,8 @@ QByteArray PythonOnlineHelp::loadResource(const QString& filename) const Py_DECREF(result); result = PyDict_GetItemString(dict, "page"); const char* page = PyString_AsString(result); + res.append("HTTP/1.0 200 OK\n"); + res.append("Content-type: text/html\n"); res.append(page); } else { diff --git a/src/Gui/Placement.cpp b/src/Gui/Placement.cpp index d8c3d627d7..091c105122 100644 --- a/src/Gui/Placement.cpp +++ b/src/Gui/Placement.cpp @@ -48,6 +48,16 @@ public: bool operator () (const std::pair& elem) const { if (elem.first == propertyname) { + // flag set that property is read-only or hidden + if (elem.second->StatusBits.test(2) || elem.second->StatusBits.test(3)) + return false; + App::PropertyContainer* parent = elem.second->getContainer(); + if (parent) { + // flag set that property is read-only or hidden + if (parent->isReadOnly(elem.second) || + parent->isHidden(elem.second)) + return false; + } return elem.second->isDerivedFrom (Base::Type::fromName("App::PropertyPlacement")); } diff --git a/src/Gui/PythonEditor.cpp b/src/Gui/PythonEditor.cpp index c79a518144..5b448633a6 100644 --- a/src/Gui/PythonEditor.cpp +++ b/src/Gui/PythonEditor.cpp @@ -61,7 +61,7 @@ struct PythonEditorP colormap[QLatin1String("Operator")] = QColor(160, 160, 164); colormap[QLatin1String("Python output")] = QColor(170, 170, 127); colormap[QLatin1String("Python error")] = Qt::red; - colormap[QLatin1String("Line")] = QColor(224,224,224); + colormap[QLatin1String("Current line highlight")] = QColor(224,224,224); } }; } // namespace Gui diff --git a/src/Gui/SelectionObject.h b/src/Gui/SelectionObject.h index 784b89f27d..5c871594c6 100644 --- a/src/Gui/SelectionObject.h +++ b/src/Gui/SelectionObject.h @@ -55,11 +55,11 @@ public: /// are there any SubNames selected bool hasSubNames(void)const { return SubNames.size() != 0; } /// get the name of the Document of this SelctionObject - inline const char* getDocName(void) { return DocName.c_str(); } + inline const char* getDocName(void) const { return DocName.c_str(); } /// get the name of the Document Object of this SelectionObject - inline const char* getFeatName(void) { return FeatName.c_str(); } + inline const char* getFeatName(void) const { return FeatName.c_str(); } /// get the Type of the selcted Object - inline const char* getTypeName(void) { return TypeName.c_str(); } + inline const char* getTypeName(void) const { return TypeName.c_str(); } /// returns the selected DocumentObject or NULL if the object is already deleted const App::DocumentObject *getObject(void) const; diff --git a/src/Gui/SoAxisCrossKit.cpp b/src/Gui/SoAxisCrossKit.cpp index 6eed7457de..d05f856702 100644 --- a/src/Gui/SoAxisCrossKit.cpp +++ b/src/Gui/SoAxisCrossKit.cpp @@ -24,20 +24,34 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# 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 #endif @@ -217,3 +231,129 @@ SoAxisCrossKit::createAxes() set("zAxis.pickStyle", "style UNPICKABLE"); set("zHead.pickStyle", "style UNPICKABLE"); } + +// -------------------------------------------------------------- + +SO_NODE_SOURCE(SoRegPoint); + +void SoRegPoint::initClass() +{ + SO_NODE_INIT_CLASS(SoRegPoint, SoShape, "Shape"); +} + +SoRegPoint::SoRegPoint() +{ + SO_NODE_CONSTRUCTOR(SoRegPoint); + + SO_NODE_ADD_FIELD(base, (SbVec3f(0,0,0))); + SO_NODE_ADD_FIELD(normal, (SbVec3f(1,1,1))); + SO_NODE_ADD_FIELD(length, (3.0)); + SO_NODE_ADD_FIELD(color, (1.0f, 0.447059f, 0.337255f)); + SO_NODE_ADD_FIELD(text, ("")); + + root = new SoSeparator(); + root->ref(); + + // translation + SoTranslation* move = new SoTranslation(); + move->translation.setValue(base.getValue() + normal.getValue() * length.getValue()); + root->addChild(move); + + // sub-group + SoBaseColor* col = new SoBaseColor(); + col->rgb.setValue(this->color.getValue()); + + SoFontStyle* font = new SoFontStyle; + font->size = 14; + + SoSeparator* sub = new SoSeparator(); + sub->addChild(col); + sub->addChild(font); + sub->addChild(new SoText2()); + root->addChild(sub); +} + +SoRegPoint::~SoRegPoint() +{ + root->unref(); +} + +/** + * Renders the probe with text label and a bullet at the base point. + */ +void SoRegPoint::GLRender(SoGLRenderAction *action) +{ + if (shouldGLRender(action)) + { + SoState* state = action->getState(); + state->push(); + SoMaterialBundle mb(action); + SoTextureCoordinateBundle tb(action, TRUE, FALSE); + SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR); + mb.sendFirst(); // make sure we have the correct material + + SbVec3f p1 = base.getValue(); + SbVec3f p2 = p1 + normal.getValue() * length.getValue(); + + glLineWidth(1.0f); + glColor3fv(color.getValue().getValue()); + glBegin(GL_LINE_STRIP); + glVertex3d(p1[0], p1[1], p1[2]); + glVertex3d(p2[0], p2[1], p2[2]); + glEnd(); + glPointSize(5.0f); + glBegin(GL_POINTS); + glVertex3fv(p1.getValue()); + glEnd(); + glPointSize(2.0f); + glBegin(GL_POINTS); + glVertex3fv(p2.getValue()); + glEnd(); + + root->GLRender(action); + state->pop(); + } +} + +void SoRegPoint::generatePrimitives(SoAction* action) +{ +} + +/** + * Sets the bounding box of the probe to \a box and its center to \a center. + */ +void SoRegPoint::computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er) +{ + root->doAction(action); + if (action->getTypeId().isDerivedFrom(SoGetBoundingBoxAction::getClassTypeId())) + static_cast(action)->resetCenter(); + + SbVec3f p1 = base.getValue(); + SbVec3f p2 = p1 + normal.getValue() * length.getValue(); + + box.extendBy(p1); + box.extendBy(p2); + + center = box.getCenter(); +} + +void SoRegPoint::notify(SoNotList * node) +{ + SoField * f = node->getLastField(); + if (f == &this->base || f == &this->normal || f == &this->length) { + SoTranslation* move = static_cast(root->getChild(0)); + move->translation.setValue(base.getValue() + normal.getValue() * length.getValue()); + } + else if (f == &this->color) { + SoSeparator* sub = static_cast(root->getChild(1)); + SoBaseColor* col = static_cast(sub->getChild(0)); + col->rgb = this->color.getValue(); + } + else if (f == &this->text) { + SoSeparator* sub = static_cast(root->getChild(1)); + SoText2* label = static_cast(sub->getChild(2)); + label->string = this->text.getValue(); + } + + SoShape::notify(node); +} diff --git a/src/Gui/SoAxisCrossKit.h b/src/Gui/SoAxisCrossKit.h index bb1a24934e..488c51ee82 100644 --- a/src/Gui/SoAxisCrossKit.h +++ b/src/Gui/SoAxisCrossKit.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include class SbViewport; class SoState; @@ -84,6 +86,33 @@ private: virtual ~SoAxisCrossKit(); }; +class GuiExport SoRegPoint : public SoShape { + typedef SoShape inherited; + + SO_NODE_HEADER(SoRegPoint); + +public: + static void initClass(); + SoRegPoint(); + + void notify(SoNotList * node); + + SoSFVec3f base; + SoSFVec3f normal; + SoSFFloat length; + SoSFColor color; + SoSFString text; + +protected: + virtual ~SoRegPoint(); + virtual void GLRender(SoGLRenderAction *action); + virtual void computeBBox(SoAction *action, SbBox3f &box, SbVec3f ¢er); + virtual void generatePrimitives(SoAction *action); + +private: + SoSeparator* root; +}; + } // namespace Gui #endif // GUI_SOSHAPESCALE_H diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index 46435be068..ddf074ca11 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -95,6 +95,7 @@ void Gui::SoFCDB::init() TranslateManip ::initClass(); SoShapeScale ::initClass(); SoAxisCrossKit ::initClass(); + SoRegPoint ::initClass(); SoDrawingGrid ::initClass(); PropertyItem ::init(); diff --git a/src/Gui/SplitView3DInventor.cpp b/src/Gui/SplitView3DInventor.cpp index be874b05c8..7014aaa77a 100644 --- a/src/Gui/SplitView3DInventor.cpp +++ b/src/Gui/SplitView3DInventor.cpp @@ -41,40 +41,29 @@ using namespace Gui; -SplitView3DInventor::SplitView3DInventor( int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags ) - : MDIView( pcDocument,parent, wflags) +TYPESYSTEM_SOURCE_ABSTRACT(Gui::AbstractSplitView,Gui::MDIView); + +AbstractSplitView::AbstractSplitView(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags) + : MDIView(pcDocument,parent, wflags) { // important for highlighting setMouseTracking(true); - +} + +AbstractSplitView::~AbstractSplitView() +{ + hGrp->Detach(this); + for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) { + delete *it; + } +} + +void AbstractSplitView::setupSettings() +{ // attach Parameter Observer hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); hGrp->Attach(this); - QSplitter* mainSplitter=0; - - if (views <= 3) { - mainSplitter = new QSplitter(Qt::Horizontal, this); - _viewer.push_back(new View3DInventorViewer(mainSplitter)); - _viewer.push_back(new View3DInventorViewer(mainSplitter)); - if (views==3) - _viewer.push_back(new View3DInventorViewer(mainSplitter)); - } - else { - mainSplitter = new QSplitter(Qt::Vertical, this); - QSplitter *topSplitter = new QSplitter(Qt::Horizontal, mainSplitter); - QSplitter *botSplitter = new QSplitter(Qt::Horizontal, mainSplitter); - _viewer.push_back(new View3DInventorViewer(topSplitter)); - _viewer.push_back(new View3DInventorViewer(topSplitter)); - for (int i=2;isetOpaqueResize( true ); - botSplitter->setOpaqueResize( true ); - } - - mainSplitter->show(); - setCentralWidget(mainSplitter); - // apply the user settings OnChange(*hGrp,"EyeDistance"); OnChange(*hGrp,"CornerCoordSystem"); @@ -98,21 +87,13 @@ SplitView3DInventor::SplitView3DInventor( int views, Gui::Document* pcDocument, OnChange(*hGrp,"NavigationStyle"); } -SplitView3DInventor::~SplitView3DInventor() -{ - hGrp->Detach(this); - for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) { - delete *it; - } -} - -View3DInventorViewer* SplitView3DInventor::getViewer(unsigned int n) const +View3DInventorViewer* AbstractSplitView::getViewer(unsigned int n) const { return (_viewer.size() > n ? _viewer[n] : 0); } /// Observer message from the ParameterGrp -void SplitView3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason) +void AbstractSplitView::OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason) { const ParameterGrp& rGrp = static_cast(rCaller); if (strcmp(Reason,"HeadlightColor") == 0) { @@ -264,17 +245,17 @@ void SplitView3DInventor::OnChange(ParameterGrp::SubjectType &rCaller,ParameterG } } -void SplitView3DInventor::onUpdate(void) +void AbstractSplitView::onUpdate(void) { update(); } -const char *SplitView3DInventor::getName(void) const +const char *AbstractSplitView::getName(void) const { return "SplitView3DInventor"; } -bool SplitView3DInventor::onMsg(const char* pMsg, const char** ppReturn) +bool AbstractSplitView::onMsg(const char* pMsg, const char** ppReturn) { if (strcmp("ViewFit",pMsg) == 0 ) { for (std::vector::iterator it = _viewer.begin(); it != _viewer.end(); ++it) @@ -344,7 +325,7 @@ bool SplitView3DInventor::onMsg(const char* pMsg, const char** ppReturn) return false; } -bool SplitView3DInventor::onHasMsg(const char* pMsg) const +bool AbstractSplitView::onHasMsg(const char* pMsg) const { if (strcmp("ViewFit",pMsg) == 0) { return true; @@ -373,7 +354,46 @@ bool SplitView3DInventor::onHasMsg(const char* pMsg) const return false; } -void SplitView3DInventor::setCursor(const QCursor& aCursor) +void AbstractSplitView::setCursor(const QCursor& aCursor) { //_viewer->getWidget()->setCursor(aCursor); } + +// ------------------------------------------------------ + +TYPESYSTEM_SOURCE_ABSTRACT(Gui::SplitView3DInventor, Gui::AbstractSplitView); + +SplitView3DInventor::SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags) + : AbstractSplitView(pcDocument,parent, wflags) +{ + QSplitter* mainSplitter=0; + + if (views <= 3) { + mainSplitter = new QSplitter(Qt::Horizontal, this); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + if (views==3) + _viewer.push_back(new View3DInventorViewer(mainSplitter)); + } + else { + mainSplitter = new QSplitter(Qt::Vertical, this); + QSplitter *topSplitter = new QSplitter(Qt::Horizontal, mainSplitter); + QSplitter *botSplitter = new QSplitter(Qt::Horizontal, mainSplitter); + _viewer.push_back(new View3DInventorViewer(topSplitter)); + _viewer.push_back(new View3DInventorViewer(topSplitter)); + for (int i=2;isetOpaqueResize( true ); + botSplitter->setOpaqueResize( true ); + } + + mainSplitter->show(); + setCentralWidget(mainSplitter); + + // apply the user settings + setupSettings(); +} + +SplitView3DInventor::~SplitView3DInventor() +{ +} diff --git a/src/Gui/SplitView3DInventor.h b/src/Gui/SplitView3DInventor.h index c10da630db..de7254ec49 100644 --- a/src/Gui/SplitView3DInventor.h +++ b/src/Gui/SplitView3DInventor.h @@ -36,11 +36,13 @@ class View3DInventorViewer; /** The SplitView3DInventor class allows to create a window with two or more Inventor views. * \author Werner Mayer */ -class GuiExport SplitView3DInventor : public MDIView,public ParameterGrp::ObserverType +class GuiExport AbstractSplitView : public MDIView, public ParameterGrp::ObserverType { + TYPESYSTEM_HEADER(); + public: - SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0); - ~SplitView3DInventor(); + AbstractSplitView(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0); + ~AbstractSplitView(); virtual const char *getName(void) const; @@ -54,14 +56,27 @@ public: void setCursor(const QCursor&); +protected: + void setupSettings(); + protected: /// handle to the viewer parameter group ParameterGrp::handle hGrp; - -private: std::vector _viewer; }; +/** The SplitView3DInventor class allows to create a window with two or more Inventor views. + * \author Werner Mayer + */ +class GuiExport SplitView3DInventor : public AbstractSplitView +{ + TYPESYSTEM_HEADER(); + +public: + SplitView3DInventor(int views, Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags=0); + ~SplitView3DInventor(); +}; + } // namespace Gui #endif //GUI_SPLITVIEW3DINVENTOR_H diff --git a/src/Gui/TaskView/TaskAppearance.ui b/src/Gui/TaskView/TaskAppearance.ui index 7955494699..e775af457c 100644 --- a/src/Gui/TaskView/TaskAppearance.ui +++ b/src/Gui/TaskView/TaskAppearance.ui @@ -33,7 +33,7 @@ - Display mode: + Document window: diff --git a/src/Gui/TextEdit.cpp b/src/Gui/TextEdit.cpp index 75fb88c1d4..bbb06d8b68 100644 --- a/src/Gui/TextEdit.cpp +++ b/src/Gui/TextEdit.cpp @@ -192,7 +192,7 @@ struct TextEditorP colormap[QLatin1String("Operator")] = QColor(160, 160, 164); colormap[QLatin1String("Python output")] = QColor(170, 170, 127); colormap[QLatin1String("Python error")] = Qt::red; - colormap[QLatin1String("Line")] = QColor(224,224,224); + colormap[QLatin1String("Current line highlight")] = QColor(224,224,224); } }; } // namespace Gui @@ -272,8 +272,11 @@ void TextEditor::highlightCurrentLine() if (!isReadOnly()) { QTextEdit::ExtraSelection selection; - QColor lineColor = d->colormap[QLatin1String("Line")]; - + QColor lineColor = d->colormap[QLatin1String("Current line highlight")]; + unsigned long col = (lineColor.red() << 24) | (lineColor.green() << 16) | (lineColor.blue() << 8); + ParameterGrp::handle hPrefGrp = getWindowParameter(); + col = hPrefGrp->GetUnsigned( "Current line highlight", col); + lineColor.setRgb((col>>24)&0xff, (col>>16)&0xff, (col>>8)&0xff); selection.format.setBackground(lineColor); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); diff --git a/src/Gui/TouchpadNavigationStyle.cpp b/src/Gui/TouchpadNavigationStyle.cpp index 530b0650d4..e33323c33b 100644 --- a/src/Gui/TouchpadNavigationStyle.cpp +++ b/src/Gui/TouchpadNavigationStyle.cpp @@ -79,10 +79,10 @@ const char* TouchpadNavigationStyle::mouseButtons(ViewerMode mode) SbBool TouchpadNavigationStyle::processSoEvent(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 inherited::processSoEvent(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 inherited::processSoEvent(ev); } const SoType type(ev->getTypeId()); @@ -265,20 +265,9 @@ SbBool TouchpadNavigationStyle::processSoEvent(const SoEvent * const ev) // Spaceball & Joystick handling if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) { - SoMotion3Event * const event = (SoMotion3Event *) ev; - SoCamera * const camera = viewer->getCamera(); - - SbVec3f dir = event->getTranslation(); - if (camera->getTypeId().isDerivedFrom(SoOrthographicCamera::getClassTypeId())){ - static float zoomConstant(-.03f); - dir[2] = 0.0;//don't move the cam for z translation. - - SoOrthographicCamera *oCam = static_cast(camera); - oCam->scaleHeight(1.0-event->getTranslation()[2] * zoomConstant); - } - camera->orientation.getValue().multVec(dir,dir); - camera->position = camera->position.getValue() + dir; - camera->orientation = event->getRotation() * camera->orientation.getValue(); + const SoMotion3Event * const event = static_cast(ev); + if (event) + this->processMotionEvent(event); processed = TRUE; } diff --git a/src/Gui/Tree.cpp b/src/Gui/Tree.cpp index 9d19c5b639..48d27f3256 100644 --- a/src/Gui/Tree.cpp +++ b/src/Gui/Tree.cpp @@ -253,6 +253,8 @@ void TreeWidget::onStartEditing() App::DocumentObject* obj = objitem->object()->getObject(); if (!obj) return; Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument()); + MDIView *view = doc->getActiveView(); + if (view) getMainWindow()->setActiveWindow(view); doc->setEdit(objitem->object(), edit); } } @@ -306,7 +308,12 @@ void TreeWidget::mouseDoubleClickEvent (QMouseEvent * event) getMainWindow()->setActiveWindow(view); } else if (item->type() == TreeWidget::ObjectType) { - if (!(static_cast(item)->object())->doubleClicked()) + DocumentObjectItem* objitem = static_cast(item); + App::DocumentObject* obj = objitem->object()->getObject(); + Gui::Document* doc = Gui::Application::Instance->getDocument(obj->getDocument()); + MDIView *view = doc->getActiveView(); + if (view) getMainWindow()->setActiveWindow(view); + if (!objitem->object()->doubleClicked()) QTreeWidget::mouseDoubleClickEvent(event); } } @@ -424,6 +431,7 @@ void TreeWidget::dropEvent(QDropEvent *event) // Open command App::Document* doc = grp->getDocument(); Gui::Document* gui = Gui::Application::Instance->getDocument(doc); + Base::Type DOGPython = Base::Type::fromName("App::DocumentObjectGroupPython"); gui->openCommand("Move object"); for (QList::Iterator it = items.begin(); it != items.end(); ++it) { // get document object @@ -433,20 +441,39 @@ void TreeWidget::dropEvent(QDropEvent *event) ::getGroupOfObject(obj); if (par) { // allow an object to be in one group only - QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").removeObject(" + QString cmd; + if (par->getTypeId().isDerivedFrom(DOGPython)) { + // if this is a python group, call the method of its Proxy + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").Proxy.removeObject(" "App.getDocument(\"%1\").getObject(\"%3\"))") .arg(QString::fromAscii(doc->getName())) .arg(QString::fromAscii(par->getNameInDocument())) .arg(QString::fromAscii(obj->getNameInDocument())); + } else { + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").removeObject(" + "App.getDocument(\"%1\").getObject(\"%3\"))") + .arg(QString::fromAscii(doc->getName())) + .arg(QString::fromAscii(par->getNameInDocument())) + .arg(QString::fromAscii(obj->getNameInDocument())); + } Gui::Application::Instance->runPythonCode(cmd.toUtf8()); } // build Python command for execution - QString cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").addObject(" + QString cmd; + if (grp->getTypeId().isDerivedFrom(DOGPython)) { + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").Proxy.addObject(" "App.getDocument(\"%1\").getObject(\"%3\"))") .arg(QString::fromAscii(doc->getName())) .arg(QString::fromAscii(grp->getNameInDocument())) .arg(QString::fromAscii(obj->getNameInDocument())); + } else { + cmd = QString::fromAscii("App.getDocument(\"%1\").getObject(\"%2\").addObject(" + "App.getDocument(\"%1\").getObject(\"%3\"))") + .arg(QString::fromAscii(doc->getName())) + .arg(QString::fromAscii(grp->getNameInDocument())) + .arg(QString::fromAscii(obj->getNameInDocument())); + } Gui::Application::Instance->runPythonCode(cmd.toUtf8()); } gui->commitCommand(); @@ -699,6 +726,8 @@ TreeDockWidget::TreeDockWidget(Gui::Document* pcDocument,QWidget *parent) setWindowTitle(tr("Tree view")); this->treeWidget = new TreeWidget(this); this->treeWidget->setRootIsDecorated(false); + 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); pLayout->setSpacing(0); @@ -803,9 +832,14 @@ void DocumentItem::slotChangeObject(const Gui::ViewProviderDocumentObject& view) children.insert(kt->second); QTreeWidgetItem* parent = kt->second->parent(); if (parent && parent != it->second) { - int index = parent->indexOfChild(kt->second); - parent->takeChild(index); - it->second->addChild(kt->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"); + } } } else { diff --git a/src/Gui/View3DInventor.cpp b/src/Gui/View3DInventor.cpp index 262916d1e6..8d354c9375 100644 --- a/src/Gui/View3DInventor.cpp +++ b/src/Gui/View3DInventor.cpp @@ -93,7 +93,7 @@ void GLOverlayWidget::paintEvent(QPaintEvent* ev) /* TRANSLATOR Gui::View3DInventor */ -TYPESYSTEM_SOURCE_ABSTRACT(Gui::View3DInventor,Gui::BaseView); +TYPESYSTEM_SOURCE_ABSTRACT(Gui::View3DInventor,Gui::MDIView); View3DInventor::View3DInventor(Gui::Document* pcDocument, QWidget* parent, Qt::WFlags wflags) : MDIView(pcDocument, parent, wflags), _viewerPy(0) @@ -937,7 +937,12 @@ void View3DInventor::customEvent(QEvent * e) { if (e->type() == QEvent::User) { NavigationStyleEvent* se = static_cast(e); - _viewer->setNavigationType(se->style()); + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath + ("User parameter:BaseApp/Preferences/View"); + if (hGrp->GetBool("SameStyleForAllViews", true)) + hGrp->SetASCII("NavigationStyle", se->style().getName()); + else + _viewer->setNavigationType(se->style()); } } diff --git a/src/Gui/View3DInventor.h b/src/Gui/View3DInventor.h index 7fc9b3dd24..cfc1f9253f 100644 --- a/src/Gui/View3DInventor.h +++ b/src/Gui/View3DInventor.h @@ -85,6 +85,7 @@ public: virtual void print(); virtual void printPdf(); virtual void printPreview(); + virtual void print(QPrinter*); virtual PyObject *getPyObject(void); /** @@ -113,7 +114,6 @@ public Q_SLOTS: protected Q_SLOTS: void stopAnimating(); - void print(QPrinter*); public: bool eventFilter(QObject*, QEvent* ); diff --git a/src/Gui/View3DInventorViewer.cpp b/src/Gui/View3DInventorViewer.cpp index 1b5ab3af07..93d06c691b 100644 --- a/src/Gui/View3DInventorViewer.cpp +++ b/src/Gui/View3DInventorViewer.cpp @@ -1070,18 +1070,16 @@ void View3DInventorViewer::processEvent(QEvent * event) motionEvent->setHandled(true); - static float translationConstant(-.001f); float xTrans, yTrans, zTrans; xTrans = static_cast(motionEvent->translationX()); yTrans = static_cast(motionEvent->translationY()); zTrans = static_cast(motionEvent->translationZ()); - SbVec3f translationVector(xTrans, yTrans, zTrans * -1.0); - translationVector *= translationConstant; + 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); + 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; @@ -1636,6 +1634,16 @@ 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. */ diff --git a/src/Gui/View3DInventorViewer.h b/src/Gui/View3DInventorViewer.h index 96c6fdce7d..71e5a2bf39 100644 --- a/src/Gui/View3DInventorViewer.h +++ b/src/Gui/View3DInventorViewer.h @@ -106,6 +106,9 @@ public: void setAnimationEnabled(const SbBool enable); SbBool isAnimationEnabled(void) const; + void setPopupMenuEnabled(const SbBool on); + SbBool isPopupMenuEnabled(void) const; + void startAnimating(const SbVec3f& axis, float velocity); void stopAnimating(void); SbBool isAnimating(void) const; diff --git a/src/Gui/ViewProviderDocumentObjectGroup.cpp b/src/Gui/ViewProviderDocumentObjectGroup.cpp index 14927fbc2e..13b2be0f03 100644 --- a/src/Gui/ViewProviderDocumentObjectGroup.cpp +++ b/src/Gui/ViewProviderDocumentObjectGroup.cpp @@ -221,3 +221,15 @@ QIcon ViewProviderDocumentObjectGroup::getIcon() const QIcon::Normal, QIcon::On); return groupIcon; } + + +// Python feature ----------------------------------------------------------------------- + +namespace Gui { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(Gui::ViewProviderDocumentObjectGroupPython, Gui::ViewProviderDocumentObjectGroup) +/// @endcond + +// explicit template instantiation +template class GuiExport ViewProviderPythonFeatureT; +} diff --git a/src/Gui/ViewProviderDocumentObjectGroup.h b/src/Gui/ViewProviderDocumentObjectGroup.h index 7157898e7b..aab9757509 100644 --- a/src/Gui/ViewProviderDocumentObjectGroup.h +++ b/src/Gui/ViewProviderDocumentObjectGroup.h @@ -26,6 +26,7 @@ #include "ViewProviderDocumentObject.h" +#include "ViewProviderPythonFeature.h" namespace Gui { @@ -63,6 +64,7 @@ private: std::vector nodes; }; +typedef ViewProviderPythonFeatureT ViewProviderDocumentObjectGroupPython; } // namespace Gui diff --git a/src/Gui/ViewProviderGeometryObject.cpp b/src/Gui/ViewProviderGeometryObject.cpp index ee02a34216..4e17a85e15 100644 --- a/src/Gui/ViewProviderGeometryObject.cpp +++ b/src/Gui/ViewProviderGeometryObject.cpp @@ -172,7 +172,8 @@ void ViewProviderGeometryObject::updateData(const App::Property* prop) trf->setMatrix(m.inverse()); } } - else if (prop->isDerivedFrom(App::PropertyPlacement::getClassTypeId())) { + else if (prop->isDerivedFrom(App::PropertyPlacement::getClassTypeId()) && + strcmp(prop->getName(), "Placement") == 0) { // Note: If R is the rotation, c the rotation center and t the translation // vector then Inventor applies the following transformation: R*(x-c)+c+t // In FreeCAD a placement only has a rotation and a translation part but diff --git a/src/Gui/ViewProviderPythonFeature.cpp b/src/Gui/ViewProviderPythonFeature.cpp index 576d012ab5..ed84b97ddb 100644 --- a/src/Gui/ViewProviderPythonFeature.cpp +++ b/src/Gui/ViewProviderPythonFeature.cpp @@ -383,6 +383,10 @@ void ViewProviderPythonFeatureImp::attach(App::DocumentObject *pcObject) args.setItem(0, Py::Object(object->getPyObject(), true)); method.apply(args); } + + // #0000415: Now simulate a property change event to call + // claimChildren if implemented. + pcObject->Label.touch(); } } } diff --git a/src/Gui/WidgetFactory.cpp b/src/Gui/WidgetFactory.cpp index c074fcd7e3..fd734154f2 100644 --- a/src/Gui/WidgetFactory.cpp +++ b/src/Gui/WidgetFactory.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" +#include #include #include #include @@ -194,6 +195,79 @@ QWidget* UiLoader::createWidget(const QString & className, QWidget * parent, // ---------------------------------------------------- +PyObject *UiLoaderPy::PyMake(struct _typeobject *type, PyObject * args, PyObject * kwds) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + return new UiLoaderPy(); +} + +void UiLoaderPy::init_type() +{ + behaviors().name("UiLoader"); + behaviors().doc("UiLoader to create widgets"); + behaviors().type_object()->tp_new = &PyMake; + // you must have overwritten the virtual functions + behaviors().supportRepr(); + behaviors().supportGetattr(); + behaviors().supportSetattr(); + add_varargs_method("createWidget",&UiLoaderPy::createWidget,"createWidget()"); +} + +UiLoaderPy::UiLoaderPy() +{ +} + +UiLoaderPy::~UiLoaderPy() +{ +} + +Py::Object UiLoaderPy::repr() +{ + std::string s; + std::ostringstream s_out; + s_out << "Ui loader"; + return Py::String(s_out.str()); +} + +Py::Object UiLoaderPy::createWidget(const Py::Tuple& args) +{ + Py::Module sipmod(PyImport_AddModule((char*)"sip")); + Py::Module qtmod(PyImport_ImportModule((char*)"PyQt4.Qt")); + + // 1st argument + std::string className = (std::string)Py::String(args[0]); + + // 2nd argument + QWidget* parent = 0; + if (args.size() > 1) { + Py::Callable func = sipmod.getDict().getItem("unwrapinstance"); + Py::Tuple arguments(1); + arguments[0] = args[1]; //PyQt pointer + Py::Object result = func.apply(arguments); + void* ptr = PyLong_AsVoidPtr(result.ptr()); + QObject* object = reinterpret_cast(ptr); + if (object) + parent = qobject_cast(object); + } + + // 3rd argument + std::string objectName; + if (args.size() > 2) { + objectName = (std::string)Py::String(args[2]); + } + + QWidget* widget = loader.createWidget(QString::fromAscii(className.c_str()), parent, + QString::fromAscii(objectName.c_str())); + Py::Callable func = sipmod.getDict().getItem("wrapinstance"); + Py::Tuple arguments(2); + arguments[0] = Py::asObject(PyLong_FromVoidPtr(widget)); + arguments[1] = qtmod.getDict().getItem("QWidget"); + return func.apply(arguments); +} + +// ---------------------------------------------------- + WidgetFactorySupplier* WidgetFactorySupplier::_pcSingleton = 0L; WidgetFactorySupplier & WidgetFactorySupplier::instance() diff --git a/src/Gui/WidgetFactory.h b/src/Gui/WidgetFactory.h index 8f20c88643..705e4c36b1 100644 --- a/src/Gui/WidgetFactory.h +++ b/src/Gui/WidgetFactory.h @@ -32,6 +32,7 @@ #include "DlgPreferencesImp.h" #include "DlgCustomizeImp.h" #include "PropertyPage.h" +#include namespace Gui { namespace Dialog{ @@ -85,13 +86,33 @@ public: * Fore more details see the documentation to QWidgetFactory. */ QWidget* createWidget(const QString & className, QWidget * parent=0, - const QString& name =QString()); + const QString& name = QString()); private: QStringList cw; }; // -------------------------------------------------------------------- +class UiLoaderPy : public Py::PythonExtension +{ +public: + static void init_type(void); // announce properties and methods + + UiLoaderPy(); + ~UiLoaderPy(); + + Py::Object repr(); + Py::Object createWidget(const Py::Tuple&); + +private: + static PyObject *PyMake(struct _typeobject *, PyObject *, PyObject *); + +private: + UiLoader loader; +}; + +// -------------------------------------------------------------------- + /** * The WidgetProducer class is a value-based template class that provides * the ability to create widgets dynamically. diff --git a/src/Gui/Widgets.cpp b/src/Gui/Widgets.cpp index e807eebe2f..d4e66e3bea 100644 --- a/src/Gui/Widgets.cpp +++ b/src/Gui/Widgets.cpp @@ -23,15 +23,17 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include +# include # include # include # include +# include # include # include # include # include # include +# include # include #endif @@ -102,6 +104,260 @@ void CommandIconView::onSelectionChanged(QListWidgetItem * item, QListWidgetItem // ------------------------------------------------------------------------------ +/* TRANSLATOR Gui::ActionSelector */ + +ActionSelector::ActionSelector(QWidget* parent) + : QWidget(parent) +{ + addButton = new QPushButton(this); + addButton->setObjectName(QLatin1String("addButton")); + addButton->setMinimumSize(QSize(30, 30)); + QIcon icon; + icon.addFile(QString::fromUtf8(":/icons/button_right.xpm"), QSize(), QIcon::Normal, QIcon::Off); + addButton->setIcon(icon); + gridLayout = new QGridLayout(this); + gridLayout->addWidget(addButton, 1, 1, 1, 1); + + spacerItem = new QSpacerItem(33, 57, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacerItem, 5, 1, 1, 1); + spacerItem1 = new QSpacerItem(33, 58, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacerItem1, 0, 1, 1, 1); + + removeButton = new QPushButton(this); + removeButton->setObjectName(QLatin1String("removeButton")); + removeButton->setMinimumSize(QSize(30, 30)); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":/icons/button_left.xpm"), QSize(), QIcon::Normal, QIcon::Off); + removeButton->setIcon(icon1); + removeButton->setAutoDefault(true); + removeButton->setDefault(false); + + gridLayout->addWidget(removeButton, 2, 1, 1, 1); + + upButton = new QPushButton(this); + upButton->setObjectName(QLatin1String("upButton")); + upButton->setMinimumSize(QSize(30, 30)); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/icons/button_up.xpm"), QSize(), QIcon::Normal, QIcon::Off); + upButton->setIcon(icon3); + + gridLayout->addWidget(upButton, 3, 1, 1, 1); + + downButton = new QPushButton(this); + downButton->setObjectName(QLatin1String("downButton")); + downButton->setMinimumSize(QSize(30, 30)); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/icons/button_down.xpm"), QSize(), QIcon::Normal, QIcon::Off); + downButton->setIcon(icon2); + downButton->setAutoDefault(true); + + gridLayout->addWidget(downButton, 4, 1, 1, 1); + + vboxLayout = new QVBoxLayout(); + vboxLayout->setContentsMargins(0, 0, 0, 0); + labelAvailable = new QLabel(this); + vboxLayout->addWidget(labelAvailable); + + availableWidget = new QTreeWidget(this); + availableWidget->setObjectName(QLatin1String("availableTreeWidget")); + availableWidget->setRootIsDecorated(false); + availableWidget->setHeaderLabels(QStringList() << QString()); + availableWidget->header()->hide(); + vboxLayout->addWidget(availableWidget); + + gridLayout->addLayout(vboxLayout, 0, 0, 6, 1); + + vboxLayout1 = new QVBoxLayout(); + vboxLayout1->setContentsMargins(0, 0, 0, 0); + labelSelected = new QLabel(this); + vboxLayout1->addWidget(labelSelected); + + selectedWidget = new QTreeWidget(this); + selectedWidget->setObjectName(QLatin1String("selectedTreeWidget")); + selectedWidget->setRootIsDecorated(false); + selectedWidget->setHeaderLabels(QStringList() << QString()); + selectedWidget->header()->hide(); + vboxLayout1->addWidget(selectedWidget); + + gridLayout->addLayout(vboxLayout1, 0, 2, 6, 1); + + addButton->setText(QString()); + removeButton->setText(QString()); + upButton->setText(QString()); + downButton->setText(QString()); + + connect(addButton, SIGNAL(clicked()), + this, SLOT(on_addButton_clicked()) ); + connect(removeButton, SIGNAL(clicked()), + this, SLOT(on_removeButton_clicked()) ); + connect(upButton, SIGNAL(clicked()), + this, SLOT(on_upButton_clicked()) ); + connect(downButton, SIGNAL(clicked()), + this, SLOT(on_downButton_clicked()) ); + connect(availableWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), + this, SLOT(onItemDoubleClicked(QTreeWidgetItem*,int)) ); + connect(selectedWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), + this, SLOT(onItemDoubleClicked(QTreeWidgetItem*,int)) ); + connect(availableWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem *)), + this, SLOT(onCurrentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)) ); + connect(selectedWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem *)), + this, SLOT(onCurrentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)) ); + retranslateUi(); + setButtonsEnabled(); +} + +ActionSelector::~ActionSelector() +{ +} + +void ActionSelector::setSelectedLabel(const QString& label) +{ + labelSelected->setText(label); +} + +QString ActionSelector::selectedLabel() const +{ + return labelSelected->text(); +} + +void ActionSelector::setAvailableLabel(const QString& label) +{ + labelAvailable->setText(label); +} + +QString ActionSelector::availableLabel() const +{ + return labelAvailable->text(); +} + + +void ActionSelector::retranslateUi() +{ + labelAvailable->setText(QApplication::translate("Gui::ActionSelector", "Available:", 0, QApplication::UnicodeUTF8)); + labelSelected->setText(QApplication::translate("Gui::ActionSelector", "Selected:", 0, QApplication::UnicodeUTF8)); + addButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Add", 0, QApplication::UnicodeUTF8)); + removeButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Remove", 0, QApplication::UnicodeUTF8)); + upButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Move up", 0, QApplication::UnicodeUTF8)); + downButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Move down", 0, QApplication::UnicodeUTF8)); +} + +void ActionSelector::changeEvent(QEvent* event) +{ + if (event->type() == QEvent::LanguageChange) { + retranslateUi(); + } + QWidget::changeEvent(event); +} + +void ActionSelector::keyPressEvent(QKeyEvent* event) +{ + if ((event->modifiers() & Qt::ControlModifier)) { + switch (event->key()) + { + case Qt::Key_Right: + on_addButton_clicked(); + break; + case Qt::Key_Left: + on_removeButton_clicked(); + break; + case Qt::Key_Up: + on_upButton_clicked(); + break; + case Qt::Key_Down: + on_downButton_clicked(); + break; + default: + event->ignore(); + return; + } + } +} + +void ActionSelector::setButtonsEnabled() +{ + addButton->setEnabled(availableWidget->indexOfTopLevelItem(availableWidget->currentItem()) > -1); + removeButton->setEnabled(selectedWidget->indexOfTopLevelItem(selectedWidget->currentItem()) > -1); + upButton->setEnabled(selectedWidget->indexOfTopLevelItem(selectedWidget->currentItem()) > 0); + downButton->setEnabled(selectedWidget->indexOfTopLevelItem(selectedWidget->currentItem()) > -1 && + selectedWidget->indexOfTopLevelItem(selectedWidget->currentItem()) < selectedWidget->topLevelItemCount() - 1); +} + +void ActionSelector::onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*) +{ + setButtonsEnabled(); +} + +void ActionSelector::onItemDoubleClicked(QTreeWidgetItem * item, int column) +{ + QTreeWidget* treeWidget = item->treeWidget(); + if (treeWidget == availableWidget) { + int index = availableWidget->indexOfTopLevelItem(item); + item = availableWidget->takeTopLevelItem(index); + availableWidget->setCurrentItem(0); + selectedWidget->addTopLevelItem(item); + selectedWidget->setCurrentItem(item); + } + else if (treeWidget == selectedWidget) { + int index = selectedWidget->indexOfTopLevelItem(item); + item = selectedWidget->takeTopLevelItem(index); + selectedWidget->setCurrentItem(0); + availableWidget->addTopLevelItem(item); + availableWidget->setCurrentItem(item); + } +} + +void ActionSelector::on_addButton_clicked() +{ + QTreeWidgetItem* item = availableWidget->currentItem(); + if (item) { + int index = availableWidget->indexOfTopLevelItem(item); + item = availableWidget->takeTopLevelItem(index); + availableWidget->setCurrentItem(0); + selectedWidget->addTopLevelItem(item); + selectedWidget->setCurrentItem(item); + } +} + +void ActionSelector::on_removeButton_clicked() +{ + QTreeWidgetItem* item = selectedWidget->currentItem(); + if (item) { + int index = selectedWidget->indexOfTopLevelItem(item); + item = selectedWidget->takeTopLevelItem(index); + selectedWidget->setCurrentItem(0); + availableWidget->addTopLevelItem(item); + availableWidget->setCurrentItem(item); + } +} + +void ActionSelector::on_upButton_clicked() +{ + QTreeWidgetItem* item = selectedWidget->currentItem(); + if (item && selectedWidget->isItemSelected(item)) { + int index = selectedWidget->indexOfTopLevelItem(item); + if (index > 0) { + selectedWidget->takeTopLevelItem(index); + selectedWidget->insertTopLevelItem(index-1, item); + selectedWidget->setCurrentItem(item); + } + } +} + +void ActionSelector::on_downButton_clicked() +{ + QTreeWidgetItem* item = selectedWidget->currentItem(); + if (item && selectedWidget->isItemSelected(item)) { + int index = selectedWidget->indexOfTopLevelItem(item); + if (index < selectedWidget->topLevelItemCount()-1) { + selectedWidget->takeTopLevelItem(index); + selectedWidget->insertTopLevelItem(index+1, item); + selectedWidget->setCurrentItem(item); + } + } +} + +// ------------------------------------------------------------------------------ + /* TRANSLATOR Gui::AccelLineEdit */ /** @@ -626,10 +882,10 @@ StatusWidget::StatusWidget(QWidget* parent) label = new QLabel(this); label->setAlignment(Qt::AlignCenter); - QGridLayout* gridLayout = new QGridLayout(this); - gridLayout->setSpacing(6); - gridLayout->setMargin(9); - gridLayout->addWidget(label, 0, 0, 1, 1); + QGridLayout* gridLayout = new QGridLayout(this); + gridLayout->setSpacing(6); + gridLayout->setMargin(9); + gridLayout->addWidget(label, 0, 0, 1, 1); } StatusWidget::~StatusWidget() @@ -641,6 +897,17 @@ void StatusWidget::setStatusText(const QString& s) label->setText(s); } +void StatusWidget::showText(int ms) +{ + show(); + QTimer timer; + QEventLoop loop; + QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + timer.start(ms); + loop.exec(QEventLoop::ExcludeUserInputEvents); + hide(); +} + QSize StatusWidget::sizeHint () const { return QSize(250,100); @@ -762,20 +1029,20 @@ void LabelEditor::setText(const QString& s) void LabelEditor::changeText() { QDialog dlg(this); - QVBoxLayout* hboxLayout = new QVBoxLayout(&dlg); - QDialogButtonBox* buttonBox = new QDialogButtonBox(&dlg); - buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Close); + QVBoxLayout* hboxLayout = new QVBoxLayout(&dlg); + QDialogButtonBox* buttonBox = new QDialogButtonBox(&dlg); + buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Close); QPlainTextEdit *edit = new QPlainTextEdit(&dlg); edit->setPlainText(this->lineEdit->text()); - - hboxLayout->addWidget(edit); - hboxLayout->addWidget(buttonBox); - connect(buttonBox, SIGNAL(accepted()), &dlg, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), &dlg, SLOT(reject())); - if (dlg.exec() == QDialog::Accepted) { - this->lineEdit->setText(edit->toPlainText()); - } + + hboxLayout->addWidget(edit); + hboxLayout->addWidget(buttonBox); + connect(buttonBox, SIGNAL(accepted()), &dlg, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), &dlg, SLOT(reject())); + if (dlg.exec() == QDialog::Accepted) { + this->lineEdit->setText(edit->toPlainText()); + } } /** diff --git a/src/Gui/Widgets.h b/src/Gui/Widgets.h index c1d58954b3..70366a67f6 100644 --- a/src/Gui/Widgets.h +++ b/src/Gui/Widgets.h @@ -63,6 +63,55 @@ Q_SIGNALS: // ------------------------------------------------------------------------------ +class GuiExport ActionSelector : public QWidget +{ + Q_OBJECT + +public: + ActionSelector(QWidget* parent=0); + ~ActionSelector(); + + QTreeWidget* availableTreeWidget() const + { return availableWidget; } + QTreeWidget* selectedTreeWidget() const + { return selectedWidget; } + void setSelectedLabel(const QString&); + QString selectedLabel() const; + void setAvailableLabel(const QString&); + QString availableLabel() const; + +private: + void keyPressEvent(QKeyEvent *); + void changeEvent(QEvent*); + void retranslateUi(); + void setButtonsEnabled(); + +private Q_SLOTS: + void on_addButton_clicked(); + void on_removeButton_clicked(); + void on_upButton_clicked(); + void on_downButton_clicked(); + void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*); + void onItemDoubleClicked(QTreeWidgetItem * item, int column); + +private: + QGridLayout *gridLayout; + QVBoxLayout *vboxLayout; + QVBoxLayout *vboxLayout1; + QPushButton *addButton; + QPushButton *removeButton; + QPushButton *upButton; + QPushButton *downButton; + QLabel *labelAvailable; + QLabel *labelSelected; + QTreeWidget *availableWidget; + QTreeWidget *selectedWidget; + QSpacerItem *spacerItem; + QSpacerItem *spacerItem1; +}; + +// ------------------------------------------------------------------------------ + /** * The AccelLineEdit class provides a lineedit to specfify shortcuts. * \author Werner Mayer @@ -275,6 +324,7 @@ public: ~StatusWidget(); void setStatusText(const QString&); QSize sizeHint () const; + void showText(int ms); protected: void showEvent(QShowEvent*); diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index d6b82d4abe..26ca5d6984 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -441,7 +441,8 @@ MenuItem* StdWorkbench::setupMenuBar() const edit->setCommand("&Edit"); *edit << "Std_Undo" << "Std_Redo" << "Separator" << "Std_Cut" << "Std_Copy" << "Std_Paste" << "Std_DuplicateSelection" << "Separator" - << "Std_Refresh" << "Std_SelectAll" << "Std_Delete" << "Std_Placement" + << "Std_Refresh" << "Std_BoxSelection" << "Std_SelectAll" << "Std_Delete" + << "Std_Placement" << "Std_Alignment" << "Std_Edit" << "Separator" << "Std_DlgPreferences"; // Standard views diff --git a/src/Gui/propertyeditor/PropertyItem.cpp b/src/Gui/propertyeditor/PropertyItem.cpp index 4c7966741f..eab7c4c20c 100644 --- a/src/Gui/propertyeditor/PropertyItem.cpp +++ b/src/Gui/propertyeditor/PropertyItem.cpp @@ -57,6 +57,7 @@ TYPESYSTEM_SOURCE(Gui::PropertyEditor::PropertyItem, Base::BaseClass); PropertyItem::PropertyItem() : parentItem(0), readonly(false) { + precision = Base::UnitsApi::getDecimals(); } PropertyItem::~PropertyItem() @@ -121,6 +122,8 @@ int PropertyItem::columnCount() const void PropertyItem::setReadOnly(bool ro) { readonly = ro; + for (QList::iterator it = childItems.begin(); it != childItems.end(); ++it) + (*it)->setReadOnly(ro); } bool PropertyItem::isReadOnly() const @@ -128,6 +131,16 @@ bool PropertyItem::isReadOnly() const return readonly; } +void PropertyItem::setDecimals(int prec) +{ + precision = prec; +} + +int PropertyItem::decimals() const +{ + return precision; +} + QVariant PropertyItem::toolTip(const App::Property* prop) const { return QVariant(QString::fromUtf8(prop->getDocumentation())); @@ -572,7 +585,7 @@ void PropertyFloatItem::setValue(const QVariant& value) if (!value.canConvert(QVariant::Double)) return; double val = value.toDouble(); - QString data = QString::fromAscii("%1").arg(val,0,'f',2); + QString data = QString::fromAscii("%1").arg(val,0,'f',decimals()); setPropertyValue(data); } @@ -580,6 +593,7 @@ QWidget* PropertyFloatItem::createEditor(QWidget* parent, const QObject* receive { QDoubleSpinBox *sb = new QDoubleSpinBox(parent); sb->setFrame(false); + sb->setDecimals(decimals()); QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method); return sb; } @@ -701,13 +715,14 @@ void PropertyFloatConstraintItem::setValue(const QVariant& value) if (!value.canConvert(QVariant::Double)) return; double val = value.toDouble(); - QString data = QString::fromAscii("%1").arg(val,0,'f',2); + QString data = QString::fromAscii("%1").arg(val,0,'f',decimals()); setPropertyValue(data); } QWidget* PropertyFloatConstraintItem::createEditor(QWidget* parent, const QObject* receiver, const char* method) const { QDoubleSpinBox *sb = new QDoubleSpinBox(parent); + sb->setDecimals(decimals()); sb->setFrame(false); QObject::connect(sb, SIGNAL(valueChanged(double)), receiver, method); return sb; @@ -871,9 +886,9 @@ void PropertyVectorItem::setValue(const QVariant& value) return; const Base::Vector3f& val = value.value(); QString data = QString::fromAscii("(%1, %2, %3)") - .arg(val.x,0,'f',2) - .arg(val.y,0,'f',2) - .arg(val.z,0,'f',2); + .arg(val.x,0,'f',decimals()) + .arg(val.y,0,'f',decimals()) + .arg(val.z,0,'f',decimals()); setPropertyValue(data); } @@ -974,9 +989,9 @@ void PropertyDoubleVectorItem::setValue(const QVariant& value) return; const Base::Vector3d& val = value.value(); QString data = QString::fromAscii("(%1, %2, %3)") - .arg(val.x,0,'f',2) - .arg(val.y,0,'f',2) - .arg(val.z,0,'f',2); + .arg(val.x,0,'f',decimals()) + .arg(val.y,0,'f',decimals()) + .arg(val.z,0,'f',decimals()); setPropertyValue(data); } @@ -1501,9 +1516,9 @@ void PropertyColorItem::setValue(const QVariant& value) val.g = (float)col.green()/255.0f; val.b = (float)col.blue()/255.0f; QString data = QString::fromAscii("(%1,%2,%3)") - .arg(val.r,0,'f',2) - .arg(val.g,0,'f',2) - .arg(val.b,0,'f',2); + .arg(val.r,0,'f',decimals()) + .arg(val.g,0,'f',decimals()) + .arg(val.b,0,'f',decimals()); setPropertyValue(data); } diff --git a/src/Gui/propertyeditor/PropertyItem.h b/src/Gui/propertyeditor/PropertyItem.h index d334d8ced2..bc247966fc 100644 --- a/src/Gui/propertyeditor/PropertyItem.h +++ b/src/Gui/propertyeditor/PropertyItem.h @@ -69,6 +69,8 @@ public: void setReadOnly(bool); bool isReadOnly() const; + void setDecimals(int); + int decimals() const; PropertyItem *child(int row); int childCount() const; @@ -99,6 +101,7 @@ private: PropertyItem *parentItem; QList childItems; bool readonly; + int precision; }; /** diff --git a/src/Gui/resource.cpp b/src/Gui/resource.cpp index 3143f1502a..b7f3ce8fbd 100644 --- a/src/Gui/resource.cpp +++ b/src/Gui/resource.cpp @@ -91,6 +91,7 @@ WidgetFactorySupplier::WidgetFactorySupplier() new WidgetProducer; new WidgetProducer; new WidgetProducer; + new WidgetProducer; new WidgetProducer; new WidgetProducer; new WidgetProducer; diff --git a/src/Mod/Arch/Arch.py b/src/Mod/Arch/Arch.py index 81bb29ffe5..fc537d85ae 100644 --- a/src/Mod/Arch/Arch.py +++ b/src/Mod/Arch/Arch.py @@ -39,3 +39,4 @@ from ArchCommands import * from ArchSectionPlane import * from ArchWindow import * from ArchAxis import * +from ArchRoof import * diff --git a/src/Mod/Arch/ArchAxis.py b/src/Mod/Arch/ArchAxis.py index dc9cca6504..a2ea310331 100644 --- a/src/Mod/Arch/ArchAxis.py +++ b/src/Mod/Arch/ArchAxis.py @@ -21,18 +21,17 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,math - -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,math,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore, QtGui from pivy import coin +from DraftTools import translate __title__="FreeCAD Axis System" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeAxis(num=0,size=0,name="Axes"): +def makeAxis(num=5,size=1,name=str(translate("Arch","Axes"))): '''makeAxis(num,size): makes an Axis System based on the given number of axes and interval distances''' obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) @@ -58,16 +57,17 @@ class _CommandAxis: 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Axis","Creates an axis system.")} def Activated(self): - FreeCAD.ActiveDocument.openTransaction("Axis") - makeAxis(5,1) + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Axis"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeAxis()") FreeCAD.ActiveDocument.commitTransaction() class _Axis: "The Axis object" def __init__(self,obj): - obj.addProperty("App::PropertyFloatList","Distances","Base", "The intervals between axes") - obj.addProperty("App::PropertyFloatList","Angles","Base", "The angles of each axis") - obj.addProperty("App::PropertyFloat","Length","Base", "The length of the axes") + obj.addProperty("App::PropertyFloatList","Distances","Base", str(translate("Arch","The intervals between axes"))) + obj.addProperty("App::PropertyFloatList","Angles","Base", str(translate("Arch","The angles of each axis"))) + obj.addProperty("App::PropertyFloat","Length","Base", str(translate("Arch","The length of the axes"))) self.Type = "Axis" obj.Length=1.0 obj.Proxy = self @@ -100,20 +100,17 @@ class _ViewProviderAxis: "A View Provider for the Axis object" def __init__(self,vobj): - vobj.addProperty("App::PropertyLength","BubbleSize","Base", "The size of the axis bubbles") - vobj.addProperty("App::PropertyEnumeration","NumerationStyle","Base", "The numeration style") - vobj.addProperty("App::PropertyEnumeration","DrawStyle","Base", "The representation style") + vobj.addProperty("App::PropertyLength","BubbleSize","Base", str(translate("Arch","The size of the axis bubbles"))) + vobj.addProperty("App::PropertyEnumeration","NumerationStyle","Base", str(translate("Arch","The numeration style"))) vobj.NumerationStyle = ["1,2,3","01,02,03","001,002,003","A,B,C","a,b,c","I,II,III","L0,L1,L2"] - vobj.DrawStyle = ["solid","dotted","dashed","dashdot"] vobj.Proxy = self - self.Object = vobj.Object - self.ViewObject = vobj vobj.BubbleSize = .1 vobj.LineWidth = 1 vobj.LineColor = (0.13,0.15,0.37) - vobj.DrawStyle = "dashdot" + vobj.DrawStyle = "Dashdot" - def getIcon(self): + def getIcon(self): + import Arch_rc return ":/icons/Arch_Axis_Tree.svg" def claimChildren(self): @@ -121,6 +118,7 @@ class _ViewProviderAxis: def attach(self, vobj): self.ViewObject = vobj + self.Object = vobj.Object self.bubbles = None def getNumber(self,num): @@ -162,61 +160,61 @@ class _ViewProviderAxis: return "L"+str(num) return "" - def setStyle(self): - ds = self.ViewObject.RootNode.getChild(2).getChild(0).getChild(0).getChild(1) - if self.ViewObject.DrawStyle == "solid": - ds.linePattern = 0xffff - elif self.ViewObject.DrawStyle == "dotted": - ds.linePattern = 0x0f0f - elif self.ViewObject.DrawStyle == "dashed": - ds.linePattern = 0xf00f - elif self.ViewObject.DrawStyle == "dashdot": - ds.linePattern = 0xff88 - def makeBubbles(self): import Part - rn = self.ViewObject.RootNode.getChild(2).getChild(0).getChild(0) - if self.bubbles: - rn.removeChild(self.bubbles) - self.bubbles = None - self.bubbles = coin.SoSeparator() - isep = coin.SoSeparator() - self.bubblestyle = coin.SoDrawStyle() - self.bubblestyle.linePattern = 0xffff - self.bubbles.addChild(self.bubblestyle) - for i in range(len(self.ViewObject.Object.Distances)): - invpl = self.ViewObject.Object.Placement.inverse() - verts = self.ViewObject.Object.Shape.Edges[i].Vertexes - p1 = invpl.multVec(verts[0].Point) - p2 = invpl.multVec(verts[1].Point) - dv = p2.sub(p1) - dv.normalize() - rad = self.ViewObject.BubbleSize - center = p2.add(dv.scale(rad,rad,rad)) - ts = Part.makeCircle(rad,center).writeInventor() - cin = coin.SoInput() - cin.setBuffer(ts) - cob = coin.SoDB.readAll(cin) - co = cob.getChild(1).getChild(0).getChild(2) - li = cob.getChild(1).getChild(0).getChild(3) - self.bubbles.addChild(co) - self.bubbles.addChild(li) - st = coin.SoSeparator() - tr = coin.SoTransform() - tr.translation.setValue((center.x,center.y,center.z)) - fo = coin.SoFont() - fo.name = "Arial,Sans" - fo.size = rad*100 - tx = coin.SoText2() - tx.justification = coin.SoText2.CENTER - tx.string = self.getNumber(i) - st.addChild(tr) - st.addChild(fo) - st.addChild(tx) - isep.addChild(st) - self.bubbles.addChild(isep) - rn.addChild(self.bubbles) - + + def getNode(): + # make sure we already have the complete node built + r = self.ViewObject.RootNode + if r.getChildren().getLength() > 2: + if r.getChild(2).getChildren().getLength() > 0: + if r.getChild(2).getChild(0).getChildren().getLength() > 0: + return self.ViewObject.RootNode.getChild(2).getChild(0).getChild(0) + return None + + rn = getNode() + if rn: + if self.bubbles: + rn.removeChild(self.bubbles) + self.bubbles = None + self.bubbles = coin.SoSeparator() + isep = coin.SoSeparator() + self.bubblestyle = coin.SoDrawStyle() + self.bubblestyle.linePattern = 0xffff + self.bubbles.addChild(self.bubblestyle) + for i in range(len(self.ViewObject.Object.Distances)): + invpl = self.ViewObject.Object.Placement.inverse() + verts = self.ViewObject.Object.Shape.Edges[i].Vertexes + p1 = invpl.multVec(verts[0].Point) + p2 = invpl.multVec(verts[1].Point) + dv = p2.sub(p1) + dv.normalize() + rad = self.ViewObject.BubbleSize + center = p2.add(dv.scale(rad,rad,rad)) + ts = Part.makeCircle(rad,center).writeInventor() + cin = coin.SoInput() + cin.setBuffer(ts) + cob = coin.SoDB.readAll(cin) + co = cob.getChild(1).getChild(0).getChild(2) + li = cob.getChild(1).getChild(0).getChild(3) + self.bubbles.addChild(co) + self.bubbles.addChild(li) + st = coin.SoSeparator() + tr = coin.SoTransform() + tr.translation.setValue((center.x,center.y-rad/4,center.z)) + fo = coin.SoFont() + fo.name = "Arial,Sans" + fo.size = rad*100 + tx = coin.SoText2() + tx.justification = coin.SoText2.CENTER + tx.string = self.getNumber(i) + st.addChild(tr) + st.addChild(fo) + st.addChild(tx) + isep.addChild(st) + self.bubbles.addChild(isep) + rn.addChild(self.bubbles) + def updateData(self, obj, prop): if prop == "Shape": self.makeBubbles() @@ -225,8 +223,6 @@ class _ViewProviderAxis: def onChanged(self, vobj, prop): if prop in ["NumerationStyle","BubbleSize"]: self.makeBubbles() - elif prop == "DrawStyle": - self.setStyle() elif prop == "LineWidth": if self.bubbles: self.bubblestyle.lineWidth = vobj.LineWidth diff --git a/src/Mod/Arch/ArchBuilding.py b/src/Mod/Arch/ArchBuilding.py index 96f1bc067e..968165527a 100644 --- a/src/Mod/Arch/ArchBuilding.py +++ b/src/Mod/Arch/ArchBuilding.py @@ -21,24 +21,22 @@ #* * #*************************************************************************** -import ArchCell,FreeCAD,FreeCADGui,Draft,ArchCommands +import FreeCAD,FreeCADGui,Draft,ArchCommands,ArchFloor from PyQt4 import QtCore +from DraftTools import translate __title__="FreeCAD Building" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeBuilding(objectslist=None,join=False,name="Building"): +def makeBuilding(objectslist=None,join=False,name=str(translate("Arch","Building"))): '''makeBuilding(objectslist,[joinmode]): creates a building including the objects from the given list. If joinmode is True, components will be joined.''' - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) + obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",name) _Building(obj) _ViewProviderBuilding(obj.ViewObject) if objectslist: - obj.Components = objectslist - for comp in obj.Components: - comp.ViewObject.hide() - obj.JoinMode = join + obj.Group = objectslist return obj class _CommandBuilding: @@ -54,30 +52,41 @@ class _CommandBuilding: ok = False if (len(sel) == 1): if Draft.getType(sel[0]) in ["Cell","Site","Floor"]: - FreeCAD.ActiveDocument.openTransaction("Type conversion") - nobj = makeBuilding() - ArchCommands.copyProperties(sel[0],nobj) - FreeCAD.ActiveDocument.removeObject(sel[0].Name) + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Type conversion"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("obj = Arch.makeBuilding()") + FreeCADGui.doCommand("Arch.copyProperties(FreeCAD.ActiveDocument."+sel[0].Name+",obj)") + FreeCADGui.doCommand('FreeCAD.ActiveDocument.removeObject("'+sel[0].Name+'")') FreeCAD.ActiveDocument.commitTransaction() ok = True if not ok: - FreeCAD.ActiveDocument.openTransaction("Building") - makeBuilding(sel) + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch"," Create Building"))) + ss = "[" + for o in sel: + if len(ss) > 1: + ss += "," + ss += "FreeCAD.ActiveDocument."+o.Name + ss += "]" + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Floor"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeBuilding("+ss+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() -class _Building(ArchCell._Cell): +class _Building(ArchFloor._Floor): "The Building object" def __init__(self,obj): - ArchCell._Cell.__init__(self,obj) + ArchFloor._Floor.__init__(self,obj) self.Type = "Building" - -class _ViewProviderBuilding(ArchCell._ViewProviderCell): + obj.setEditorMode('Height',2) + +class _ViewProviderBuilding(ArchFloor._ViewProviderFloor): "A View Provider for the Building object" def __init__(self,vobj): - ArchCell._ViewProviderCell.__init__(self,vobj) + ArchFloor._ViewProviderFloor.__init__(self,vobj) def getIcon(self): + import Arch_rc return ":/icons/Arch_Building_Tree.svg" FreeCADGui.addCommand('Arch_Building',_CommandBuilding()) diff --git a/src/Mod/Arch/ArchCell.py b/src/Mod/Arch/ArchCell.py index 8783602ccf..6c4527ce5c 100644 --- a/src/Mod/Arch/ArchCell.py +++ b/src/Mod/Arch/ArchCell.py @@ -121,6 +121,7 @@ class _ViewProviderCell(ArchComponent.ViewProviderComponent): self.Object = vobj.Object def getIcon(self): + import Arch_rc return ":/icons/Arch_Cell_Tree.svg" def updateData(self,obj,prop): diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index e94d21b3ef..2025a6f308 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -21,10 +21,10 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore +from DraftTools import translate __title__="FreeCAD Arch Commands" __author__ = "Yorik van Havre" @@ -39,12 +39,18 @@ def addComponents(objectsList,host): if not isinstance(objectsList,list): objectsList = [objectsList] tp = Draft.getType(host) - if tp in ["Cell","Floor","Building","Site"]: + if tp in ["Cell"]: c = host.Components for o in objectsList: if not o in c: c.append(o) host.Components = c + elif tp in ["Floor","Building","Site"]: + c = host.Group + for o in objectsList: + if not o in c: + c.append(o) + host.Group = c elif tp in ["Wall","Structure"]: a = host.Additions for o in objectsList: @@ -73,6 +79,17 @@ def removeComponents(objectsList,host=None): for o in objectsList: if not o in s: s.append(o) + if Draft.getType(o) == "Window": + # fix for sketch-based windows + if o.Base: + if o.Base.Support: + if isinstance(o.Base.Support,tuple): + if o.Base.Support[0].Name == host.Name: + print "removing sketch support to avoid cross-referencing" + o.Base.Support = None + elif o.Base.Support.Name == host.Name: + print "removing sketch support to avoid cross-referencing" + o.Base.Support = None host.Subtractions = s else: for o in objectsList: @@ -135,13 +152,65 @@ def splitMesh(obj,mark=True): return nlist return [obj] +def makeFace(wires,method=2,cleanup=False): + '''makeFace(wires): makes a face from a list of wires, finding which ones are holes''' + + import Part + + if not isinstance(wires,list): + return Part.Face(wires) + elif len(wires) == 1: + return Part.Face(wires[0]) + + wires = wires[:] + + print "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" + 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 + wires.remove(ext) + + if method == 1: + # method 1: reverse inner wires + # all interior wires mark a hole and must reverse + # their orientation, otherwise Part.Face fails + for w in wires: + print "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 + if wires: + return Part.Face(wires) + else: + # method 2: use the cut method + mf = Part.Face(ext) + print "external face:",mf + for w in wires: + f = Part.Face(w) + print "internal face:",f + mf = mf.cut(f) + print "final face:",mf.Faces + return mf.Faces[0] + def meshToShape(obj,mark=True): '''meshToShape(object,[mark]): turns a mesh into a shape, joining coplanar facets. If mark is True (default), non-solid objects will be marked in red''' name = obj.Name - import Part,MeshPart - from draftlibs import fcgeo + import Part, MeshPart, DraftGeomUtils if "Mesh" in obj.PropertiesList: faces = [] mesh = obj.Mesh @@ -154,33 +223,8 @@ def meshToShape(obj,mark=True): wires = MeshPart.wireFromSegment(mesh, i) print "wire done" print wires - if len(wires) > 1: - # a segment can have inner holes - print "inner wires found" - ext = None - max_length = 0 - # cleaning up rubbish in wires - for i in range(len(wires)): - wires[i] = fcgeo.removeInterVertices(wires[i]) - 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 - wires.remove(ext) - # all interior wires mark a hole and must reverse - # their orientation, otherwise Part.Face fails - for w in wires: - print "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 if wires: - faces.append(Part.Face(wires)) + faces.append(makeFace(wires)) print "done facing" print "faces",faces @@ -192,24 +236,24 @@ def meshToShape(obj,mark=True): else: if solid.isClosed(): FreeCAD.ActiveDocument.removeObject(name) - else: - if mark: - newobj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0) newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name) newobj.Shape = solid newobj.Placement = plac + if not solid.isClosed(): + if mark: + newobj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0) return newobj return None def removeShape(objs,mark=True): '''takes an arch object (wall or structure) built on a cubic shape, and removes the inner shape, keeping its length, width and height as parameters.''' - from draftlibs import fcgeo + import DraftGeomUtils if not isinstance(objs,list): objs = [objs] for obj in objs: - if fcgeo.isCubic(obj.Shape): - dims = fcgeo.getCubicDimensions(obj.Shape) + if DraftGeomUtils.isCubic(obj.Shape): + dims = DraftGeomUtils.getCubicDimensions(obj.Shape) if dims: name = obj.Name tp = Draft.getType(obj) @@ -225,7 +269,7 @@ def removeShape(objs,mark=True): length = dims[1] width = dims[2] v1 = Vector(length/2,0,0) - v2 = fcvec.neg(v1) + v2 = DraftVecUtils.neg(v1) v1 = dims[0].multVec(v1) v2 = dims[0].multVec(v2) line = Draft.makeLine(v1,v2) @@ -298,11 +342,20 @@ class _CommandAdd: def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction("Grouping") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Grouping"))) if not mergeCells(sel): host = sel.pop() - addComponents(sel,host) + ss = "[" + for o in sel: + if len(ss) > 1: + ss += "," + ss += "FreeCAD.ActiveDocument."+o.Name + ss += "]" + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.addComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + class _CommandRemove: "the Arch Add command definition" @@ -319,13 +372,22 @@ class _CommandRemove: def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction("Ungrouping") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Ungrouping"))) if Draft.getType(sel[-1]) in ["Wall","Structure"]: host = sel.pop() - removeComponents(sel,host) + ss = "[" + for o in sel: + if len(ss) > 1: + ss += "," + ss += "FreeCAD.ActiveDocument."+o.Name + ss += "]" + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.removeComponents("+ss+",FreeCAD.ActiveDocument."+host.Name+")") else: - removeComponents(sel) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.removeComponents("+ss+")") FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() class _CommandSplitMesh: @@ -344,7 +406,7 @@ class _CommandSplitMesh: def Activated(self): if FreeCADGui.Selection.getSelection(): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction("Split Mesh") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Split Mesh"))) for obj in sel: n = obj.Name nobjs = splitMesh(obj) @@ -353,6 +415,7 @@ class _CommandSplitMesh: for o in nobjs: g.addObject(o) FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() class _CommandMeshToShape: @@ -381,7 +444,7 @@ class _CommandMeshToShape: if f.InList: if f.InList[0].isDerivedFrom("App::DocumentObjectGroup"): g = f.InList[0] - FreeCAD.ActiveDocument.openTransaction("Mesh to Shape") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Mesh to Shape"))) for obj in FreeCADGui.Selection.getSelection(): newobj = meshToShape(obj) if g and newobj: diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index b6065fa044..5e0206fe93 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -257,11 +257,9 @@ class Component: obj.addProperty("App::PropertyLink","Base","Base", "The base object this component is built upon") obj.addProperty("App::PropertyLinkList","Additions","Base", - "Other shapes that are appended to this wall") + "Other shapes that are appended to this object") obj.addProperty("App::PropertyLinkList","Subtractions","Base", - "Other shapes that are subtracted from this wall") - obj.addProperty("App::PropertyVector","Normal","Base", - "The normal extrusion direction of this wall (keep (0,0,0) for automatic normal)") + "Other shapes that are subtracted from this object") obj.Proxy = self self.Type = "Component" self.Subvolume = None @@ -310,16 +308,23 @@ class ViewProviderComponent: return False class ArchSelectionObserver: - def __init__(self,origin,watched): + def __init__(self,origin,watched,hide=True,nextCommand=None): self.origin = origin self.watched = watched + self.hide = hide + self.nextCommand = nextCommand def addSelection(self,document, object, element, position): if object == self.watched.Name: if not element: print "closing Sketch edit" - self.origin.ViewObject.Transparency = 0 - self.origin.ViewObject.Selectable = True - self.watched.ViewObject.hide() + if self.hide: + self.origin.ViewObject.Transparency = 0 + self.origin.ViewObject.Selectable = True + self.watched.ViewObject.hide() FreeCADGui.activateWorkbench("ArchWorkbench") FreeCADGui.Selection.removeObserver(FreeCAD.ArchObserver) + if self.nextCommand: + FreeCADGui.Selection.clearSelection() + FreeCADGui.Selection.addSelection(self.watched) + FreeCADGui.runCommand(self.nextCommand) del FreeCAD.ArchObserver diff --git a/src/Mod/Arch/ArchFloor.py b/src/Mod/Arch/ArchFloor.py index 4e17d16600..be99561074 100644 --- a/src/Mod/Arch/ArchFloor.py +++ b/src/Mod/Arch/ArchFloor.py @@ -21,25 +21,23 @@ #* * #*************************************************************************** -import ArchCell,FreeCAD,FreeCADGui,Draft,ArchCommands +import FreeCAD,FreeCADGui,Draft,ArchCommands from PyQt4 import QtCore +from DraftTools import translate __title__="FreeCAD Arch Floor" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeFloor(objectslist=None,join=True,name="Floor"): +def makeFloor(objectslist=None,join=True,name=str(translate("Arch","Floor"))): '''makeFloor(objectslist,[joinmode]): creates a floor including the objects from the given list. If joinmode is False, components will not be joined.''' - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) + obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",name) _Floor(obj) _ViewProviderFloor(obj.ViewObject) if objectslist: - obj.Components = objectslist - for comp in obj.Components: - comp.ViewObject.hide() - obj.JoinMode = join + obj.Group = objectslist return obj class _CommandFloor: @@ -55,32 +53,81 @@ class _CommandFloor: ok = False if (len(sel) == 1): if Draft.getType(sel[0]) in ["Cell","Site","Building"]: - FreeCAD.ActiveDocument.openTransaction("Type conversion") - nobj = makeFloor() - ArchCommands.copyProperties(sel[0],nobj) - FreeCAD.ActiveDocument.removeObject(sel[0].Name) + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Type conversion"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("obj = Arch.makeFloor()") + FreeCADGui.doCommand("Arch.copyProperties(FreeCAD.ActiveDocument."+sel[0].Name+",obj)") + FreeCADGui.doCommand('FreeCAD.ActiveDocument.removeObject("'+sel[0].Name+'")') FreeCAD.ActiveDocument.commitTransaction() ok = True if not ok: - FreeCAD.ActiveDocument.openTransaction("Floor") - makeFloor(sel) + ss = "[" + for o in sel: + if len(ss) > 1: + ss += "," + ss += "FreeCAD.ActiveDocument."+o.Name + ss += "]" + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Floor"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeFloor("+ss+")") FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() + FreeCAD.ActiveDocument.recompute() -class _Floor(ArchCell._Cell): - "The Cell object" +class _Floor: + "The Floor object" def __init__(self,obj): - ArchCell._Cell.__init__(self,obj) obj.addProperty("App::PropertyLength","Height","Base", - "The height of this floor") + str(translate("Arch","The height of this floor"))) self.Type = "Floor" + obj.Proxy = self + self.Object = obj + + def __getstate__(self): + return None + + def __setstate__(self,state): + return None + + def execute(self,obj): + pass -class _ViewProviderFloor(ArchCell._ViewProviderCell): - "A View Provider for the Cell object" + def onChanged(self,obj,prop): + self.Object = obj + + def addObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if not child in g: + g.append(child) + self.Object.Group = g + + def removeObject(self,child): + if hasattr(self,"Object"): + g = self.Object.Group + if child in g: + g.remove(child) + self.Object.Group = g + +class _ViewProviderFloor: + "A View Provider for the Floor object" def __init__(self,vobj): - ArchCell._ViewProviderCell.__init__(self,vobj) + vobj.Proxy = self def getIcon(self): + import Arch_rc return ":/icons/Arch_Floor_Tree.svg" + def attach(self,vobj): + self.Object = vobj.Object + return + + def claimChildren(self): + return self.Object.Group + + def __getstate__(self): + return None + + def __setstate__(self,state): + return None + FreeCADGui.addCommand('Arch_Floor',_CommandFloor()) diff --git a/src/Mod/Arch/ArchRoof.py b/src/Mod/Arch/ArchRoof.py new file mode 100644 index 0000000000..e85581e606 --- /dev/null +++ b/src/Mod/Arch/ArchRoof.py @@ -0,0 +1,155 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2012 * +#* Yorik van Havre * +#* * +#* 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 * +#* * +#*************************************************************************** + +import FreeCAD,FreeCADGui,Draft,ArchComponent, DraftVecUtils +from FreeCAD import Vector +from PyQt4 import QtCore +from DraftTools import translate + +__title__="FreeCAD Roof" +__author__ = "Yorik van Havre" +__url__ = "http://free-cad.sourceforge.net" + +def makeRoof(baseobj,facenr=1,angle=45,name=str(translate("Arch","Roof"))): + '''makeRoof(baseobj,[facenr],[angle],[name]) : Makes a roof based on a + face from an existing object. You can provide the number of the face + to build the roof on (default = 1), the angle (default=45) and a name (default + = roof).''' + obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) + _Roof(obj) + _ViewProviderRoof(obj.ViewObject) + obj.Base = baseobj + obj.Face = facenr + obj.Angle = angle + return obj + +class _CommandRoof: + "the Arch Roof command definition" + def GetResources(self): + return {'Pixmap' : 'Arch_Roof', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Roof","Roof"), + 'Accel': "R, F", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Roof","Creates a roof object from the selected face of an object")} + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False + + def Activated(self): + sel = FreeCADGui.Selection.getSelectionEx() + if sel: + sel = sel[0] + obj = sel.Object + if sel.HasSubObjects: + if "Face" in sel.SubElementNames[0]: + idx = int(sel.SubElementNames[0][4:]) + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Roof"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+","+str(idx)+")") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + elif obj.isDerivedFrom("Part::Feature"): + if len(obj.Shape.Faces) == 1: + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Roof"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+",1)") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + elif obj.isDerivedFrom("Part::Feature"): + if len(obj.Shape.Faces) == 1: + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Roof"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeRoof(FreeCAD.ActiveDocument."+obj.Name+",1)") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() + else: + FreeCAD.Console.PrintMessage(str(translate("Arch","Unable to create a roof"))) + else: + FreeCAD.Console.PrintMessage(str(translate("Arch","No object selected"))) + +class _Roof(ArchComponent.Component): + "The Roof object" + def __init__(self,obj): + ArchComponent.Component.__init__(self,obj) + obj.addProperty("App::PropertyAngle","Angle","Base", + str(translate("Arch","The angle of this roof"))) + obj.addProperty("App::PropertyInteger","Face","Base", + str(translate("Arch","The face number of the base object used to build this roof"))) + self.Type = "Structure" + + def execute(self,obj): + self.createGeometry(obj) + + def onChanged(self,obj,prop): + if prop in ["Base","Face","Angle","Additions","Subtractions"]: + self.createGeometry(obj) + + def createGeometry(self,obj): + import Part, math, DraftGeomUtils + pl = obj.Placement + + if obj.Base and obj.Face and obj.Angle: + if len(obj.Base.Shape.Faces) >= obj.Face: + f = obj.Base.Shape.Faces[obj.Face-1] + if len(f.Wires) == 1: + if f.Wires[0].isClosed(): + c = round(math.tan(math.radians(obj.Angle)),Draft.precision()) + norm = f.normalAt(0,0) + d = f.BoundBox.DiagonalLength + edges = DraftGeomUtils.sortEdges(f.Edges) + l = len(edges) + edges.append(edges[0]) + shps = [] + for i in range(l): + v = DraftGeomUtils.vec(DraftGeomUtils.angleBisection(edges[i],edges[i+1])) + v.normalize() + bis = v.getAngle(DraftGeomUtils.vec(edges[i])) + delta = 1/math.cos(bis) + v.multiply(delta) + n = (FreeCAD.Vector(norm)).multiply(c) + dv = v.add(n) + dv.normalize() + dv.scale(d,d,d) + shps.append(f.extrude(dv)) + c = shps.pop() + for s in shps: + c = c.common(s) + c = c.removeSplitter() + if not c.isNull(): + obj.Shape = c + if not DraftGeomUtils.isNull(pl): + obj.Placement = pl + +class _ViewProviderRoof(ArchComponent.ViewProviderComponent): + "A View Provider for the Roof object" + + def __init__(self,vobj): + ArchComponent.ViewProviderComponent.__init__(self,vobj) + + def getIcon(self): + import Arch_rc + return ":/icons/Arch_Roof_Tree.svg" + +FreeCADGui.addCommand('Arch_Roof',_CommandRoof()) diff --git a/src/Mod/Arch/ArchSectionPlane.py b/src/Mod/Arch/ArchSectionPlane.py index c47ca24198..460d3a7d17 100644 --- a/src/Mod/Arch/ArchSectionPlane.py +++ b/src/Mod/Arch/ArchSectionPlane.py @@ -21,12 +21,49 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,Drawing,math +import FreeCAD,FreeCADGui,ArchComponent,WorkingPlane,math,Draft,ArchCommands, DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore from pivy import coin -from draftlibs import fcvec +from DraftTools import translate +def makeSectionPlane(objectslist=None): + """makeSectionPlane([objectslist]) : Creates a Section plane objects including the + given objects. If no object is given, the whole document will be considered.""" + obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Section") + _SectionPlane(obj) + _ViewProviderSectionPlane(obj.ViewObject) + if objectslist: + g = [] + for o in objectslist: + if o.isDerivedFrom("Part::Feature"): + g.append(o) + elif o.isDerivedFrom("App::DocumentObjectGroup"): + g.append(o) + obj.Objects = g + return obj + +def makeSectionView(section): + """makeSectionView(section) : Creates a Drawing view of the given Section Plane + in the active Page object (a new page will be created if none exists""" + page = None + for o in FreeCAD.ActiveDocument.Objects: + if o.isDerivedFrom("Drawing::FeaturePage"): + page = o + break + if not page: + page = FreeCAD.ActiveDocument.addObject("Drawing::FeaturePage",str(translate("Arch","Page"))) + template = Draft.getParam("template") + if not template: + template = FreeCAD.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg' + page.Template = template + + view = FreeCAD.ActiveDocument.addObject("Drawing::FeatureViewPython","View") + page.addObject(view) + _ArchDrawingView(view) + view.Source = section + view.Label = str(translate("Arch","View of"))+" "+section.Name + return view class _CommandSectionPlane: "the Arch SectionPlane command definition" @@ -34,30 +71,21 @@ class _CommandSectionPlane: return {'Pixmap' : 'Arch_SectionPlane', 'Accel': "S, P", 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_SectionPlane","Section Plane"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_SectionPlane","Adds a section plane object to the document")} + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_SectionPlane","Creates a section plane object, including the selected objects")} def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction("Section Plane") - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Section") - _SectionPlane(obj) - _ViewProviderSectionPlane(obj.ViewObject) - FreeCAD.ActiveDocument.commitTransaction() - g = [] + ss = "[" for o in sel: - if o.isDerivedFrom("Part::Feature"): - g.append(o) - obj.Objects = g - page = FreeCAD.ActiveDocument.addObject("Drawing::FeaturePage","Page") - template = FreeCAD.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg' - page.ViewObject.HintOffsetX = 200 - page.ViewObject.HintOffsetY = 100 - page.ViewObject.HintScale = 20 - page.Template = template - view = FreeCAD.ActiveDocument.addObject("Drawing::FeatureViewPython","View") - page.addObject(view) - _ArchDrawingView(view) - view.Source = obj + if len(ss) > 1: + ss += "," + ss += "FreeCAD.ActiveDocument."+o.Name + ss += "]" + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Section Plane"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("section = Arch.makeSectionPlane("+ss+")") + FreeCADGui.doCommand("Arch.makeSectionView(section)") + FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() class _SectionPlane: @@ -65,7 +93,7 @@ class _SectionPlane: def __init__(self,obj): obj.Proxy = self obj.addProperty("App::PropertyLinkList","Objects","Base", - "The objects that must be considered by this section plane. Empty means all document") + str(translate("Arch","The objects that must be considered by this section plane. Empty means all document"))) self.Type = "SectionPlane" def execute(self,obj): @@ -86,7 +114,7 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent): "A View Provider for Section Planes" def __init__(self,vobj): vobj.addProperty("App::PropertyLength","DisplaySize","Base", - "The display size of the section plane") + str(translate("Arch","The display size of this section plane"))) vobj.DisplaySize = 1 vobj.Transparency = 85 vobj.LineWidth = 1 @@ -95,6 +123,7 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent): self.Object = vobj.Object def getIcon(self): + import Arch_rc return ":/icons/Arch_SectionPlane_Tree.svg" def claimChildren(self): @@ -120,7 +149,6 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent): self.setVerts() def setColor(self): - print self.Object.ViewObject.LineColor self.col.rgb.setValue(self.Object.ViewObject.LineColor[0], self.Object.ViewObject.LineColor[1], self.Object.ViewObject.LineColor[2]) @@ -155,9 +183,11 @@ class _ViewProviderSectionPlane(ArchComponent.ViewProviderComponent): class _ArchDrawingView: def __init__(self, obj): obj.addProperty("App::PropertyLink","Source","Base","The linked object") - obj.addProperty("App::PropertyEnumeration","RenderingMode","Base","The rendering mode to use") - obj.RenderingMode = ["Z-sorted","Wireframe","Wireframe + shade"] - obj.RenderingMode = "Z-sorted" + obj.addProperty("App::PropertyEnumeration","RenderingMode","Drawing View","The rendering mode to use") + obj.addProperty("App::PropertyFloat","LineWidth","Drawing View","The line width of the rendered objects") + obj.RenderingMode = ["Solid","Wireframe"] + obj.RenderingMode = "Solid" + obj.LineWidth = 0.35 obj.Proxy = self self.Type = "DrawingView" @@ -169,250 +199,56 @@ class _ArchDrawingView: if prop in ["Source","RenderingMode"]: obj.ViewResult = self.updateSVG(obj) - def updateSVG(self, obj): + def updateSVG(self, obj,join=False): "encapsulates a svg fragment into a transformation node" - if obj.Source: - if obj.Source.Objects: - svg = '' - if obj.RenderingMode == "Z-sorted": - svg += self.renderClassicSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source)) - elif obj.RenderingMode == "Wireframe": - svg += self.renderWireframeSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source)) - elif obj.RenderingMode == "Wireframe + shade": - svg += self.renderOutlineSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source)) - svg += self.renderWireframeSVG(obj.Source.Objects,obj.Source.Proxy.getNormal(obj.Source)) - result = '' - result += ' 0.1: lx = -lx - ny = fcvec.project(vec,plane.v) - ly = ny.Length - if abs(ny.getAngle(plane.v)) > 0.1: ly = -ly - return Vector(lx,ly,0) - - def getPath(self,face,plane): - import Part - from draftlibs import fcgeo - "returns a svg path from a face" - svg =' math.pi/2: - faces.append(face) - print "faces:",faces - if faces: - base = faces.pop() - for face in faces: - base = base.oldFuse(face) - result = self.getPath(base,plane) - return result - - def renderClassicSVG(self,objs,direction,base=None): - """returns an svg fragment from a SectionPlane object, - a direction vector and optionally a base point""" - - def intersection(p1,p2,p3,p4): - "returns the intersection of line (p1,p2) with plane (p3,p4)" - # http://paulbourke.net/geometry/planeline/ - dn = p4.dot(p2.sub(p1)) - if dn != 0: - u = (p4.dot(p3.sub(p1))) / dn - p = p1.add((p2.sub(p1)).scale(u,u,u)) - return p - else: - # line is parallel to normal - vp = fcvec.project(p3.sub(p1),p2.sub(p1)) - l = vp.Length - if vp.getAngle(p2.sub(p1)) > 1: - l = -l - return fcvec.scaleTo(p2.sub(p1),l) - - def getFirstIndex(list1,list2): - "returns the first index from list2 where there is an item of list1" - for i1 in range(len(list1)): - for i2 in range(len(list2)): - if list1[i1].hashCode() == list2[i2].hashCode(): - return i2 - return None - - def getLastIndex(list1,list2): - "returns the last index from list2 where there is an item of list1" - i = None - for i1 in range(len(list1)): - for i2 in range(len(list2)): - if list1[i1].hashCode() == list2[i2].hashCode(): - i = i2 - return i - - def findPrevious(base,dir,faces): - "returns the highest index in faces that is crossed by the given line" - for i in range(len(faces)-1,-1,-1): - print "p1:",base," p2: ",base.add(dir) - obb = faces[i].BoundBox - print "bo: ",obb - op = intersection(base,base.add(dir),faces[i].CenterOfMass,faces[i].normalAt(0,0)) - print "int:", op - if obb.isInside(op): - dv = op.sub(base) - if dv.getAngle(dir) < math.pi/2: - return i - return None - - def findNext(base,dir,faces): - "returns the lowest index in faces that is crossed by the given line" - for i in range(len(faces)): - obb = faces[i].BoundBox - op = intersection(base,base.add(dir),faces[i].CenterOfMass,faces[i].normalAt(0,0)) - if obb.isInside(op): - dv = op.sub(base) - if dv.getAngle(dir) > math.pi/2: - return i - return None - - print "getting representation at ",direction," =======================================>" - - # using Draft WorkingPlane - plane = None - plane = WorkingPlane.plane() - if direction != Vector(0,0,0): - plane.alignToPointAndAxis(Vector(0,0,0),fcvec.neg(direction),0) - else: - direction = Vector(0,0,-1) - print "plane:",plane - sortedFaces = [] - - if not base: - # getting the base point = first point from the bounding box - bb = FreeCAD.BoundBox() - for o in objs: - bb.add(o.Shape.BoundBox) - rad = bb.DiagonalLength/2 - rv = bb.Center.add(direction) - rv = fcvec.scaleTo(rv,rad) - rv = fcvec.neg(rv) - base = bb.Center.add(rv) - - print "base:",base - - # getting faces - unsortedFaces = [] - notFoundFaces = [] - for o in objs: - unsortedFaces.append(o.Name) - unsortedFaces.extend(o.Shape.Faces[:]) - print "analyzing ",len(unsortedFaces)," faces" - - for face in unsortedFaces: - - if isinstance(face,str): - print "OBJECT ",face," =======================================>" - continue - - print "testing face ",unsortedFaces.index(face) - - # testing if normal points outwards - normal = face.normalAt(0,0) - if normal.getAngle(direction) <= math.pi/2: - print "normal pointing outwards" - continue - - fprev = 0 - fnext = len(sortedFaces) - notFound = True - - print "checking ",len(face.Vertexes)," verts" - - for v in face.Vertexes: - vprev = findPrevious(v.Point,direction,sortedFaces) - vnext = findNext(v.Point,direction,sortedFaces) - print "temp indexes:",vprev,vnext - if (vprev != None): - notfound = False - if (vprev > fprev): - fprev = vprev - if (vnext != None): - notfound = False - if (vnext < fnext): - fnext = vnext - - print "fprev:",fprev - print "fnext:",fnext - print "notFound",notFound - - if fnext < fprev: - raise "Error, impossible index" - elif fnext == fprev: - sortedFaces.insert(fnext,face) - else: - sortedFaces.insert(fnext,face) - - print len(sortedFaces)," sorted faces:",sortedFaces - - # building SVG representation in correct order - svg = '' - for f in sortedFaces: - svg += self.getPath(f,plane) - - return svg - FreeCADGui.addCommand('Arch_SectionPlane',_CommandSectionPlane()) diff --git a/src/Mod/Arch/ArchSite.py b/src/Mod/Arch/ArchSite.py index eb3f5a1fd1..f6c6e9acbb 100644 --- a/src/Mod/Arch/ArchSite.py +++ b/src/Mod/Arch/ArchSite.py @@ -21,22 +21,22 @@ #* * #*************************************************************************** -import ArchCell,FreeCAD,FreeCADGui,Draft,ArchCommands +import FreeCAD,FreeCADGui,Draft,ArchCommands,ArchFloor from PyQt4 import QtCore +from DraftTools import translate __title__="FreeCAD Site" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeSite(objectslist=None,name="Site"): +def makeSite(objectslist=None,name=str(translate("Arch","Site"))): '''makeBuilding(objectslist): creates a site including the objects from the given list.''' - obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) + obj = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroupPython",name) _Site(obj) _ViewProviderSite(obj.ViewObject) if objectslist: - obj.Components = objectslist - obj.JoinMode = False + obj.Group = objectslist return obj class _CommandSite: @@ -52,36 +52,45 @@ class _CommandSite: ok = False if (len(sel) == 1): if Draft.getType(sel[0]) in ["Cell","Building","Floor"]: - FreeCAD.ActiveDocument.openTransaction("Type conversion") + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Type conversion"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("obj = Arch.makeSite()") + FreeCADGui.doCommand("Arch.copyProperties(FreeCAD.ActiveDocument."+sel[0].Name+",obj)") + FreeCADGui.doCommand('FreeCAD.ActiveDocument.removeObject("'+sel[0].Name+'")') + nobj = makeSite() ArchCommands.copyProperties(sel[0],nobj) FreeCAD.ActiveDocument.removeObject(sel[0].Name) FreeCAD.ActiveDocument.commitTransaction() ok = True if not ok: - FreeCAD.ActiveDocument.openTransaction("Site") - makeSite(sel) + ss = "[" + for o in sel: + if len(ss) > 1: + ss += "," + ss += "FreeCAD.ActiveDocument."+o.Name + ss += "]" + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Site"))) + FreeCADGui.doCommand("import Arch") + FreeCADGui.doCommand("Arch.makeSite("+ss+")") FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() - -class _Site(ArchCell._Cell): + +class _Site(ArchFloor._Floor): "The Site object" def __init__(self,obj): - ArchCell._Cell.__init__(self,obj) + ArchFloor._Floor.__init__(self,obj) self.Type = "Site" - - def execute(self,obj): - pass - - def onChanged(self,obj,prop): - pass - -class _ViewProviderSite(ArchCell._ViewProviderCell): + obj.setEditorMode('Height',2) + +class _ViewProviderSite(ArchFloor._ViewProviderFloor): "A View Provider for the Site object" def __init__(self,vobj): - ArchCell._ViewProviderCell.__init__(self,vobj) + ArchFloor._ViewProviderFloor.__init__(self,vobj) def getIcon(self): + import Arch_rc return ":/icons/Arch_Site_Tree.svg" + FreeCADGui.addCommand('Arch_Site',_CommandSite()) diff --git a/src/Mod/Arch/ArchStructure.py b/src/Mod/Arch/ArchStructure.py index daa7b25e9b..1a9f51c071 100644 --- a/src/Mod/Arch/ArchStructure.py +++ b/src/Mod/Arch/ArchStructure.py @@ -21,16 +21,16 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore +from DraftTools import translate __title__="FreeCAD Structure" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeStructure(baseobj=None,length=None,width=None,height=None,name="Structure"): +def makeStructure(baseobj=None,length=None,width=None,height=None,name=str(translate("Arch","Structure"))): '''makeStructure([obj],[length],[width],[heigth],[swap]): creates a structure element based on the given profile object and the given extrusion height. If no base object is given, you can also specify @@ -65,27 +65,31 @@ class _CommandStructure: 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Structure","Creates a structure object from scratch or from a selected object (sketch, wire, face or solid)")} def Activated(self): + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Structure"))) + FreeCADGui.doCommand("import Arch") sel = FreeCADGui.Selection.getSelection() if sel: - FreeCAD.ActiveDocument.openTransaction("Structure") for obj in sel: - makeStructure(obj) - FreeCAD.ActiveDocument.commitTransaction() + FreeCADGui.doCommand("Arch.makeStructure(FreeCAD.ActiveDocument."+obj.Name+")") else: - makeStructure() + FreeCADGui.doCommand("Arch.makeStructure()") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() class _Structure(ArchComponent.Component): "The Structure object" def __init__(self,obj): ArchComponent.Component.__init__(self,obj) obj.addProperty("App::PropertyLength","Length","Base", - "The length of this element, if not based on a profile") + str(translate("Arch","The length of this element, if not based on a profile"))) obj.addProperty("App::PropertyLength","Width","Base", - "The width of this element, if not based on a profile") + str(translate("Arch","The width of this element, if not based on a profile"))) obj.addProperty("App::PropertyLength","Height","Base", - "The height or extrusion depth of this element. Keep 0 for automatic") + str(translate("Arch","The height or extrusion depth of this element. Keep 0 for automatic"))) obj.addProperty("App::PropertyLinkList","Axes","Base", - "Axes systems this structure is built on") + str(translate("Arch","Axes systems this structure is built on"))) + obj.addProperty("App::PropertyVector","Normal","Base", + str(translate("Arch","The normal extrusion direction of this object (keep (0,0,0) for automatic normal)"))) self.Type = "Structure" def execute(self,obj): @@ -97,7 +101,7 @@ class _Structure(ArchComponent.Component): def getAxisPoints(self,obj): "returns the gridpoints of linked axes" - from draftlibs import fcgeo + import DraftGeomUtils pts = [] if len(obj.Axes) == 1: for e in obj.Axes[0].Shape.Edges: @@ -107,22 +111,21 @@ class _Structure(ArchComponent.Component): set2 = obj.Axes[1].Shape.Edges for e1 in set1: for e2 in set2: - pts.extend(fcgeo.findIntersection(e1,e2)) + pts.extend(DraftGeomUtils.findIntersection(e1,e2)) return pts def createGeometry(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils # getting default values height = normal = None if obj.Length: length = obj.Length else: length = 1 - if obj.Width: - width = obj.Width - else: - width = 1 + width = 1 + if hasattr(obj,"Width"): + if obj.Width: + width = obj.Width if obj.Height: height = obj.Height else: @@ -160,18 +163,13 @@ class _Structure(ArchComponent.Component): base = Part.Face(base) base = base.extrude(normal) for app in obj.Additions: - base = base.oldFuse(app.Shape) - app.ViewObject.hide() # to be removed + if hasattr(app,"Shape"): + if not app.Shape.isNull(): + base = base.fuse(app.Shape) + app.ViewObject.hide() # to be removed for hole in obj.Subtractions: - cut = False - if hasattr(hole,"Proxy"): - if hasattr(hole.Proxy,"Subvolume"): - if hole.Proxy.Subvolume: - print "cutting subvolume",hole.Proxy.Subvolume - base = base.cut(hole.Proxy.Subvolume) - cut = True - if not cut: - if hasattr(obj,"Shape"): + if hasattr(hole,"Shape"): + if not hole.Shape.isNull(): base = base.cut(hole.Shape) hole.ViewObject.hide() # to be removed if base: @@ -184,8 +182,10 @@ class _Structure(ArchComponent.Component): fsh.append(sh) obj.Shape = Part.makeCompound(fsh) else: - obj.Shape = base - if not fcgeo.isNull(pl): obj.Placement = pl + if not base.isNull(): + base = base.removeSplitter() + obj.Shape = base + if not DraftGeomUtils.isNull(pl): obj.Placement = pl class _ViewProviderStructure(ArchComponent.ViewProviderComponent): "A View Provider for the Structure object" @@ -193,7 +193,8 @@ class _ViewProviderStructure(ArchComponent.ViewProviderComponent): def __init__(self,vobj): ArchComponent.ViewProviderComponent.__init__(self,vobj) - def getIcon(self): + def getIcon(self): + import Arch_rc return ":/icons/Arch_Structure_Tree.svg" FreeCADGui.addCommand('Arch_Structure',_CommandStructure()) diff --git a/src/Mod/Arch/ArchVRM.py b/src/Mod/Arch/ArchVRM.py new file mode 100644 index 0000000000..2eefd8f279 --- /dev/null +++ b/src/Mod/Arch/ArchVRM.py @@ -0,0 +1,609 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2012 * +#* Yorik van Havre * +#* * +#* 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 * +#* * +#*************************************************************************** + +"The FreeCAD Arch Vector Rendering Module" + +import FreeCAD,math,Part,ArchCommands,DraftVecUtils,DraftGeomUtils + +DEBUG = True # if we want debug messages +MAXLOOP = 10 # the max number of loop before abort + +# WARNING: in this module, faces are lists whose first item is the actual OCC face, the +# other items being additional information such as color, etc. + +class Renderer: + "A renderer object" + def __init__(self,wp=None): + + """ + Creates a renderer with a default Draft WorkingPlane + Use like this: + + import ArchVRM + p = ArchVRM.Renderer() + p.add(App.ActiveDocument.ActiveObject) + p.sort() + p.buildDummy() + """ + + self.reset() + if wp: + self.wp = wp + else: + import WorkingPlane + self.wp = WorkingPlane.plane() + + if DEBUG: print "Renderer initialized on " + str(self.wp) + + def __str__(self): + return "Arch Renderer: " + str(len(self.faces)) + " faces projected on " + str(self.wp) + + def reset(self): + "removes all faces from this renderer" + self.objects = [] + self.shapes = [] + self.faces = [] + self.resetFlags() + + def resetFlags(self): + "resets all flags of this renderer" + self.oriented = False + self.trimmed = False + self.sorted = False + self.iscut = False + self.joined = False + self.sections = [] + + def setWorkingPlane(self,wp): + "sets a Draft WorkingPlane or Placement for this renderer" + if isinstance(wp,FreeCAD.Placement): + self.wp.setFromPlacement(wp) + else: + self.wp = wp + if DEBUG: print "Renderer set on " + str(self.wp) + + def addFaces(self,faces,color=(0.9,0.9,0.9,1.0)): + "add individual faces to this renderer, optionally with a color" + if DEBUG: print "adding ", len(faces), " faces. Warning, these will get lost if using cut() or join()" + for f in faces: + self.faces.append([f,color]) + self.resetFlags() + + def addObjects(self,objs): + "add objects to this renderer" + for o in objs: + if o.isDerivedFrom("Part::Feature"): + self.objects.append(o) + color = o.ViewObject.ShapeColor + if o.Shape.Faces: + self.shapes.append([o.Shape,color]) + for f in o.Shape.Faces: + self.faces.append([f,color]) + self.resetFlags() + if DEBUG: print "adding ", len(self.objects), " objects, ", len(self.faces), " faces" + + def addShapes(self,shapes,color=(0.9,0.9,0.9,1.0)): + "add shapes to this renderer, optionally with a color. Warning, these will get lost if using join()" + if DEBUG: print "adding ", len(shapes), " shapes" + for s in shapes: + if s.Faces: + self.shapes.append([s,color]) + for f in s.Faces: + self.faces.append([f,color]) + self.resetFlags() + + def info(self): + "Prints info about the contents of this renderer" + r = str(self)+"\n" + r += "oriented: " + str(self.oriented) + "\n" + r += "trimmed: " + str(self.trimmed) + "\n" + r += "sorted: " + str(self.sorted) + "\n" + r += "contains " + str(len(self.faces)) + " faces\n" + for i in range(len(self.faces)): + r += " face " + str(i) + " : center " + str(self.faces[i][0].CenterOfMass) + r += " : normal " + str(self.faces[i][0].normalAt(0,0)) + r += ", " + str(len(self.faces[i][0].Vertexes)) + " verts" + r += ", color: " + self.getFill(self.faces[i][1]) + "\n" + return r + + def addLabels(self): + "Add labels on the model to identify faces" + c = 0 + for f in self.faces: + l = FreeCAD.ActiveDocument.addObject("App::AnnotationLabel","facelabel") + l.BasePosition = f[0].CenterOfMass + l.LabelText = str(c) + c += 1 + + def isVisible(self,face): + "returns True if the given face points in the view direction" + normal = face[0].normalAt(0,0) + if DEBUG: print "checking face normal ", normal, " against ", self.wp.axis, " : ", math.degrees(normal.getAngle(self.wp.axis)) + if normal.getAngle(self.wp.axis) < math.pi/2: + return True + return False + + def reorient(self): + "reorients the faces on the WP" + 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 + + def removeHidden(self): + "removes faces pointing outwards" + if not self.faces: + return + faces = [] + for f in self.faces: + if self.isVisible(f): + faces.append(f) + if DEBUG: print len(self.faces)-len(faces) , " faces removed, ", len(faces), " faces retained" + self.faces = faces + self.trimmed = True + + def projectFace(self,face): + "projects a single face on the WP" + wires = [] + norm = face[0].normalAt(0,0) + for w in face[0].Wires: + verts = [] + edges = DraftGeomUtils.sortEdges(w.Edges) + for e in edges: + v = e.Vertexes[0].Point + v = self.wp.getLocalCoords(v) + verts.append(v) + verts.append(verts[0]) + if len(verts) > 2: + wires.append(Part.makePolygon(verts)) + try: + sh = ArchCommands.makeFace(wires) + except: + if DEBUG: print "Error: Unable to project face on the WP" + return None + else: + # restoring flipped normals + vnorm = self.wp.getLocalCoords(norm) + if vnorm.getAngle(sh.normalAt(0,0)) > 1: + sh.reverse() + return [sh]+face[1:] + + def flattenFace(self,face): + "Returns a face where all vertices have Z = 0" + wires = [] + for w in face[0].Wires: + verts = [] + edges = DraftGeomUtils.sortEdges(w.Edges) + for e in edges: + v = e.Vertexes[0].Point + verts.append(FreeCAD.Vector(v.x,v.y,0)) + verts.append(verts[0]) + wires.append(Part.makePolygon(verts)) + try: + sh = Part.Face(wires) + except: + if DEBUG: print "Error: Unable to flatten face" + return None + else: + return [sh]+face[1:] + + def cut(self,cutplane): + "Cuts through the shapes with a given cut plane and builds section faces" + if self.iscut: + return + if not self.shapes: + if DEBUG: print "No objects to make sections" + else: + fill = (1.0,1.0,1.0,1.0) + placement = FreeCAD.Placement(cutplane.Placement) + + # building boundbox + bb = self.shapes[0][0].BoundBox + for sh in self.shapes[1:]: + bb.add(sh[0].BoundBox) + bb.enlarge(1) + um = vm = wm = 0 + if not bb.isCutPlane(placement.Base,self.wp.axis): + if DEBUG: print "No objects are cut by the plane" + else: + corners = [FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMin), + FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMin), + FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMin), + FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMin), + FreeCAD.Vector(bb.XMin,bb.YMin,bb.ZMax), + FreeCAD.Vector(bb.XMin,bb.YMax,bb.ZMax), + FreeCAD.Vector(bb.XMax,bb.YMin,bb.ZMax), + FreeCAD.Vector(bb.XMax,bb.YMax,bb.ZMax)] + for c in corners: + dv = c.sub(placement.Base) + um1 = DraftVecUtils.project(dv,self.wp.u).Length + um = max(um,um1) + vm1 = DraftVecUtils.project(dv,self.wp.v).Length + vm = max(vm,vm1) + wm1 = DraftVecUtils.project(dv,self.wp.axis).Length + wm = max(wm,wm1) + p1 = FreeCAD.Vector(-um,vm,0) + p2 = FreeCAD.Vector(um,vm,0) + p3 = FreeCAD.Vector(um,-vm,0) + p4 = FreeCAD.Vector(-um,-vm,0) + cutface = Part.makePolygon([p1,p2,p3,p4,p1]) + cutface = Part.Face(cutface) + cutface.Placement = placement + cutnormal = DraftVecUtils.scaleTo(self.wp.axis,wm) + cutvolume = cutface.extrude(cutnormal) + shapes = [] + faces = [] + sections = [] + for sh in self.shapes: + for sol in sh[0].Solids: + c = sol.cut(cutvolume) + 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]) + self.shapes = shapes + self.faces = faces + self.sections = sections + if DEBUG: print "Built ",len(self.sections)," sections, ", len(self.faces), " faces retained" + self.iscut = True + self.oriented = False + self.trimmed = False + self.sorted = False + self.joined = False + + def isInside(self,vert,face): + "Returns True if the vert is inside the face in Z projection" + + # http://paulbourke.net/geometry/insidepoly/ + count = 0 + p = self.wp.getLocalCoords(vert.Point) + for e in face[0].Edges: + p1 = e.Vertexes[0].Point + p2 = e.Vertexes[-1].Point + if p.y > min(p1.y,p2.y): + if p.y <= max(p1.y,p2.y): + if p.x <= max(p1.x,p2.x): + if p1.y != p2.y: + xinters = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x + if (p1.x == p2.x) or (p.x <= xinters): + count += 1 + if count % 2 == 0: + return False + else: + return True + + def zOverlaps(self,face1,face2): + "Checks if face1 overlaps face2 in Z direction" + face1 = self.flattenFace(face1) + face2 = self.flattenFace(face2) + + # first we check if one of the verts is inside the other face + for v in face1[0].Vertexes: + if self.isInside(v,face2): + return True + + # even so, faces can still overlap if their edges cross each other + for e1 in face1[0].Edges: + for e2 in face2[0].Edges: + if DraftGeomUtils.findIntersection(e1,e2): + return True + return False + + def compare(self,face1,face2): + "zsorts two faces. Returns 1 if face1 is closer, 2 if face2 is closer, 0 otherwise" + + # theory from + # http://www.siggraph.org/education/materials/HyperGraph/scanline/visibility/painter.htm + # and practical application http://vrm.ao2.it/ (blender vector renderer) + + b1 = face1[0].BoundBox + b2 = face2[0].BoundBox + + # test 1: if faces don't overlap, no comparison possible + if DEBUG: print "doing test 1" + if b1.XMax < b2.XMin: + return 0 + if b1.XMin > b2.XMax: + return 0 + if b1.YMax < b2.YMin: + return 0 + if b1.YMin > b2.YMax: + return 0 + if DEBUG: print "failed, faces bboxes are not distinct" + + # test 2: if Z bounds dont overlap, it's easy to know the closest + if DEBUG: print "doing test 2" + if b1.ZMax < b2.ZMin: + return 2 + if b2.ZMax < b1.ZMin: + return 1 + if DEBUG: print "failed, faces Z are not distinct" + + # test 3: all verts of face1 are in front or behind the plane of face2 + if DEBUG: print "doing test 3" + norm = face2[0].normalAt(0,0) + behind = 0 + front = 0 + for v in face1[0].Vertexes: + dv = v.Point.sub(face2[0].Vertexes[0].Point) + dv = DraftVecUtils.project(dv,norm) + if DraftVecUtils.isNull(dv): + behind += 1 + front += 1 + else: + if dv.getAngle(norm) > 1: + behind += 1 + else: + front += 1 + if DEBUG: print "front: ",front," behind: ",behind + if behind == len(face1[0].Vertexes): + return 2 + elif front == len(face1[0].Vertexes): + return 1 + if DEBUG: print "failed, cannot say if face 1 is in front or behind" + + # test 4: all verts of face2 are in front or behind the plane of face1 + if DEBUG: print "doing test 4" + norm = face1[0].normalAt(0,0) + behind = 0 + front = 0 + for v in face2[0].Vertexes: + dv = v.Point.sub(face1[0].Vertexes[0].Point) + dv = DraftVecUtils.project(dv,norm) + if DraftVecUtils.isNull(dv): + behind += 1 + front += 1 + else: + if dv.getAngle(norm) > 1: + behind += 1 + else: + front += 1 + if DEBUG: print "front: ",front," behind: ",behind + if behind == len(face2[0].Vertexes): + return 1 + elif front == len(face2[0].Vertexes): + return 2 + if DEBUG: print "failed, cannot say if face 2 is in front or behind" + + # test 5: see if faces projections don't overlap, vertexwise + if DEBUG: print "doing test 5" + if not self.zOverlaps(face1,face2): + return 0 + elif not self.zOverlaps(face2,face1): + return 0 + if DEBUG: print "failed, faces are overlapping" + + if DEBUG: print "Houston, all tests passed, and still no results" + return 0 + + def join(self,otype): + "joins the objects of same type" + walls = [] + structs = [] + objs = [] + for o in obj.Source.Objects: + t = Draft.getType(o) + if t == "Wall": + walls.append(o) + elif t == "Structure": + structs.append(o) + else: + objs.append(o) + for g in [walls,structs]: + if g: + print "group:",g + col = g[0].ViewObject.DiffuseColor[0] + s = g[0].Shape + for o in g[1:]: + try: + fs = s.fuse(o.Shape) + fs = fs.removeSplitter() + except: + print "shape fusion failed" + objs.append([o.Shape,o.ViewObject.DiffuseColor[0]]) + else: + s = fs + objs.append([s,col]) + + def findPosition(self,f1,faces): + "Finds the position of a face in a list of faces" + l = None + h = None + for f2 in faces: + if DEBUG: print "comparing face",str(self.faces.index(f1))," with face",str(self.faces.index(f2)) + r = self.compare(f1,f2) + if r == 1: + l = faces.index(f2) + elif r == 2: + if h == None: + h = faces.index(f2) + else: + if faces.index(f2) < h: + h = faces.index(f2) + if l != None: + return l + 1 + elif h != None: + return h + else: + return None + + def sort(self): + "projects a shape on the WP" + if len(self.faces) <= 1: + return + if not self.trimmed: + self.removeHidden() + if len(self.faces) == 1: + return + if not self.oriented: + self.reorient() + faces = self.faces[:] + if DEBUG: print "sorting ",len(self.faces)," faces" + sfaces = [] + loopcount = 0 + notfoundstack = 0 + while faces: + if DEBUG: print "loop ", loopcount + f1 = faces[0] + if sfaces and (notfoundstack < len(faces)): + if DEBUG: print "using ordered stack, notfound = ",notfoundstack + p = self.findPosition(f1,sfaces) + if p == None: + # no position found, we move the face to the end of the pile + faces.remove(f1) + faces.append(f1) + notfoundstack += 1 + else: + # position found, we insert it + faces.remove(f1) + sfaces.insert(p,f1) + notfoundstack = 0 + else: + # either there is no stack, or no more face can be compared + # find a root, 2 faces that can be compared + if DEBUG: print "using unordered stack, notfound = ",notfoundstack + 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) + if r == 1: + faces.remove(f2) + sfaces.append(f2) + faces.remove(f1) + sfaces.append(f1) + notfoundstack = 0 + break + elif r == 2: + faces.remove(f1) + sfaces.append(f1) + faces.remove(f2) + sfaces.append(f2) + notfoundstack = 0 + break + else: + # nothing found, move the face to the end of the pile + faces.remove(f1) + faces.append(f1) + loopcount += 1 + if loopcount == MAXLOOP * len(self.faces): + if DEBUG: print "Too many loops, aborting." + break + + if DEBUG: print "done Z sorting. ", len(sfaces), " faces retained, ", len(self.faces)-len(sfaces), " faces lost." + self.faces = sfaces + self.sorted = True + + def buildDummy(self): + "Builds a dummy object with faces spaced on the Z axis, for visual check" + z = 0 + if not self.sorted: + self.sort() + faces = [] + for f in self.faces[:]: + ff = self.flattenFace(f)[0] + ff.translate(FreeCAD.Vector(0,0,z)) + faces.append(ff) + z += 1 + if faces: + c = Part.makeCompound(faces) + Part.show(c) + + def getFill(self,fill): + "Returns a SVG fill value" + r = str(hex(int(fill[0]*255)))[2:].zfill(2) + g = str(hex(int(fill[1]*255)))[2:].zfill(2) + b = str(hex(int(fill[2]*255)))[2:].zfill(2) + col = "#"+r+g+b + return col + + def getPathData(self,w): + "Returns a SVG path data string from a 2D wire" + edges = DraftGeomUtils.sortEdges(w.Edges) + v = edges[0].Vertexes[0].Point + svg = 'M '+ str(v.x) +' '+ str(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) + ' ' + 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 ' + return svg + + def getViewSVG(self,linewidth=0.01): + "Returns a SVG fragment from viewed faces" + if DEBUG: print "Printing ", len(self.faces), " faces" + if not self.sorted: + self.sort() + svg = '' + for f in self.faces: + fill = self.getFill(f[1]) + svg +=' max_length: + max_length = w.BoundBox.DiagonalLength + f = w + if f: + f = Part.Face(f) + n = f.normalAt(0,0) + v1 = DraftVecUtils.scaleTo(n,width) + f.translate(v1) + v2 = DraftVecUtils.neg(v1) + v2 = DraftVecUtils.scale(v1,-2) + f = f.extrude(v2) + if delta: + f.translate(delta) + return f + return None + + def createGeometry(self,obj): + "builds the wall shape" + + if not obj.Base: + return + + import Part, DraftGeomUtils flat = False if hasattr(obj.ViewObject,"DisplayMode"): flat = (obj.ViewObject.DisplayMode == "Flat 2D") + + width = 1.0 + if hasattr(obj,"Width"): + if obj.Width: + width = obj.Width def getbase(wire): "returns a full shape from a base wire" - dvec = fcgeo.vec(wire.Edges[0]).cross(normal) + dvec = DraftGeomUtils.vec(wire.Edges[0]).cross(normal) dvec.normalize() if obj.Align == "Left": - dvec = dvec.multiply(obj.Width) - w2 = fcgeo.offsetWire(wire,dvec) - sh = fcgeo.bind(wire,w2) + dvec = dvec.multiply(width) + w2 = DraftGeomUtils.offsetWire(wire,dvec) + w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) + sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Right": - dvec = dvec.multiply(obj.Width) - dvec = fcvec.neg(dvec) - w2 = fcgeo.offsetWire(wire,dvec) - sh = fcgeo.bind(wire,w2) + dvec = dvec.multiply(width) + dvec = DraftVecUtils.neg(dvec) + w2 = DraftGeomUtils.offsetWire(wire,dvec) + w1 = Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)) + sh = DraftGeomUtils.bind(w1,w2) elif obj.Align == "Center": - dvec = dvec.multiply(obj.Width/2) - w1 = fcgeo.offsetWire(wire,dvec) - dvec = fcvec.neg(dvec) - w2 = fcgeo.offsetWire(wire,dvec) - sh = fcgeo.bind(w1,w2) + dvec = dvec.multiply(width/2) + w1 = DraftGeomUtils.offsetWire(wire,dvec) + dvec = DraftVecUtils.neg(dvec) + w2 = DraftGeomUtils.offsetWire(wire,dvec) + sh = DraftGeomUtils.bind(w1,w2) # fixing self-intersections sh.fix(0.1,0,1) if height and (not flat): @@ -303,12 +355,13 @@ class _Wall(ArchComponent.Component): normal = Vector(obj.Normal) # computing shape - if obj.Base: - if obj.Base.isDerivedFrom("Part::Feature"): + base = None + if obj.Base.isDerivedFrom("Part::Feature"): + if not obj.Base.Shape.isNull(): base = obj.Base.Shape.copy() if base.Solids: pass - elif base.Faces: + elif base.Faces and (not obj.ForceWire): if height: norm = normal.multiply(height) base = base.extrude(norm) @@ -317,36 +370,52 @@ class _Wall(ArchComponent.Component): for wire in obj.Base.Shape.Wires: sh = getbase(wire) if temp: - temp = temp.oldFuse(sh) + temp = temp.fuse(sh) else: temp = sh base = temp - else: - if obj.Length == 0: - return - v1 = Vector(0,0,0) - v2 = Vector(obj.Length,0,0) - w = Part.Wire(Part.Line(v1,v2).toShape()) - base = getbase(w) - - for app in obj.Additions: - base = base.oldFuse(app.Shape) - app.ViewObject.hide() #to be removed - for hole in obj.Subtractions: - cut = False - if hasattr(hole,"Proxy"): - if hasattr(hole.Proxy,"Subvolume"): - if hole.Proxy.Subvolume: - print "cutting subvolume",hole.Proxy.Subvolume - base = base.cut(hole.Proxy.Subvolume) - cut = True - if not cut: - if hasattr(obj,"Shape"): - base = base.cut(hole.Shape) - hole.ViewObject.hide() # to be removed - obj.Shape = base - if not fcgeo.isNull(pl): - obj.Placement = pl + elif base.Edges: + wire = Part.Wire(base.Edges) + sh = getbase(wire) + if sh: + base = sh + else: + FreeCAD.Console.PrintError(str(translate("Arch","Error: Invalid base object"))) + + if base: + for app in obj.Additions: + if hasattr(app,"Shape"): + if app.Shape: + if not app.Shape.isNull(): + base = base.fuse(app.Shape) + app.ViewObject.hide() #to be removed + + for hole in obj.Subtractions: + if Draft.getType(hole) == "Window": + # window + if hole.Base and obj.Width: + f = self.getSubVolume(hole.Base,width) + if f: + base = base.cut(f) + elif Draft.isClone(hole,"Window"): + if hole.Objects[0].Base and width: + f = self.getSubVolume(hole.Objects[0].Base,width,hole.Placement.Base) + if f: + base = base.cut(f) + elif hasattr(hole,"Shape"): + if hole.Shape: + if not hole.Shape.isNull(): + base = base.cut(hole.Shape) + hole.ViewObject.hide() # to be removed + + if not base.isNull(): + try: + base = base.removeSplitter() + except: + FreeCAD.Console.PrintError(str(translate("Arch","Error removing splitter from wall shape"))) + obj.Shape = base + if not DraftGeomUtils.isNull(pl): + obj.Placement = pl class _ViewProviderWall(ArchComponent.ViewProviderComponent): "A View Provider for the Wall object" @@ -354,7 +423,8 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent): def __init__(self,vobj): ArchComponent.ViewProviderComponent.__init__(self,vobj) - def getIcon(self): + def getIcon(self): + import Arch_rc return ":/icons/Arch_Wall_Tree.svg" def getDisplayModes(self,vobj): diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index f6f1303cb6..ad9d493699 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -21,24 +21,31 @@ #* * #*************************************************************************** -import FreeCAD,FreeCADGui,Draft,ArchComponent -from draftlibs import fcvec +import FreeCAD,FreeCADGui,Draft,ArchComponent,DraftVecUtils from FreeCAD import Vector from PyQt4 import QtCore,QtGui +from DraftTools import translate __title__="FreeCAD Wall" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -def makeWindow(baseobj=None,name="Window"): +def makeWindow(baseobj=None,width=None,name=str(translate("Arch","Window"))): '''makeWindow(obj,[name]): creates a window based on the given object''' + if baseobj: + if Draft.getType(baseobj) == "Window": + obj = Draft.clone(baseobj) + return obj obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) _Window(obj) _ViewProviderWindow(obj.ViewObject) if baseobj: obj.Base = baseobj - obj.WindowParts = makeDefaultWindowPart(baseobj) + if width: + obj.WindowParts = ["Default","Panel","Wire0",str(width),"0"] + else: + obj.WindowParts = makeDefaultWindowPart(baseobj) if obj.Base: obj.Base.ViewObject.DisplayMode = "Wireframe" obj.Base.ViewObject.hide() @@ -71,26 +78,48 @@ class _CommandWindow: return {'Pixmap' : 'Arch_Window', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Window"), 'Accel': "W, N", - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Creates a window object from scratch or from a selected object (wire, rectangle or sketch)")} + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Creates a window object from a selected object (wire, rectangle or sketch)")} + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False def Activated(self): sel = FreeCADGui.Selection.getSelection() - FreeCAD.ActiveDocument.openTransaction("Window") if sel: - for obj in sel: - makeWindow(obj) - else: - rect = Draft.makeRectangle(1,1) - makeWindow(rect) - FreeCAD.ActiveDocument.commitTransaction() + if Draft.getType(sel[0]) == "Wall": + FreeCADGui.activateWorkbench("SketcherWorkbench") + FreeCADGui.runCommand("Sketcher_NewSketch") + FreeCAD.ArchObserver = ArchComponent.ArchSelectionObserver(sel[0],FreeCAD.ActiveDocument.Objects[-1],hide=False,nextCommand="Arch_Window") + FreeCADGui.Selection.addObserver(FreeCAD.ArchObserver) + else: + FreeCAD.ActiveDocument.openTransaction(str(translate("Arch","Create Window"))) + FreeCADGui.doCommand("import Arch") + for obj in sel: + FreeCADGui.doCommand("Arch.makeWindow(FreeCAD.ActiveDocument."+obj.Name+")") + if hasattr(obj,"Support"): + if obj.Support: + if isinstance(obj.Support,tuple): + s = obj.Support[0] + else: + s = obj.Support + w = FreeCAD.ActiveDocument.Objects[-1] # last created object + FreeCADGui.doCommand("Arch.removeComponents(FreeCAD.ActiveDocument."+w.Name+",host=FreeCAD.ActiveDocument."+s.Name+")") + elif Draft.isClone(w,"Window"): + if w.Objects[0].Inlist: + FreeCADGui.doCommand("Arch.removeComponents(FreeCAD.ActiveDocument."+w.Name+",host=FreeCAD.ActiveDocument."+w.Objects[0].Inlist[0].Name+")") + FreeCAD.ActiveDocument.commitTransaction() class _Window(ArchComponent.Component): "The Window object" def __init__(self,obj): ArchComponent.Component.__init__(self,obj) obj.addProperty("App::PropertyStringList","WindowParts","Base", - "the components of this window") + str(translate("Arch","the components of this window"))) self.Type = "Window" + obj.Proxy = self def execute(self,obj): self.createGeometry(obj) @@ -100,45 +129,49 @@ class _Window(ArchComponent.Component): self.createGeometry(obj) def createGeometry(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils pl = obj.Placement if obj.Base: if obj.Base.isDerivedFrom("Part::Feature"): - if obj.WindowParts and (len(obj.WindowParts)%5 == 0): - shapes = [] - for i in range(len(obj.WindowParts)/5): - wires = [] - wstr = obj.WindowParts[(i*5)+2].split(',') - for s in wstr: - j = int(s[4:]) - if len(obj.Base.Shape.Wires) >= j: - wires.append(obj.Base.Shape.Wires[j]) - if wires: - max_length = 0 - for w in wires: - if w.BoundBox.DiagonalLength > max_length: - max_length = w.BoundBox.DiagonalLength - ext = w - wires.remove(ext) - for w in wires: - w.reverse() - wires.insert(0, ext) - shape = Part.Face(wires) - norm = shape.normalAt(0,0) - thk = float(obj.WindowParts[(i*5)+3]) - if thk: - exv = fcvec.scaleTo(norm,thk) - shape = shape.extrude(exv) - if obj.WindowParts[(i*5)+4]: - zof = float(obj.WindowParts[(i*5)+4]) - if zof: - zov = fcvec.scaleTo(norm,zof) - shape.translate(zov) - shapes.append(shape) - obj.Shape = Part.makeCompound(shapes) - if not fcgeo.isNull(pl): - obj.Placement = pl + if hasattr(obj,"WindowParts"): + if obj.WindowParts and (len(obj.WindowParts)%5 == 0): + shapes = [] + for i in range(len(obj.WindowParts)/5): + wires = [] + wstr = obj.WindowParts[(i*5)+2].split(',') + for s in wstr: + j = int(s[4:]) + if obj.Base.Shape.Wires: + if len(obj.Base.Shape.Wires) >= j: + wires.append(obj.Base.Shape.Wires[j]) + if wires: + max_length = 0 + for w in wires: + if w.BoundBox.DiagonalLength > max_length: + max_length = w.BoundBox.DiagonalLength + ext = w + wires.remove(ext) + shape = Part.Face(ext) + norm = shape.normalAt(0,0) + thk = float(obj.WindowParts[(i*5)+3]) + if thk: + exv = DraftVecUtils.scaleTo(norm,thk) + shape = shape.extrude(exv) + for w in wires: + f = Part.Face(w) + f = f.extrude(exv) + shape = shape.cut(f) + if obj.WindowParts[(i*5)+4]: + zof = float(obj.WindowParts[(i*5)+4]) + if zof: + zov = DraftVecUtils.scaleTo(norm,zof) + shape.translate(zov) + print shape + shapes.append(shape) + if shapes: + obj.Shape = Part.makeCompound(shapes) + if not DraftGeomUtils.isNull(pl): + obj.Placement = pl class _ViewProviderWindow(ArchComponent.ViewProviderComponent): "A View Provider for the Window object" @@ -146,7 +179,8 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent): def __init__(self,vobj): ArchComponent.ViewProviderComponent.__init__(self,vobj) - def getIcon(self): + def getIcon(self): + import Arch_rc return ":/icons/Arch_Window_Tree.svg" def setEdit(self,vobj,mode): diff --git a/src/Mod/Arch/Arch_rc.py b/src/Mod/Arch/Arch_rc.py index f56440b2c8..6e7f3870ae 100644 --- a/src/Mod/Arch/Arch_rc.py +++ b/src/Mod/Arch/Arch_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Tue Jan 24 10:12:37 2012 -# by: The Resource Compiler for PyQt (Qt v4.7.4) +# Created: Sun May 13 20:45:11 2012 +# by: The Resource Compiler for PyQt (Qt v4.8.1) # # WARNING! All changes made in this file will be lost! @@ -1757,6 +1757,351 @@ qt_resource_data = "\ \x00\x00\x00\x0c\x00\x4f\x00\x75\x00\x74\x00\x69\x00\x6c\x00\x73\ \x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\x54\x6f\x6f\x6c\x73\x07\ \x00\x00\x00\x04\x61\x72\x63\x68\x01\ +\x00\x00\x15\x62\ +\x3c\ +\xb8\x64\x18\xca\xef\x9c\x95\xcd\x21\x1c\xbf\x60\xa1\xbd\xdd\x42\ +\x00\x00\x01\x50\x00\x04\x9c\x2c\x00\x00\x02\xa5\x00\x05\xa0\xa5\ +\x00\x00\x0b\x01\x00\x05\xd8\x2c\x00\x00\x0e\x87\x00\x39\xdf\x33\ +\x00\x00\x11\x22\x00\x4b\x87\xd4\x00\x00\x13\x66\x00\x4d\x36\x62\ +\x00\x00\x04\x25\x00\x5b\x66\x33\x00\x00\x13\xc8\x00\x62\x9b\xa8\ +\x00\x00\x0b\x2d\x00\xfb\x72\xf3\x00\x00\x10\xb0\x01\xf7\xa8\x83\ +\x00\x00\x12\x43\x02\x5f\xc9\x59\x00\x00\x0d\xb7\x02\x90\x40\x65\ +\x00\x00\x05\x00\x02\xb8\xae\x74\x00\x00\x05\x56\x02\xcd\x05\xa3\ +\x00\x00\x04\x55\x02\xdd\x14\x14\x00\x00\x05\xa0\x02\xe5\xaa\xe4\ +\x00\x00\x00\x8b\x03\x1d\xe8\xe3\x00\x00\x0f\xb7\x03\xd4\x22\x74\ +\x00\x00\x00\xc8\x04\xdb\x21\x3e\x00\x00\x0a\x56\x05\x18\xda\xa3\ +\x00\x00\x03\x77\x05\xe0\x4b\x67\x00\x00\x0f\x89\x06\x32\xe3\xe3\ +\x00\x00\x13\x8e\x07\x60\x23\xf3\x00\x00\x00\x00\x09\x13\xce\x39\ +\x00\x00\x0e\xb5\x09\xba\xe6\x35\x00\x00\x0d\x75\x09\xe3\x98\xe4\ +\x00\x00\x01\x0e\x09\xed\x98\x55\x00\x00\x08\x68\x0a\x7f\xee\xa3\ +\x00\x00\x12\xf2\x0b\x51\x30\xa8\x00\x00\x06\xb6\x0b\x65\xda\xb3\ +\x00\x00\x10\x40\x0b\x8d\x97\x93\x00\x00\x11\x85\x0b\xb9\xe8\x93\ +\x00\x00\x07\x17\x0b\xc4\xb1\x23\x00\x00\x02\xcf\x0b\xe2\xc4\x04\ +\x00\x00\x07\xb7\x0c\x02\xac\xd7\x00\x00\x01\xb6\x0c\x25\x3e\x53\ +\x00\x00\x09\x41\x0c\x4e\x9b\x23\x00\x00\x08\xc5\x0d\x1e\xda\xa4\ +\x00\x00\x00\x37\x0d\x3b\x3b\x49\x00\x00\x0c\x2d\x0e\x32\x23\x85\ +\x00\x00\x13\x29\x0e\x8c\xd7\x43\x00\x00\x0b\x78\x0e\xec\x0b\x9e\ +\x00\x00\x01\xee\x69\x00\x00\x13\xf8\x03\x00\x00\x00\x14\x00\x6b\ +\x00\x6f\x00\x6d\x00\x70\x00\x6f\x00\x6e\x00\x65\x00\x6e\x00\x74\ +\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0a\x43\x6f\x6d\x70\ +\x6f\x6e\x65\x6e\x74\x73\x07\x00\x00\x00\x04\x41\x72\x63\x68\x01\ +\x03\x00\x00\x00\x22\x00\x53\x00\x6b\x01\x42\x00\x61\x00\x64\x00\ +\x6e\x00\x69\x00\x6b\x00\x69\x00\x20\x00\x6f\x00\x62\x00\x69\x00\ +\x65\x00\x6b\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x19\x43\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x73\x20\x6f\x66\x20\x74\ +\x68\x69\x73\x20\x6f\x62\x6a\x65\x63\x74\x07\x00\x00\x00\x04\x41\ +\x72\x63\x68\x01\x03\x00\x00\x00\x18\x00\x52\x00\x65\x00\x6d\x00\ +\x6f\x00\x76\x00\x65\x00\x20\x00\x63\x00\x68\x00\x69\x00\x6c\x00\ +\x64\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c\x52\x65\x6d\x6f\x76\ +\x65\x20\x63\x68\x69\x6c\x64\x07\x00\x00\x00\x04\x41\x72\x63\x68\ +\x01\x03\x00\x00\x00\x1c\x00\x44\x00\x6f\x00\x64\x00\x61\x00\x6a\ +\x00\x20\x00\x73\x00\x6b\x01\x42\x00\x61\x00\x64\x00\x6e\x00\x69\ +\x00\x6b\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\x41\x64\x64\x20\ +\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x07\x00\x00\x00\x08\x41\x72\ +\x63\x68\x5f\x41\x64\x64\x01\x03\x00\x00\x00\x5a\x00\x44\x00\x6f\ +\x00\x64\x00\x61\x00\x6a\x00\x65\x00\x20\x00\x77\x00\x79\x00\x62\ +\x00\x72\x00\x61\x00\x6e\x00\x65\x00\x20\x00\x73\x00\x6b\x01\x42\ +\x00\x61\x00\x64\x00\x6e\x00\x69\x00\x6b\x00\x69\x00\x20\x00\x64\ +\x00\x6f\x00\x20\x00\x61\x00\x6b\x00\x74\x00\x79\x00\x77\x00\x6e\ +\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\ +\x00\x6b\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x31\ +\x41\x64\x64\x73\x20\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\x65\ +\x64\x20\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x73\x20\x74\x6f\x20\ +\x74\x68\x65\x20\x61\x63\x74\x69\x76\x65\x20\x6f\x62\x6a\x65\x63\ +\x74\x07\x00\x00\x00\x08\x41\x72\x63\x68\x5f\x41\x64\x64\x01\x03\ +\x00\x00\x00\x0e\x00\x42\x00\x75\x00\x64\x00\x79\x00\x6e\x00\x65\ +\x00\x6b\x08\x00\x00\x00\x00\x06\x00\x00\x00\x08\x42\x75\x69\x6c\ +\x64\x69\x6e\x67\x07\x00\x00\x00\x0d\x41\x72\x63\x68\x5f\x42\x75\ +\x69\x6c\x64\x69\x6e\x67\x01\x03\x00\x00\x00\x60\x00\x54\x00\x77\ +\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\x6f\x00\x62\x00\x69\ +\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x42\x00\x75\x00\x64\x00\x79\ +\x00\x6e\x00\x65\x00\x6b\x00\x20\x00\x77\x00\x72\x00\x61\x00\x7a\ +\x00\x20\x00\x7a\x00\x20\x00\x77\x00\x79\x00\x62\x00\x72\x00\x61\ +\x00\x6e\x00\x79\x00\x6d\x00\x69\x00\x20\x00\x6f\x00\x62\x00\x69\ +\x00\x65\x00\x6b\x00\x74\x00\x61\x00\x6d\x00\x69\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x35\x43\x72\x65\x61\x74\x65\x73\x20\x61\x20\ +\x62\x75\x69\x6c\x64\x69\x6e\x67\x20\x6f\x62\x6a\x65\x63\x74\x20\ +\x69\x6e\x63\x6c\x75\x64\x69\x6e\x67\x20\x73\x65\x6c\x65\x63\x74\ +\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x2e\x07\x00\x00\x00\x0d\ +\x41\x72\x63\x68\x5f\x42\x75\x69\x6c\x64\x69\x6e\x67\x01\x03\x00\ +\x00\x00\x08\x00\x43\x00\x65\x00\x6c\x00\x6c\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x04\x43\x65\x6c\x6c\x07\x00\x00\x00\x09\x41\x72\ +\x63\x68\x5f\x43\x65\x6c\x6c\x01\x03\x00\x00\x00\x5a\x00\x54\x00\ +\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\x6f\x00\x62\x00\ +\x69\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x43\x00\x65\x00\x6c\x00\ +\x6c\x00\x20\x00\x77\x00\x72\x00\x61\x00\x7a\x00\x20\x00\x7a\x00\ +\x20\x00\x77\x00\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\x79\x00\ +\x6d\x00\x69\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\ +\x74\x00\x61\x00\x6d\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x30\x43\x72\x65\x61\x74\x65\x73\x20\x61\x20\x63\x65\x6c\x6c\x20\ +\x6f\x62\x6a\x65\x63\x74\x20\x69\x6e\x63\x6c\x75\x64\x69\x6e\x67\ +\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\ +\x73\x07\x00\x00\x00\x09\x41\x72\x63\x68\x5f\x43\x65\x6c\x6c\x01\ +\x03\x00\x00\x00\x5e\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\ +\x79\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\x20\x00\x50\x00\x69\x01\x19\x00\x74\x00\x72\x00\x6f\x00\x20\x00\ +\x77\x00\x72\x00\x61\x00\x7a\x00\x20\x00\x7a\x00\x20\x00\x77\x00\ +\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\x79\x00\x6d\x00\x69\x00\ +\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x61\x00\ +\x6d\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x31\x43\x72\x65\ +\x61\x74\x65\x73\x20\x61\x20\x66\x6c\x6f\x6f\x72\x20\x6f\x62\x6a\ +\x65\x63\x74\x20\x69\x6e\x63\x6c\x75\x64\x69\x6e\x67\x20\x73\x65\ +\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\ +\x00\x00\x0a\x41\x72\x63\x68\x5f\x46\x6c\x6f\x6f\x72\x01\x03\x00\ +\x00\x00\x0c\x00\x50\x00\x69\x01\x19\x00\x74\x00\x72\x00\x6f\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x05\x46\x6c\x6f\x6f\x72\x07\x00\ +\x00\x00\x0a\x41\x72\x63\x68\x5f\x46\x6c\x6f\x6f\x72\x01\x03\x00\ +\x00\x00\x5a\x00\x54\x00\x75\x00\x72\x00\x6e\x00\x73\x00\x20\x00\ +\x73\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\x65\x00\x64\x00\ +\x20\x00\x6d\x00\x65\x00\x73\x00\x68\x00\x65\x00\x73\x00\x20\x00\ +\x69\x00\x6e\x00\x74\x00\x6f\x00\x20\x00\x50\x00\x61\x00\x72\x00\ +\x74\x00\x20\x00\x53\x00\x68\x00\x61\x00\x70\x00\x65\x00\x20\x00\ +\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\x73\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x2d\x54\x75\x72\x6e\x73\x20\x73\x65\x6c\ +\x65\x63\x74\x65\x64\x20\x6d\x65\x73\x68\x65\x73\x20\x69\x6e\x74\ +\x6f\x20\x50\x61\x72\x74\x20\x53\x68\x61\x70\x65\x20\x6f\x62\x6a\ +\x65\x63\x74\x73\x07\x00\x00\x00\x0f\x41\x72\x63\x68\x5f\x4d\x65\ +\x73\x68\x54\x6f\x50\x61\x72\x74\x01\x03\x00\x00\x00\x24\x00\x53\ +\x00\x69\x00\x61\x00\x74\x00\x6b\x00\x61\x00\x20\x00\x64\x00\x6f\ +\x00\x20\x00\x4b\x00\x73\x00\x7a\x00\x74\x00\x61\x01\x42\x00\x74\ +\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\x4d\x65\x73\x68\ +\x20\x74\x6f\x20\x53\x68\x61\x70\x65\x07\x00\x00\x00\x10\x41\x72\ +\x63\x68\x5f\x4d\x65\x73\x68\x54\x6f\x53\x68\x61\x70\x65\x01\x03\ +\x00\x00\x00\x1a\x00\x55\x00\x73\x00\x75\x01\x44\x00\x20\x00\x73\ +\x00\x6b\x01\x42\x00\x61\x00\x64\x00\x6e\x00\x69\x00\x6b\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x10\x52\x65\x6d\x6f\x76\x65\x20\x63\ +\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x07\x00\x00\x00\x0b\x41\x72\x63\ +\x68\x5f\x52\x65\x6d\x6f\x76\x65\x01\x03\x00\x00\x00\xa4\x00\x52\ +\x00\x65\x00\x6d\x00\x6f\x00\x76\x00\x65\x00\x20\x00\x74\x00\x68\ +\x00\x65\x00\x20\x00\x73\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\ +\x00\x65\x00\x64\x00\x20\x00\x63\x00\x6f\x00\x6d\x00\x70\x00\x6f\ +\x00\x6e\x00\x65\x00\x6e\x00\x74\x00\x73\x00\x20\x00\x66\x00\x72\ +\x00\x6f\x00\x6d\x00\x20\x00\x74\x00\x68\x00\x65\x00\x69\x00\x72\ +\x00\x20\x00\x70\x00\x61\x00\x72\x00\x65\x00\x6e\x00\x74\x00\x73\ +\x00\x2c\x00\x20\x00\x6f\x00\x72\x00\x20\x00\x63\x00\x72\x00\x65\ +\x00\x61\x00\x74\x00\x65\x00\x20\x00\x61\x00\x20\x00\x68\x00\x6f\ +\x00\x6c\x00\x65\x00\x20\x00\x69\x00\x6e\x00\x20\x00\x61\x00\x20\ +\x00\x63\x00\x6f\x00\x6d\x00\x70\x00\x6f\x00\x6e\x00\x65\x00\x6e\ +\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\x52\x52\x65\x6d\x6f\ +\x76\x65\x20\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\ +\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x73\x20\x66\x72\x6f\x6d\x20\ +\x74\x68\x65\x69\x72\x20\x70\x61\x72\x65\x6e\x74\x73\x2c\x20\x6f\ +\x72\x20\x63\x72\x65\x61\x74\x65\x20\x61\x20\x68\x6f\x6c\x65\x20\ +\x69\x6e\x20\x61\x20\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x07\x00\ +\x00\x00\x0b\x41\x72\x63\x68\x5f\x52\x65\x6d\x6f\x76\x65\x01\x03\ +\x00\x00\x00\x26\x00\x55\x00\x73\x00\x75\x01\x44\x00\x20\x00\x4b\ +\x00\x73\x00\x7a\x00\x74\x00\x61\x01\x42\x00\x74\x00\x20\x00\x7a\ +\x00\x20\x00\x41\x00\x72\x00\x63\x00\x68\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x16\x52\x65\x6d\x6f\x76\x65\x20\x53\x68\x61\x70\x65\ +\x20\x66\x72\x6f\x6d\x20\x41\x72\x63\x68\x07\x00\x00\x00\x10\x41\ +\x72\x63\x68\x5f\x52\x65\x6d\x6f\x76\x65\x53\x68\x61\x70\x65\x01\ +\x03\x00\x00\x00\x52\x00\x52\x00\x65\x00\x6d\x00\x6f\x00\x76\x00\ +\x65\x00\x73\x00\x20\x00\x63\x00\x75\x00\x62\x00\x69\x00\x63\x00\ +\x20\x00\x73\x00\x68\x00\x61\x00\x70\x00\x65\x00\x73\x00\x20\x00\ +\x66\x00\x72\x00\x6f\x00\x6d\x00\x20\x00\x41\x00\x72\x00\x63\x00\ +\x68\x00\x20\x00\x63\x00\x6f\x00\x6d\x00\x70\x00\x6f\x00\x6e\x00\ +\x65\x00\x6e\x00\x74\x00\x73\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x29\x52\x65\x6d\x6f\x76\x65\x73\x20\x63\x75\x62\x69\x63\x20\x73\ +\x68\x61\x70\x65\x73\x20\x66\x72\x6f\x6d\x20\x41\x72\x63\x68\x20\ +\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\x74\x73\x07\x00\x00\x00\x10\x41\ +\x72\x63\x68\x5f\x52\x65\x6d\x6f\x76\x65\x53\x68\x61\x70\x65\x01\ +\x03\x00\x00\x00\x60\x00\x44\x00\x6f\x00\x64\x00\x61\x00\x6a\x00\ +\x65\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\x20\x00\x50\x01\x42\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\x00\ +\x79\x00\x7a\x00\x6e\x00\x61\x00\x20\x00\x50\x00\x72\x00\x7a\x00\ +\x65\x00\x6b\x00\x72\x00\x6f\x00\x6a\x00\x75\x00\x20\x00\x64\x00\ +\x6f\x00\x20\x00\x64\x00\x6f\x00\x6b\x00\x75\x00\x6d\x00\x65\x00\ +\x6e\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2b\x41\ +\x64\x64\x73\x20\x61\x20\x73\x65\x63\x74\x69\x6f\x6e\x20\x70\x6c\ +\x61\x6e\x65\x20\x6f\x62\x6a\x65\x63\x74\x20\x74\x6f\x20\x74\x68\ +\x65\x20\x64\x6f\x63\x75\x6d\x65\x6e\x74\x07\x00\x00\x00\x11\x41\ +\x72\x63\x68\x5f\x53\x65\x63\x74\x69\x6f\x6e\x50\x6c\x61\x6e\x65\ +\x01\x03\x00\x00\x00\x2a\x00\x50\x01\x42\x00\x61\x00\x73\x00\x7a\ +\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\x6e\x00\x61\x00\x20\x00\x70\ +\x00\x72\x00\x7a\x00\x65\x00\x6b\x00\x72\x00\x6f\x00\x6a\x00\x75\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\x53\x65\x63\x74\x69\x6f\ +\x6e\x20\x50\x6c\x61\x6e\x65\x07\x00\x00\x00\x11\x41\x72\x63\x68\ +\x5f\x53\x65\x63\x74\x69\x6f\x6e\x50\x6c\x61\x6e\x65\x01\x03\x00\ +\x00\x00\x34\x00\x53\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\ +\x20\x00\x6e\x00\x6f\x00\x6e\x00\x2d\x00\x6d\x00\x61\x00\x6e\x00\ +\x69\x00\x66\x00\x6f\x00\x6c\x00\x64\x00\x20\x00\x6d\x00\x65\x00\ +\x73\x00\x68\x00\x65\x00\x73\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x1a\x53\x65\x6c\x65\x63\x74\x20\x6e\x6f\x6e\x2d\x6d\x61\x6e\x69\ +\x66\x6f\x6c\x64\x20\x6d\x65\x73\x68\x65\x73\x07\x00\x00\x00\x19\ +\x41\x72\x63\x68\x5f\x53\x65\x6c\x65\x63\x74\x4e\x6f\x6e\x53\x6f\ +\x6c\x69\x64\x4d\x65\x73\x68\x65\x73\x01\x03\x00\x00\x00\x9a\x00\ +\x53\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\x73\x00\x20\x00\ +\x61\x00\x6c\x00\x6c\x00\x20\x00\x6e\x00\x6f\x00\x6e\x00\x2d\x00\ +\x6d\x00\x61\x00\x6e\x00\x69\x00\x66\x00\x6f\x00\x6c\x00\x64\x00\ +\x20\x00\x6d\x00\x65\x00\x73\x00\x68\x00\x65\x00\x73\x00\x20\x00\ +\x66\x00\x72\x00\x6f\x00\x6d\x00\x20\x00\x74\x00\x68\x00\x65\x00\ +\x20\x00\x64\x00\x6f\x00\x63\x00\x75\x00\x6d\x00\x65\x00\x6e\x00\ +\x74\x00\x20\x00\x6f\x00\x72\x00\x20\x00\x66\x00\x72\x00\x6f\x00\ +\x6d\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x73\x00\x65\x00\ +\x6c\x00\x65\x00\x63\x00\x74\x00\x65\x00\x64\x00\x20\x00\x67\x00\ +\x72\x00\x6f\x00\x75\x00\x70\x00\x73\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x4d\x53\x65\x6c\x65\x63\x74\x73\x20\x61\x6c\x6c\x20\x6e\ +\x6f\x6e\x2d\x6d\x61\x6e\x69\x66\x6f\x6c\x64\x20\x6d\x65\x73\x68\ +\x65\x73\x20\x66\x72\x6f\x6d\x20\x74\x68\x65\x20\x64\x6f\x63\x75\ +\x6d\x65\x6e\x74\x20\x6f\x72\x20\x66\x72\x6f\x6d\x20\x74\x68\x65\ +\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x67\x72\x6f\x75\x70\x73\ +\x07\x00\x00\x00\x19\x41\x72\x63\x68\x5f\x53\x65\x6c\x65\x63\x74\ +\x4e\x6f\x6e\x53\x6f\x6c\x69\x64\x4d\x65\x73\x68\x65\x73\x01\x03\ +\x00\x00\x00\x5c\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\ +\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\ +\x00\x54\x00\x65\x00\x72\x00\x65\x00\x6e\x00\x20\x00\x77\x00\x72\ +\x00\x61\x00\x7a\x00\x20\x00\x7a\x00\x20\x00\x77\x00\x79\x00\x62\ +\x00\x72\x00\x61\x00\x6e\x00\x79\x00\x6d\x00\x69\x00\x20\x00\x6f\ +\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x61\x00\x6d\x00\x69\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x31\x43\x72\x65\x61\x74\x65\ +\x73\x20\x61\x20\x73\x69\x74\x65\x20\x6f\x62\x6a\x65\x63\x74\x20\ +\x69\x6e\x63\x6c\x75\x64\x69\x6e\x67\x20\x73\x65\x6c\x65\x63\x74\ +\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x2e\x07\x00\x00\x00\x09\ +\x41\x72\x63\x68\x5f\x53\x69\x74\x65\x01\x03\x00\x00\x00\x0a\x00\ +\x54\x00\x65\x00\x72\x00\x65\x00\x6e\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x04\x53\x69\x74\x65\x07\x00\x00\x00\x09\x41\x72\x63\x68\ +\x5f\x53\x69\x74\x65\x01\x03\x00\x00\x00\x1e\x00\x52\x00\x6f\x00\ +\x7a\x00\x64\x00\x7a\x00\x69\x00\x65\x00\x6c\x00\x20\x00\x73\x00\ +\x69\x00\x61\x00\x74\x00\x6b\x01\x19\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x0a\x53\x70\x6c\x69\x74\x20\x4d\x65\x73\x68\x07\x00\x00\ +\x00\x0e\x41\x72\x63\x68\x5f\x53\x70\x6c\x69\x74\x4d\x65\x73\x68\ +\x01\x03\x00\x00\x00\x60\x00\x52\x00\x6f\x00\x7a\x00\x64\x00\x7a\ +\x00\x69\x00\x65\x00\x6c\x00\x61\x00\x20\x00\x77\x00\x79\x00\x62\ +\x00\x72\x00\x61\x00\x6e\x00\x65\x00\x20\x00\x73\x00\x69\x00\x61\ +\x00\x74\x00\x6b\x00\x69\x00\x20\x00\x6e\x00\x61\x00\x20\x00\x6e\ +\x00\x69\x00\x65\x00\x7a\x00\x61\x00\x6c\x00\x65\x01\x7c\x00\x6e\ +\x00\x65\x00\x20\x00\x73\x00\x6b\x01\x42\x00\x61\x00\x64\x00\x6e\ +\x00\x69\x00\x6b\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x32\ +\x53\x70\x6c\x69\x74\x73\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\ +\x6d\x65\x73\x68\x65\x73\x20\x69\x6e\x74\x6f\x20\x69\x6e\x64\x65\ +\x70\x65\x6e\x64\x65\x6e\x74\x20\x63\x6f\x6d\x70\x6f\x6e\x65\x6e\ +\x74\x73\x07\x00\x00\x00\x0e\x41\x72\x63\x68\x5f\x53\x70\x6c\x69\ +\x74\x4d\x65\x73\x68\x01\x03\x00\x00\x00\xc6\x00\x55\x00\x74\x00\ +\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\x6f\x00\x62\x00\x69\x00\ +\x65\x00\x6b\x00\x74\x00\x20\x00\x4b\x00\x6f\x00\x6e\x00\x73\x00\ +\x74\x00\x72\x00\x75\x00\x6b\x00\x63\x00\x6a\x00\x61\x00\x20\x00\ +\x6f\x00\x64\x00\x20\x00\x70\x00\x6f\x00\x63\x00\x7a\x01\x05\x00\ +\x74\x00\x6b\x00\x75\x00\x20\x00\x6c\x00\x75\x00\x62\x00\x20\x00\ +\x7a\x00\x20\x00\x77\x00\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\ +\x79\x00\x63\x00\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\xf3\x00\x77\x00\x20\x00\x28\x00\x73\x00\x7a\x00\ +\x6b\x00\x69\x00\x63\x00\x2c\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\ +\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x2c\x00\x20\x00\x66\x00\ +\x61\x00\x73\x00\x65\x00\x74\x00\x6b\x00\x61\x00\x20\x00\x6c\x00\ +\x75\x00\x62\x00\x20\x00\x73\x00\x6f\x00\x6c\x00\x69\x00\x64\x00\ +\x29\x08\x00\x00\x00\x00\x06\x00\x00\x00\x5f\x43\x72\x65\x61\x74\ +\x65\x73\x20\x61\x20\x73\x74\x72\x75\x63\x74\x75\x72\x65\x20\x6f\ +\x62\x6a\x65\x63\x74\x20\x66\x72\x6f\x6d\x20\x73\x63\x72\x61\x74\ +\x63\x68\x20\x6f\x72\x20\x66\x72\x6f\x6d\x20\x61\x20\x73\x65\x6c\ +\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x20\x28\x73\x6b\ +\x65\x74\x63\x68\x2c\x20\x77\x69\x72\x65\x2c\x20\x66\x61\x63\x65\ +\x20\x6f\x72\x20\x73\x6f\x6c\x69\x64\x29\x07\x00\x00\x00\x0e\x41\ +\x72\x63\x68\x5f\x53\x74\x72\x75\x63\x74\x75\x72\x65\x01\x03\x00\ +\x00\x00\x16\x00\x4b\x00\x6f\x00\x6e\x00\x73\x00\x74\x00\x72\x00\ +\x75\x00\x6b\x00\x63\x00\x6a\x00\x61\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x09\x53\x74\x72\x75\x63\x74\x75\x72\x65\x07\x00\x00\x00\ +\x0e\x41\x72\x63\x68\x5f\x53\x74\x72\x75\x63\x74\x75\x72\x65\x01\ +\x03\x00\x00\x00\x60\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\ +\x79\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\x20\x01\x5a\x00\x63\x00\x69\x00\x61\x00\x6e\x00\x61\x00\x20\x00\ +\x6f\x00\x64\x00\x20\x00\x70\x00\x6f\x00\x63\x00\x7a\x01\x05\x00\ +\x74\x00\x6b\x00\x75\x00\x20\x00\x6c\x00\x75\x00\x62\x00\x20\x00\ +\x7a\x00\x20\x00\x77\x00\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\ +\x79\x00\x63\x00\x68\x08\x00\x00\x00\x00\x06\x00\x00\x00\x52\x43\ +\x72\x65\x61\x74\x65\x73\x20\x61\x20\x77\x61\x6c\x6c\x20\x6f\x62\ +\x6a\x65\x63\x74\x20\x66\x72\x6f\x6d\x20\x73\x63\x72\x61\x74\x63\ +\x68\x20\x6f\x72\x20\x66\x72\x6f\x6d\x20\x61\x20\x73\x65\x6c\x65\ +\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x20\x28\x77\x69\x72\ +\x65\x2c\x20\x66\x61\x63\x65\x20\x6f\x72\x20\x73\x6f\x6c\x69\x64\ +\x29\x07\x00\x00\x00\x09\x41\x72\x63\x68\x5f\x57\x61\x6c\x6c\x01\ +\x03\x00\x00\x00\x0c\x01\x5a\x00\x63\x00\x69\x00\x61\x00\x6e\x00\ +\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04\x57\x61\x6c\x6c\x07\ +\x00\x00\x00\x09\x41\x72\x63\x68\x5f\x57\x61\x6c\x6c\x01\x03\x00\ +\x00\x00\x5a\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x20\x00\ +\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x4f\x00\ +\x6b\x00\x6e\x00\x6f\x00\x20\x00\x6f\x00\x64\x00\x20\x00\x70\x00\ +\x6f\x00\x63\x00\x7a\x01\x05\x00\x74\x00\x6b\x00\x75\x00\x20\x00\ +\x6c\x00\x75\x00\x62\x00\x20\x00\x7a\x00\x20\x00\x77\x00\x79\x00\ +\x62\x00\x72\x00\x61\x00\x6e\x00\x79\x00\x63\x00\x68\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x5a\x43\x72\x65\x61\x74\x65\x73\x20\x61\ +\x20\x77\x69\x6e\x64\x6f\x77\x20\x6f\x62\x6a\x65\x63\x74\x20\x66\ +\x72\x6f\x6d\x20\x73\x63\x72\x61\x74\x63\x68\x20\x6f\x72\x20\x66\ +\x72\x6f\x6d\x20\x61\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x6f\ +\x62\x6a\x65\x63\x74\x20\x28\x77\x69\x72\x65\x2c\x20\x72\x65\x63\ +\x74\x61\x6e\x67\x6c\x65\x20\x6f\x72\x20\x73\x6b\x65\x74\x63\x68\ +\x29\x07\x00\x00\x00\x0b\x41\x72\x63\x68\x5f\x57\x69\x6e\x64\x6f\ +\x77\x01\x03\x00\x00\x00\x08\x00\x4f\x00\x6b\x00\x6e\x00\x6f\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x06\x57\x69\x6e\x64\x6f\x77\x07\ +\x00\x00\x00\x0b\x41\x72\x63\x68\x5f\x57\x69\x6e\x64\x6f\x77\x01\ +\x03\x00\x00\x00\x3c\x00\x4b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\ +\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\ +\x79\x00\x20\x00\x64\x00\x6c\x00\x61\x00\x20\x00\x6b\x00\x6f\x00\ +\x6e\x00\x73\x00\x74\x00\x72\x00\x75\x00\x6b\x00\x63\x00\x6a\x00\ +\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1c\x44\x65\x66\x61\x75\ +\x6c\x74\x20\x63\x6f\x6c\x6f\x72\x20\x66\x6f\x72\x20\x73\x74\x72\ +\x75\x63\x74\x75\x72\x65\x73\x07\x00\x00\x00\x1c\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x41\x72\x63\x68\x01\x03\x00\x00\x00\x28\x00\x44\ +\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\x20\ +\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x01\x5b\x00\x63\ +\x00\x69\x00\x61\x00\x6e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17\ +\x44\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6c\x6f\x72\x20\x66\x6f\ +\x72\x20\x77\x61\x6c\x6c\x73\x07\x00\x00\x00\x1c\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x41\x72\x63\x68\x01\x03\x00\x00\x00\x2c\x00\x55\ +\x00\x73\x00\x74\x00\x61\x00\x77\x00\x69\x00\x65\x00\x6e\x00\x69\ +\x00\x61\x00\x20\x00\x6f\x00\x67\x00\xf3\x00\x6c\x00\x6e\x00\x65\ +\x00\x20\x00\x41\x00\x72\x00\x63\x00\x68\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x15\x47\x65\x6e\x65\x72\x61\x6c\x20\x41\x72\x63\x68\ +\x20\x53\x65\x74\x74\x69\x6e\x67\x73\x07\x00\x00\x00\x1c\x47\x75\ +\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\ +\x74\x74\x69\x6e\x67\x73\x41\x72\x63\x68\x01\x03\x00\x00\x00\x22\ +\x00\x55\x00\x73\x00\x74\x00\x61\x00\x77\x00\x69\x00\x65\x00\x6e\ +\x00\x69\x00\x61\x00\x20\x00\x6f\x00\x67\x00\xf3\x00\x6c\x00\x6e\ +\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\x47\x65\x6e\x65\ +\x72\x61\x6c\x20\x73\x65\x74\x74\x69\x6e\x67\x73\x07\x00\x00\x00\ +\x1c\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x41\x72\x63\x68\x01\x03\x00\ +\x00\x00\x5a\x00\x4b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\ +\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\ +\x20\x00\x64\x00\x6c\x00\x61\x00\x20\x00\x6e\x00\x6f\x00\x77\x00\ +\x65\x00\x67\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x75\x00\x20\x00\x4b\x00\x6f\x00\x6e\x00\x73\x00\ +\x74\x00\x72\x00\x75\x00\x6b\x00\x63\x00\x6a\x00\x61\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x33\x54\x68\x69\x73\x20\x69\x73\x20\x74\ +\x68\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6c\x6f\x72\ +\x20\x66\x6f\x72\x20\x6e\x65\x77\x20\x53\x74\x72\x75\x63\x74\x75\ +\x72\x65\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\x00\x00\x1c\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x41\x72\x63\x68\x01\x03\x00\x00\x00\ +\x50\x00\x4b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\x64\x00\ +\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\ +\x64\x00\x6c\x00\x61\x00\x20\x00\x6e\x00\x6f\x00\x77\x00\x65\x00\ +\x67\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\ +\x74\x00\x75\x00\x20\x01\x5a\x00\x63\x00\x69\x00\x61\x00\x6e\x00\ +\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2e\x54\x68\x69\x73\x20\ +\x69\x73\x20\x74\x68\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x63\ +\x6f\x6c\x6f\x72\x20\x66\x6f\x72\x20\x6e\x65\x77\x20\x57\x61\x6c\ +\x6c\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\x00\x00\x1c\x47\x75\ +\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\ +\x74\x74\x69\x6e\x67\x73\x41\x72\x63\x68\x01\x03\x00\x00\x00\x14\ +\x00\x41\x00\x72\x00\x63\x00\x68\x00\x20\x00\x74\x00\x6f\x00\x6f\ +\x00\x6c\x00\x73\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0a\x41\x72\ +\x63\x68\x20\x74\x6f\x6f\x6c\x73\x07\x00\x00\x00\x04\x61\x72\x63\ +\x68\x01\x03\x00\x00\x00\x18\x00\x41\x00\x72\x00\x63\x00\x68\x00\ +\x69\x00\x74\x00\x65\x00\x63\x00\x74\x00\x75\x00\x72\x00\x65\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x0c\x41\x72\x63\x68\x69\x74\x65\ +\x63\x74\x75\x72\x65\x07\x00\x00\x00\x04\x61\x72\x63\x68\x01\x03\ +\x00\x00\x00\x0a\x00\x44\x00\x72\x00\x61\x00\x66\x00\x74\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x05\x44\x72\x61\x66\x74\x07\x00\x00\ +\x00\x04\x61\x72\x63\x68\x01\x03\x00\x00\x00\x16\x00\x44\x00\x72\ +\x00\x61\x00\x66\x00\x74\x00\x20\x00\x74\x00\x6f\x00\x6f\x00\x6c\ +\x00\x73\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0b\x44\x72\x61\x66\ +\x74\x20\x74\x6f\x6f\x6c\x73\x07\x00\x00\x00\x04\x61\x72\x63\x68\ +\x01\x03\x00\x00\x00\x12\x00\x4e\x00\x61\x00\x72\x00\x7a\x01\x19\ +\x00\x64\x00\x7a\x00\x69\x00\x61\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x05\x54\x6f\x6f\x6c\x73\x07\x00\x00\x00\x04\x61\x72\x63\x68\ +\x01\ \x00\x00\x17\x20\ \x3c\ \xb8\x64\x18\xca\xef\x9c\x95\xcd\x21\x1c\xbf\x60\xa1\xbd\xdd\x42\ @@ -5697,83 +6042,85 @@ qt_resource_data = "\ \x00\x00\x00\x12\x00\x57\x00\x65\x00\x72\x00\x6b\x00\x7a\x00\x65\ \x00\x75\x00\x67\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\ \x54\x6f\x6f\x6c\x73\x07\x00\x00\x00\x04\x61\x72\x63\x68\x01\ -\x00\x00\x04\xaa\ +\x00\x00\x04\xd0\ \x00\ -\x00\x1c\xf4\x78\x9c\xed\x59\x6d\x6f\xa3\x38\x10\xfe\xde\x5f\x61\ -\xf1\xf9\xae\x24\xd9\x24\xbb\xad\x08\xab\x7d\xb9\xbe\x48\xbb\xba\ -\x54\xe9\x6e\x3f\xae\x08\x4c\x82\x6f\xc1\xe6\x8c\xb9\x24\xfb\xeb\ -\xcf\x36\x26\x60\x20\xb4\x69\xb2\xad\x54\x55\x6a\x54\xdb\x63\x66\ -\xc6\x8f\x67\x1e\x0f\xd8\x79\xbf\x8e\x23\xf4\x1f\xb0\x14\x53\x32\ -\xb1\xfa\xa7\x3d\x0b\x01\xf1\x69\x80\xc9\x72\x62\x7d\xbb\xbd\xf8\ -\xf3\x9d\xf5\xde\x3d\x71\x32\x5c\x4e\x1a\x8a\x49\xee\x09\x72\xfc\ -\xc8\x4b\x53\xf7\x32\xc3\xe7\xe7\x9f\xb1\x17\xd1\xa5\xf8\x1f\x2d\ -\x67\xc0\xb9\x78\x38\xfd\xc0\xfc\xd0\xb1\xf3\x39\x62\xf2\x0a\x07\ -\x4b\xe0\x48\xf5\x27\xd6\xcd\x9d\xea\x5a\x88\x78\x31\x4c\xac\x2e\ -\x1d\xd2\x14\x72\x12\x46\x13\x60\x7c\xa3\x1f\x58\x02\x8d\x81\xb3\ -\x8d\x12\x22\x87\x81\xcf\x55\x0b\x39\x6b\xb7\xe7\xd8\x6b\xdd\xd9\ -\xc8\xce\x46\x77\x84\x07\x3c\x74\x47\x6f\x47\x8e\x9d\x37\xf3\xe1\ -\x10\xf0\x32\xe4\xee\x78\x70\xe6\xd8\xba\xad\x74\xda\x85\x52\xc7\ -\x2e\x8c\xb7\x79\xb2\xc2\x24\xa0\xab\x5b\xcc\x23\xd0\xce\xa4\x9c\ -\x09\xdf\xdd\x4b\x20\xc0\xbc\x08\xa5\x7a\x2d\x8e\xad\x05\x4d\x95\ -\x91\xb7\xa1\x59\x89\xcd\xf7\x8f\x74\xfd\x45\x0d\x69\x8d\x35\x93\ -\x69\xe2\xf9\x42\x91\xa5\x17\x40\xb2\x78\x0e\xcc\x1d\x3b\xb6\x6e\ -\xe5\xee\x57\x2d\x34\x54\xc4\x1e\x5b\x62\x52\xd3\x70\xd6\xa9\x01\ -\x73\x88\x4b\x24\xab\x7b\x79\xc9\x68\x96\x08\x9f\x8b\xdd\x5c\x16\ -\xfd\x7c\x7a\xc3\x38\x2f\xc1\x6a\xc1\x4b\xee\x39\x9a\xb5\x80\xd6\ -\xf4\xa9\x13\x3a\x6d\x4c\x44\x2d\xc7\xbe\x17\xe5\xa3\x3f\x06\xa5\ -\xdd\x72\x41\x2d\x8a\xae\x1a\x8a\x42\xca\xf0\x2f\x4a\x78\x8b\xaa\ -\xba\xb2\x26\x44\x5f\xbc\x39\x44\x85\xa6\x48\x76\x8c\xc7\x5b\x30\ -\x82\x35\x37\x26\x6c\x71\xfa\x0c\x0b\x2f\x8b\x84\x6a\x1a\x51\x86\ -\x16\xe2\xb7\xf2\xa2\xa8\x8e\x54\x3b\x5c\xf9\x60\xee\x5b\xc5\x79\ -\xdb\xf4\xbe\xb1\x18\x19\x70\xc0\x1a\x38\xcc\xd4\x70\xe7\x32\xc4\ -\x5c\x10\x53\xb9\xe0\x8d\xda\x6a\x40\x84\x9a\x7b\xc3\xcf\xcf\xaf\ -\xb6\xfa\x1c\x5b\x0d\xde\xb7\x80\x66\x3e\xe0\x5f\x70\x85\x89\xd8\ -\xa9\x94\x07\x22\xdd\x26\x56\xaf\x0e\x9d\x98\x61\x8c\x14\x6c\x30\ -\xec\x19\x64\xb0\x95\x6a\x22\x18\xf4\x0c\x4e\x28\xdd\xaa\x2b\xdc\ -\x81\x74\x0e\xdc\x1e\x48\x9b\x61\xa3\x68\x71\xca\x60\xf1\x49\xee\ -\xf5\xc7\x8c\x73\x01\x63\x91\x64\x52\x96\x08\x99\x8a\x83\x79\x2e\ -\xeb\x8c\x28\x4a\xa3\x5b\x9c\xb4\x07\xd5\x6d\x88\x53\x24\xfe\x78\ -\x08\x28\x68\x04\x18\x81\x15\xba\x13\x41\x86\xe8\xfc\x1f\x41\x8a\ -\x0f\x8f\xb5\x86\x13\x4a\x67\xcd\x05\x35\x56\xc3\x9f\x41\xe0\x0e\ -\x46\x23\x49\xc2\x41\x4d\xb4\x64\x00\xc4\xed\x9f\x89\xad\xc9\x9b\ -\xa6\x78\x1e\x65\xe0\xf6\xdf\x0a\xa9\x6a\x99\xdb\xd6\x30\xf5\x30\ -\xaf\x25\xcc\x7f\x11\x79\xdc\xec\x8c\x30\x5f\x23\x22\x61\x52\xbb\ -\x25\x8c\x3d\x16\x24\x69\x6e\xea\xf1\xf0\x7e\x6b\x5f\x69\x60\xeb\ -\x73\xf6\x58\xd9\xef\xd8\x39\x13\x6e\x69\xd2\x10\x1f\x4a\x9a\x07\ -\x51\xe6\xd1\x08\x53\x08\x32\x9f\x67\x0c\x9e\x8f\x35\xef\xa1\xff\ -\x57\xde\x7c\x4a\xde\xbc\xef\x2c\x3e\x8c\x39\x67\x45\xb4\x3d\x2d\ -\x7d\xf6\x47\xbd\x0e\xfa\x1c\x9f\x75\xd1\xe7\xbb\xf1\x33\xd1\xe7\ -\x16\xab\x57\x0e\xdd\x5d\x78\x8e\x0f\x2b\x3c\x47\xc7\x2b\x3c\xd5\ -\xbb\xcf\x33\x92\xe8\xf0\x95\x44\x77\x63\xfd\xd4\x24\xfa\xa6\x73\ -\x33\xf6\xa1\xae\xd1\x59\x07\x73\xbd\x19\x74\x31\xd7\xf0\xb9\x98\ -\xeb\x4e\xe5\xc2\xcb\xa5\x2d\x53\x68\xe8\xaa\xcc\x7b\xc4\x57\x82\ -\xf2\xf0\x7d\xd8\x77\x82\xeb\x8b\x4f\x08\xc7\x09\x65\xfc\xd8\x1f\ -\x07\x8e\xf7\x69\x60\xf8\x70\x86\x2e\xd3\x2c\x04\xff\x67\x15\x9f\ -\x6d\x8e\x49\xc1\xbc\x0a\x54\x3b\x5a\x5d\x55\x0a\x5e\x88\x02\x25\ -\x2f\x54\x94\x3a\x08\xfe\x50\x15\x8b\x20\x2e\x60\xa4\xf8\xea\x22\ -\xa1\x4d\x3c\x96\x82\xa4\x76\xf1\xba\x37\x07\x94\xa5\x80\x38\x45\ -\xf3\x0c\x47\x41\x3e\x49\x17\x31\x68\xc1\x68\x8c\x7e\x12\xba\x22\ -\xea\x39\xbe\x49\x20\x3d\x7d\x7c\x69\xb3\xfb\xdc\x91\x2e\x6c\xfd\ -\x2c\x5d\x3c\xa0\x8a\xca\x11\xa8\x59\x9b\x0b\xfc\x5c\x51\x7e\x80\ -\x20\x10\xd9\xfc\x9d\x64\x21\x96\x74\xbd\xf0\xa7\x7a\x1d\x2f\x90\ -\x2d\x0e\x4f\xa1\xd1\xef\x48\xa1\xc7\x27\xd0\xf5\x8e\x04\x12\xf1\ -\xf8\x77\x02\x64\x16\x82\xc8\x97\x9c\x96\xcc\xec\x09\x54\xa5\x54\ -\x24\x0d\xa1\x1c\x85\x1e\x09\x22\x31\x3e\xdf\x98\x29\x78\x68\x58\ -\xef\xce\xa0\x6f\xa9\xe9\xe8\xe3\x6d\xec\x1d\xe3\x15\x9b\x2f\x30\ -\xcc\xf7\x3f\x14\x8d\x7a\xb6\x38\x7e\xcc\x0f\xa9\x0f\x29\x63\xcb\ -\x0a\xf6\xbb\xd6\x61\xd4\xaf\xcd\xa3\x70\x8f\xaa\xd5\x2c\x58\x75\ -\xad\x3a\x68\xd4\xaa\x45\x99\x3a\x6c\x94\xa9\x46\x85\x5a\x77\xc5\ -\xa8\x4b\x4b\x90\x2a\x48\x56\x60\xd4\xbc\x51\xbc\x57\xeb\x8b\x8f\ -\x89\x35\xb6\x50\x7e\x83\x31\xb1\xfa\x7d\xcb\x96\x33\x13\xbc\x8e\ -\xbd\x64\x91\x11\x5f\x02\xe5\xfe\x3b\x55\xfd\x0b\x71\x48\x7d\xc5\ -\x31\xcc\x68\xc6\x7c\xc1\xec\xb5\x59\xf2\x12\x2b\x4b\x39\x8d\x73\ -\x8b\xa9\xf2\xa4\x3a\x92\x7b\x59\xb9\xe8\xaa\x14\xc3\xe5\xe5\x96\ -\xdc\x8f\x35\x07\x12\xa4\xee\xcd\x34\x4b\xc3\x42\x5e\x0c\x9e\xe4\ -\x70\x79\x81\x58\xb6\xd0\x62\xe7\x97\x5f\xe9\x69\x28\x91\x53\xa3\ -\x0a\x81\xba\xe1\x6e\x4f\x6a\xa5\x79\xab\x37\x4d\x97\x77\xb9\x24\ -\xb5\x1d\xcf\x2d\xcd\xc3\xed\x08\x95\xd2\xc3\x9d\x31\x07\xd4\x45\ -\x23\x83\x54\x6d\x76\xaa\xc2\xc2\xa7\x84\x80\xda\x6c\xd9\x77\xec\ -\x0c\xbb\x27\xff\x03\x16\x13\x63\x21\ +\x00\x1e\xaa\x78\x9c\xed\x59\x6d\x6f\xdb\x36\x10\xfe\x9e\x5f\x41\ +\xe8\xd3\x06\x6c\x95\xed\xd8\x6e\x13\xc8\x2a\xd6\x74\x79\x01\x5a\ +\x2c\x81\xd3\xe6\xe3\x20\x4b\x67\x8b\xab\x24\x7a\x24\x95\xd8\xfd\ +\xf5\x3d\x92\x92\x65\xbd\x58\x89\x63\x27\x01\x82\x00\x31\x22\xf2\ +\x4e\xc7\xe3\xc3\xe3\xa3\x3b\xd2\xf9\xb8\x88\x23\x72\x0b\x5c\x50\ +\x96\x8c\xac\xee\xbb\x8e\x45\x20\xf1\x59\x40\x93\xd9\xc8\xfa\x76\ +\x7d\xfa\xe7\x07\xeb\xa3\x7b\xe0\xa4\xb4\x50\xea\xa3\x92\x7b\x40\ +\x1c\x3f\xf2\x84\x70\xcf\x52\x7a\x7c\xfc\x99\x7a\x11\x9b\xe1\xff\ +\x68\x36\x06\x29\xf1\x65\xf1\x17\xf7\x43\xc7\x36\x3a\xa8\x7c\x47\ +\x83\x19\x48\xa2\xdb\x23\xeb\xea\x46\x37\x2d\x92\x78\x31\x8c\xac\ +\x36\x1b\x6a\x28\xe2\xcc\x39\x9b\x03\x97\xcb\xec\x85\x19\xb0\x18\ +\x24\x5f\x6a\x21\x71\x38\xf8\x52\x3f\x11\x67\xe1\x76\x1c\x7b\x91\ +\x35\x96\xaa\xb1\xcc\x1a\xe8\x81\x0c\xdd\xc1\xfb\x81\x63\x9b\x47\ +\xd3\x1d\x02\x9d\x85\xd2\x1d\xf6\x8e\x1c\x3b\x7b\xd6\x36\xed\xdc\ +\xa8\x63\xe7\x83\x37\x79\x72\x47\x93\x80\xdd\x5d\x53\x19\x41\xe6\ +\x8c\x90\x1c\x7d\x77\xcf\x20\x01\xee\x45\x44\x64\x73\x71\xec\x4c\ +\x50\x37\x19\x79\x4b\x96\x16\xd8\x7c\xff\xc4\x16\x5f\x74\x57\x66\ +\xb1\x32\xa4\x98\x7b\x3e\x1a\xb2\xb2\x09\x24\x69\x3c\x01\xee\x0e\ +\x1d\x3b\x7b\x32\xee\xaf\x8f\x50\x33\x11\x7b\x7c\x46\x93\x8a\x85\ +\xa3\x56\x0b\x54\x42\x5c\x20\xb9\xbe\x96\x67\x9c\xa5\x73\xf4\x39\ +\x5f\xcd\x59\xde\x36\xea\xb5\xc1\x65\x01\x56\x03\x5e\x6a\xcd\xc9\ +\xb8\x01\xb4\xba\x4f\xad\xd0\x65\x83\x61\xd4\x4a\xea\x7b\x91\xe9\ +\xfd\xb7\x57\x8c\x5b\x4c\xa8\xc1\xd0\x79\xcd\x50\xc8\x38\xfd\xc9\ +\x12\xd9\x60\xaa\x6a\xac\x0e\xd1\x17\x6f\x02\x51\x6e\x29\x52\x8d\ +\xd2\xeb\x0d\x18\xc1\x42\x96\x14\x56\x38\x7d\x86\xa9\x97\x46\x68\ +\x9a\x45\x8c\x93\x29\xfe\xee\xbc\x28\xaa\x22\xd5\x0c\x97\xe9\x34\ +\xbe\xad\x39\x6f\x97\xbd\xaf\x4d\x46\x05\x1c\xf0\x1a\x0e\x63\xdd\ +\xdd\x3a\x0d\xd4\x05\x54\x95\xc8\x1b\x95\xd9\x00\x86\x9a\x7b\x25\ +\x8f\x8f\xcf\x57\xf6\x1c\x5b\x77\xde\x37\x81\xfa\x7e\xa0\x3f\xe1\ +\x9c\x26\xb8\x52\x42\x06\xb8\xdd\x46\x56\xa7\x0a\x1d\x6a\x94\x7a\ +\x72\x36\xe8\x77\x4a\x64\xb0\x92\x66\x44\xd0\xeb\x94\x38\xa1\x70\ +\xab\x6a\x70\x03\xd2\x06\xb8\x2d\x90\x2e\x87\x8d\xa6\xc5\x4b\x0e\ +\xd3\x13\xb5\xd6\x9f\x52\x29\x11\xc6\x7c\x93\x29\xd9\x1c\x65\x3a\ +\x0e\x26\x46\xd6\x1a\x51\x8c\x45\xd7\x74\xde\x1c\x54\xd7\x21\x15\ +\x04\xff\x64\x08\x24\xa8\x05\x58\x02\x77\xe4\x06\x83\x8c\xb0\xc9\ +\x7f\x48\x8a\x0f\x8f\xb5\x9a\x13\xda\x66\xc5\x05\xdd\x57\xc1\x9f\ +\x43\xe0\xf6\x06\x03\x45\xc2\x41\x45\x34\xe3\x00\x89\xdb\x3d\xc2\ +\xa5\x31\x8f\x65\xf1\x24\x4a\xc1\xed\xbe\x47\xa9\x7e\x2a\x2f\x5b\ +\x6d\xa8\x87\x79\xad\x60\xfe\x3b\x51\x9f\x9b\x8d\x11\xe6\x67\x88\ +\x28\x98\xf4\x6a\xe1\x60\x8f\x05\x49\x0d\x77\xe9\xc9\xf0\xfe\xd1\ +\xbe\xb2\xc0\xce\xbe\xb3\xfb\xda\xfd\x8e\x6d\x98\x70\x45\x93\x25\ +\xf1\xae\xa4\xb9\x13\x65\xee\x8d\x30\x51\x90\xfa\x32\xe5\xf0\x72\ +\xac\x79\x0f\xfd\xbf\xf1\xe6\x73\xf2\xe6\x7d\xdf\xe2\xdd\x98\x73\ +\x9c\x47\xdb\xf3\xd2\x67\x77\xd0\x69\xa1\xcf\xe1\x51\x1b\x7d\x7e\ +\x18\xbe\x10\x7d\xae\xb0\x7a\xe3\xd0\xcd\x89\xe7\x70\xb7\xc4\x73\ +\xb0\xbf\xc4\x53\xd7\x3e\x2f\x48\xa2\xfd\x37\x12\xdd\x8c\xf5\x73\ +\x93\xe8\x61\xeb\x62\x6c\x43\x5d\x83\xa3\x16\xe6\x3a\xec\xb5\x31\ +\x57\xff\xa5\x98\xeb\x46\xef\x85\xd7\x4b\x5b\x65\x61\xc9\xd6\x9a\ +\xde\x23\x4e\x09\x8a\x8f\xef\xc3\xce\x09\x2e\x4e\x4f\x08\x8d\xe7\ +\x8c\xcb\x7d\x1f\x0e\xec\xef\x68\x60\xf0\x70\x86\x2e\xb6\x59\x08\ +\xfe\x8f\x75\x7c\x56\x7b\x4c\x09\x26\xc5\x71\x4a\x33\x56\x6d\x39\ +\xca\xc5\x14\xd3\x13\x93\xa6\x68\x63\x10\xfc\xa1\xf3\x15\x84\xf2\ +\x9f\x39\x24\xe3\x10\xb0\xb6\x33\x98\x82\x62\x75\x6c\x4d\x80\xa4\ +\x42\xe9\x61\x3d\xc3\x90\xe7\x67\x44\xb2\x4c\x85\xc4\x8c\xeb\x77\ +\x89\x5c\xce\xb7\x48\xa1\xb7\xf8\xd4\x7c\x13\x55\xe7\xa6\xc4\xbb\ +\xf5\x28\x7e\xc0\x22\x78\xfc\x80\x5b\x6c\x67\x9c\xfc\xc5\xd4\x5f\ +\x39\xf0\x2a\xb7\xf4\xee\x71\x7e\xf8\x14\x71\xbe\x4b\x36\x7e\xc2\ +\xc1\x93\x20\x88\x26\x17\xa1\x93\x14\xf0\xfc\xd0\x1c\x2a\x9a\xf4\ +\x5b\x47\xed\x53\x04\xad\x26\x38\xcc\x8e\x70\x93\x24\x98\x77\x08\ +\x32\x59\xee\xba\x43\xb6\x08\x58\x5f\xcf\x1c\x63\x56\xbb\x21\xde\ +\x02\xb6\x31\x60\xfb\x4f\x12\xb0\xed\x99\xcf\xe6\x88\xb9\x30\x7c\ +\x3a\x4d\x79\x42\x75\x81\xf8\x9b\xef\x25\x24\xf6\x7e\x80\xa6\xe7\ +\x98\x05\x10\x91\x10\xbc\xdb\xe5\xef\xcf\x12\x43\x86\xdf\x31\x86\ +\x4e\x73\x8f\x5e\x65\x18\x6d\x9f\xca\x94\xaa\x90\x3c\x69\x28\x1f\ +\x7f\x3f\xa4\xf8\x28\xea\x8e\xef\x99\x8d\x52\xd5\x51\x4f\x60\xb6\ +\xa8\x35\xca\x65\x46\x56\x61\xf4\x6a\x15\x46\x5e\x5c\xf4\x6b\xc5\ +\x45\xa9\xae\xa8\xba\x52\xaa\x26\x0a\x90\xd6\x90\x5c\x83\x31\xdb\ +\x97\xf9\x69\x48\x76\x5d\x35\xb2\x86\x16\x31\xf7\x4e\x23\xab\xdb\ +\xb5\x6c\xa5\x39\xa7\x8b\xd8\x9b\x4f\xd3\xc4\x57\x40\xb9\xff\x5f\ +\xea\xf6\x29\x67\xf1\x57\x1a\xc3\x98\xa5\xdc\xc7\x18\xac\x68\xa9\ +\xab\xc7\x54\x48\x16\x9b\x11\x85\xf6\x64\xbd\xc7\x78\xb9\x76\x3d\ +\xb9\x56\xc2\x14\x57\x92\x6a\x3d\x16\x12\x92\x40\xb8\x57\x97\xa9\ +\x08\x73\x79\xde\x79\x60\xe0\xf2\x02\x9c\x36\x5a\xb1\xcd\x95\xa5\ +\x78\x17\x2a\xe4\x74\xaf\x46\xa0\x3a\x70\xbb\x27\x95\x82\xaa\xd1\ +\x9b\xba\xcb\x9b\x5c\x52\xd6\xf6\xe7\x56\xc6\x73\xcd\x08\x15\xd2\ +\xdd\x9d\x29\x77\xe8\xeb\x61\x0e\x42\x2f\xb6\xd0\x61\xe1\xb3\x24\ +\x01\xbd\xd8\xaa\xed\xd8\x29\x75\x0f\x7e\x01\x09\x6b\xe1\xfc\ \x00\x00\x07\x4c\ \x00\ \x00\x29\xd1\x78\x9c\xed\x59\x5b\x8f\xe2\x46\x16\x7e\xef\x5f\xe1\ @@ -6444,7 +6791,7 @@ qt_resource_data = "\ \x60\x24\x14\x71\x18\x20\xc8\x29\x21\x64\x0a\xba\x54\x4c\x69\x8a\ \x07\xa3\xfe\x50\x76\x18\x1a\x6f\x00\x69\x8d\xda\xda\x66\xb6\xba\ \xbe\xb8\xb2\x35\xc7\xf5\xc5\x7f\x01\x9a\x79\xce\xaf\ -\x00\x00\x12\x5a\ +\x00\x00\x12\x5c\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ \x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ @@ -6484,173 +6831,233 @@ qt_resource_data = "\ \x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x39\x38\ \x35\x22\x0a\x20\x20\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\ \x2e\x31\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\ -\x72\x39\x37\x36\x30\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\ -\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x41\x72\x63\x68\ -\x5f\x53\x69\x74\x65\x2e\x73\x76\x67\x22\x3e\x0a\x20\x20\x3c\x64\ -\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\ -\x73\x32\x39\x38\x37\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\ -\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ -\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x22\x3e\x0a\x20\x20\x20\x20\ -\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\ -\x6f\x72\x3a\x23\x66\x66\x62\x34\x30\x30\x3b\x73\x74\x6f\x70\x2d\ -\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\ -\x70\x33\x37\x39\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\ -\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\ -\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\ -\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\ -\x37\x39\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\ -\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\ -\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ -\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\ -\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\ -\x38\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\ -\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x62\x34\ -\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ -\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\ -\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x36\x2d\x35\x22\ -\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\ -\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x65\x61\ -\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ -\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\ -\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x38\x2d\x38\x22\ -\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\ -\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\ -\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x79\x32\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\ -\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x32\x3d\x22\x36\ -\x32\x2e\x36\x35\x32\x33\x37\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x79\x31\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x78\x31\x3d\x22\x31\x35\x2e\x31\x38\x34\ -\x39\x37\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\ -\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\ -\x61\x74\x72\x69\x78\x28\x31\x2e\x30\x32\x36\x35\x35\x36\x38\x2c\ -\x30\x2c\x30\x2c\x30\x2e\x39\x31\x34\x39\x30\x36\x32\x36\x2c\x2d\ -\x33\x2e\x32\x33\x36\x37\x30\x36\x2c\x2d\x31\x2e\x38\x30\x32\x37\ -\x30\x33\x32\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\ -\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\ -\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\ -\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ -\x64\x69\x65\x6e\x74\x33\x38\x38\x36\x22\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\ -\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\ -\x34\x2d\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ -\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\ -\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\ -\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\ -\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\ -\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\x31\x22\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\ -\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x62\x34\x30\x30\x3b\x73\x74\ -\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\ -\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ -\x73\x74\x6f\x70\x33\x37\x39\x36\x2d\x32\x22\x20\x2f\x3e\x0a\x20\ -\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\ -\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\x73\x74\ -\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\ -\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ -\x73\x74\x6f\x70\x33\x37\x39\x38\x2d\x32\x22\x20\x2f\x3e\x0a\x20\ +\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x33\x2e\ +\x31\x20\x72\x39\x38\x38\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\ +\x70\x6f\x64\x69\x3a\x64\x6f\x63\x6e\x61\x6d\x65\x3d\x22\x41\x72\ +\x63\x68\x5f\x53\x69\x74\x65\x5f\x54\x72\x65\x65\x2e\x73\x76\x67\ +\x22\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\ +\x69\x64\x3d\x22\x64\x65\x66\x73\x32\x39\x38\x37\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\ +\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\ +\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\ +\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x62\x34\x30\ +\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\ +\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\ +\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x36\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x38\x22\x20\x2f\x3e\x0a\x20\ \x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\ \x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\ \x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x79\x32\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\ -\x20\x20\x20\x20\x20\x20\x78\x32\x3d\x22\x36\x32\x2e\x36\x35\x32\ -\x33\x37\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x31\x3d\x22\x32\ -\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x78\x31\x3d\x22\x31\x35\x2e\x31\x38\x34\x39\x37\x31\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\ -\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\ -\x28\x31\x2e\x30\x32\x36\x35\x35\x36\x38\x2c\x30\x2c\x30\x2c\x30\ -\x2e\x39\x31\x34\x39\x30\x36\x32\x36\x2c\x2d\x33\x2e\x32\x33\x36\ -\x37\x30\x36\x2c\x2d\x31\x2e\x38\x30\x32\x37\x30\x33\x32\x29\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ -\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\ -\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\ -\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\ -\x33\x38\x38\x36\x2d\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\ -\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\ -\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\x31\ -\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ -\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\ -\x73\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\ -\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\ -\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x62\ -\x61\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\ -\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\ -\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\ -\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\ -\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\ +\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x33\x37\x39\x34\x2d\x38\x22\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x66\x66\x62\x34\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\ +\x33\x37\x39\x36\x2d\x35\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x66\x66\x65\x61\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\ +\x33\x37\x39\x38\x2d\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ +\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\ +\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x32\x3d\x22\ +\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x78\x32\x3d\x22\x36\x32\x2e\x36\x35\x32\x33\x37\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x79\x31\x3d\x22\x32\x33\x2e\x38\x34\ +\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x31\x3d\ +\x22\x31\x35\x2e\x31\x38\x34\x39\x37\x31\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\ +\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2e\x30\ +\x32\x36\x35\x35\x36\x38\x2c\x30\x2c\x30\x2c\x30\x2e\x39\x31\x34\ +\x39\x30\x36\x32\x36\x2c\x2d\x33\x2e\x32\x33\x36\x37\x30\x36\x2c\ +\x2d\x31\x2e\x38\x30\x32\x37\x30\x33\x32\x29\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\ +\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\ +\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x38\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\ +\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x33\x37\x39\x34\x2d\x38\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\ +\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\ +\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\ +\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x37\x39\ +\x34\x2d\x31\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\ +\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\ +\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\ +\x62\x34\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\ +\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x36\x2d\ +\x32\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\ +\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\ +\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\ +\x65\x61\x30\x30\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\ +\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x37\x39\x38\x2d\ +\x32\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\ +\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\ +\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x79\x32\x3d\x22\x32\x33\x2e\x38\x34\ +\x38\x36\x38\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x32\x3d\ +\x22\x36\x32\x2e\x36\x35\x32\x33\x37\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x79\x31\x3d\x22\x32\x33\x2e\x38\x34\x38\x36\x38\x36\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x31\x3d\x22\x31\x35\x2e\x31\ +\x38\x34\x39\x37\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\ +\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\ +\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2e\x30\x32\x36\x35\x35\x36\ +\x38\x2c\x30\x2c\x30\x2c\x30\x2e\x39\x31\x34\x39\x30\x36\x32\x36\ +\x2c\x2d\x33\x2e\x32\x33\x36\x37\x30\x36\x2c\x2d\x31\x2e\x38\x30\ +\x32\x37\x30\x33\x32\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\ +\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\ +\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\ +\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x38\x36\x2d\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\ +\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x33\x37\x39\x34\x2d\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\ +\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\x20\x20\x3c\ +\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\ +\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\ +\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\ +\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\ +\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\ +\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\ +\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\ +\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x37\x2e\x37\x37\x38\x31\ +\x37\x34\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x63\x78\x3d\x22\x32\x36\x2e\x34\x33\x31\x33\x36\x37\ \x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\ -\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\ -\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\ -\x6d\x3d\x22\x32\x2e\x37\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ -\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x2d\x31\x32\x2e\x35\ -\x34\x31\x38\x31\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ -\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x32\x33\x2e\x38\x34\x36\x36\ -\x39\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ -\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\ -\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x73\x68\ -\x6f\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\ -\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\ -\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\ -\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\ -\x69\x64\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\ -\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\ -\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\ -\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\ -\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\ -\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ -\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\ +\x63\x79\x3d\x22\x33\x30\x2e\x38\x30\x36\x36\x30\x38\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\ +\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x6c\x61\x79\x65\ +\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\x72\x69\ +\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\ +\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\x64\x2d\x62\x62\ +\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x77\ +\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\ +\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\x35\x22\x0a\x20\x20\ \x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\ -\x6f\x77\x2d\x79\x3d\x22\x31\x39\x22\x0a\x20\x20\x20\x20\x20\x69\ -\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\ -\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\ -\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\ -\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x39\x39\ -\x30\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\ -\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\ -\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\ -\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\ -\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\ -\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\ -\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\ -\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\ -\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x3e\x3c\x2f\x64\x63\ -\x3a\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\ -\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\ -\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\ -\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\ -\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\ -\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\ -\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\ -\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\ -\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x3c\ +\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\ +\x22\x32\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\ +\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\ +\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x39\x39\x30\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\ +\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\ +\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\ +\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\ +\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\ +\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\ +\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\ +\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\ +\x3a\x74\x69\x74\x6c\x65\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\ +\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\ +\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\ +\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\ +\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\x20\x20\ +\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\ +\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\ +\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x62\x66\x62\x62\x62\x62\x3b\ +\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\ +\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\ +\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\ +\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\ +\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\ +\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\ +\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\ +\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\x76\ +\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\ +\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\ +\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\ +\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\ +\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\ +\x20\x35\x2e\x32\x39\x30\x30\x39\x32\x2c\x34\x31\x2e\x35\x33\x32\ +\x31\x34\x36\x20\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\ +\x35\x35\x35\x35\x36\x39\x20\x32\x39\x2e\x36\x30\x35\x38\x30\x33\ +\x2c\x35\x37\x2e\x30\x37\x34\x30\x38\x31\x20\x35\x2e\x35\x32\x32\ +\x37\x37\x38\x33\x2c\x34\x36\x2e\x39\x33\x38\x30\x33\x37\x20\x7a\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\ +\x68\x33\x39\x30\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\ +\x2d\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\ +\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\ +\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x66\x66\ +\x66\x66\x66\x66\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\ +\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\ +\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\ +\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\ +\x68\x3a\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\ +\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\ +\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\ +\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\ +\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\ +\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\ +\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\ +\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\ +\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\ +\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\ +\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\ +\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x64\x3d\x22\x4d\x20\x35\x39\x2e\x35\x30\x35\x39\x38\x35\x2c\ +\x31\x32\x2e\x33\x36\x32\x38\x36\x32\x20\x35\x39\x2e\x30\x34\x30\ +\x36\x31\x32\x2c\x33\x34\x2e\x34\x33\x36\x39\x31\x35\x20\x32\x39\ +\x2e\x36\x30\x35\x38\x30\x33\x2c\x35\x36\x2e\x39\x36\x31\x34\x35\ +\x39\x20\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\x35\x35\ +\x35\x35\x36\x39\x20\x34\x30\x2e\x37\x37\x34\x37\x34\x33\x2c\x31\ +\x33\x2e\x39\x33\x39\x35\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x38\x36\x39\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\ +\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ \x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\ -\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\ -\x3b\x66\x69\x6c\x6c\x3a\x23\x62\x66\x62\x62\x62\x62\x3b\x66\x69\ -\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\ -\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\ +\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x23\x39\x32\x62\x64\x38\x65\x3b\ +\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\ \x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\ \x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x3b\x73\x74\x72\ \x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\ @@ -6659,87 +7066,27 @@ qt_resource_data = "\ \x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\ \x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\ \x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\ -\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\ -\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\ -\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\ -\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\ -\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\ -\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\ -\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\ -\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x20\x35\ -\x2e\x32\x39\x30\x30\x39\x32\x2c\x34\x31\x2e\x35\x33\x32\x31\x34\ -\x36\x20\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\x35\x35\ -\x35\x35\x36\x39\x20\x32\x39\x2e\x36\x30\x35\x38\x30\x33\x2c\x35\ -\x37\x2e\x30\x37\x34\x30\x38\x31\x20\x35\x2e\x35\x32\x32\x37\x37\ -\x38\x33\x2c\x34\x36\x2e\x39\x33\x38\x30\x33\x37\x20\x7a\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\ -\x39\x30\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ -\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\ -\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\ -\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\ -\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\ -\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x66\x66\x66\x66\ -\x66\x66\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ -\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\ -\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\ -\x30\x30\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\ -\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\ -\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\ -\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\ -\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\ -\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\ -\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\ -\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\ -\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\ -\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\ -\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\ -\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\ -\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\ -\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\ -\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\ -\x3d\x22\x4d\x20\x35\x39\x2e\x35\x30\x35\x39\x38\x35\x2c\x31\x32\ -\x2e\x33\x36\x32\x38\x36\x32\x20\x35\x39\x2e\x30\x34\x30\x36\x31\ -\x32\x2c\x33\x34\x2e\x34\x33\x36\x39\x31\x35\x20\x32\x39\x2e\x36\ -\x30\x35\x38\x30\x33\x2c\x35\x36\x2e\x39\x36\x31\x34\x35\x39\x20\ -\x32\x39\x2e\x34\x38\x39\x34\x36\x2c\x35\x31\x2e\x35\x35\x35\x35\ -\x36\x39\x20\x34\x30\x2e\x37\x37\x34\x37\x34\x33\x2c\x31\x33\x2e\ -\x39\x33\x39\x35\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ -\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x38\x36\x39\x22\x0a\x20\x20\ -\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\ -\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\x75\x72\ -\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\ -\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\ -\x22\x66\x69\x6c\x6c\x3a\x23\x35\x35\x39\x61\x35\x36\x3b\x66\x69\ -\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\ -\x6f\x6b\x65\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x73\x74\x72\x6f\ -\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x3b\x73\x74\x72\x6f\x6b\ -\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\ -\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\ -\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\ -\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ -\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\ -\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x22\ -\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x33\x36\x2e\ -\x35\x30\x32\x38\x38\x37\x2c\x36\x2e\x34\x34\x36\x38\x36\x38\x20\ -\x2d\x31\x31\x2e\x30\x38\x39\x35\x37\x32\x2c\x38\x2e\x35\x36\x35\ -\x35\x37\x33\x20\x2d\x38\x2e\x39\x39\x39\x33\x39\x2c\x31\x36\x2e\ -\x30\x32\x39\x31\x34\x33\x20\x30\x2e\x31\x37\x34\x31\x38\x31\x2c\ -\x30\x2e\x30\x37\x35\x31\x34\x20\x4c\x20\x35\x2e\x32\x30\x38\x32\ -\x33\x31\x36\x2c\x34\x31\x2e\x37\x33\x36\x30\x32\x37\x20\x32\x39\ -\x2e\x35\x33\x35\x36\x31\x37\x2c\x35\x31\x2e\x36\x35\x34\x30\x35\ -\x39\x20\x34\x30\x2e\x34\x35\x31\x30\x30\x36\x2c\x34\x30\x2e\x36\ -\x38\x34\x31\x31\x35\x20\x34\x30\x2e\x38\x35\x37\x34\x33\x31\x2c\ -\x34\x30\x2e\x32\x38\x33\x33\x38\x36\x20\x34\x30\x2e\x36\x38\x33\ -\x32\x35\x2c\x34\x30\x2e\x32\x30\x38\x32\x34\x39\x20\x34\x39\x2e\ -\x34\x32\x31\x33\x36\x37\x2c\x32\x33\x2e\x35\x37\x38\x30\x31\x34\ -\x20\x35\x39\x2e\x35\x38\x31\x39\x36\x39\x2c\x31\x32\x2e\x34\x33\ -\x32\x37\x35\x31\x20\x33\x36\x2e\x35\x30\x32\x38\x38\x37\x2c\x36\ -\x2e\x34\x34\x36\x38\x36\x38\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\ -\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x37\x36\x33\x22\x0a\ -\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ -\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\ -\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x67\ -\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x6d\x20\x33\ +\x36\x2e\x35\x30\x32\x38\x38\x37\x2c\x36\x2e\x34\x34\x36\x38\x36\ +\x38\x20\x2d\x31\x31\x2e\x30\x38\x39\x35\x37\x32\x2c\x38\x2e\x35\ +\x36\x35\x35\x37\x33\x20\x2d\x38\x2e\x39\x39\x39\x33\x39\x2c\x31\ +\x36\x2e\x30\x32\x39\x31\x34\x33\x20\x30\x2e\x31\x37\x34\x31\x38\ +\x31\x2c\x30\x2e\x30\x37\x35\x31\x34\x20\x4c\x20\x35\x2e\x32\x30\ +\x38\x32\x33\x31\x36\x2c\x34\x31\x2e\x37\x33\x36\x30\x32\x37\x20\ +\x32\x39\x2e\x35\x33\x35\x36\x31\x37\x2c\x35\x31\x2e\x36\x35\x34\ +\x30\x35\x39\x20\x34\x30\x2e\x34\x35\x31\x30\x30\x36\x2c\x34\x30\ +\x2e\x36\x38\x34\x31\x31\x35\x20\x34\x30\x2e\x38\x35\x37\x34\x33\ +\x31\x2c\x34\x30\x2e\x32\x38\x33\x33\x38\x36\x20\x34\x30\x2e\x36\ +\x38\x33\x32\x35\x2c\x34\x30\x2e\x32\x30\x38\x32\x34\x39\x20\x34\ +\x39\x2e\x34\x32\x31\x33\x36\x37\x2c\x32\x33\x2e\x35\x37\x38\x30\ +\x31\x34\x20\x35\x39\x2e\x35\x38\x31\x39\x36\x39\x2c\x31\x32\x2e\ +\x34\x33\x32\x37\x35\x31\x20\x33\x36\x2e\x35\x30\x32\x38\x38\x37\ +\x2c\x36\x2e\x34\x34\x36\x38\x36\x38\x20\x7a\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x33\x37\x36\x33\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\x63\x75\x72\x76\ +\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\x0a\x20\x20\x3c\ +\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ \x00\x00\x0e\x6b\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ @@ -8011,6 +8358,133 @@ qt_resource_data = "\ \x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x6f\x64\x65\x74\x79\x70\ \x65\x73\x3d\x22\x63\x63\x63\x63\x63\x22\x20\x2f\x3e\x0a\x20\x20\ \x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ +\x00\x00\x07\xc4\ +\x00\ +\x00\x37\x1e\x78\x9c\xed\x5b\x6d\x8f\x9b\x48\x12\xfe\x3e\xbf\x82\ +\x65\xbe\x24\x3a\x83\xfb\x9d\x6e\x32\x9e\xd5\xdd\x46\xbb\x5a\xe9\ +\x4e\x27\x5d\x12\xdd\xc7\x88\x81\xb6\xcd\x0e\x06\x0b\xf0\xd8\xce\ +\xaf\xdf\x6a\xcc\x9b\x6d\x3c\x2f\xd9\x91\x6e\x77\x38\x4b\xc9\x40\ +\x55\x75\x77\xd5\xd3\x55\xd5\xd5\xd0\xdc\xfc\xb8\x5b\x25\xd6\x83\ +\xce\x8b\x38\x4b\x67\x36\x76\x91\x6d\xe9\x34\xcc\xa2\x38\x5d\xcc\ +\xec\x2f\x9f\x7f\x76\xa4\x6d\x15\x65\x90\x46\x41\x92\xa5\x7a\x66\ +\xa7\x99\xfd\xe3\xed\xd5\xcd\x0f\x8e\x63\xfd\x94\xeb\xa0\xd4\x91\ +\xb5\x8d\xcb\xa5\xf5\x6b\x7a\x5f\x84\xc1\x5a\x5b\xef\x96\x65\xb9\ +\xf6\xa7\xd3\xed\x76\xeb\xc6\x35\xd1\xcd\xf2\xc5\xf4\xbd\xe5\x38\ +\xb7\x57\x57\x37\xc5\xc3\xe2\xca\xb2\x2c\x18\x37\x2d\xfc\x28\x9c\ +\xd9\x75\x83\xf5\x26\x4f\x2a\xc1\x28\x9c\xea\x44\xaf\x74\x5a\x16\ +\x53\xec\xe2\xa9\xdd\x89\x87\x9d\x78\x68\x46\x8f\x1f\x74\x98\xad\ +\x56\x59\x5a\x54\x2d\xd3\xe2\xba\x27\x9c\x47\xf3\x56\xda\x68\xb3\ +\xa5\x95\x10\x56\x4a\x4d\x11\x99\x12\xe2\x80\x84\x53\xec\xd3\x32\ +\xd8\x39\xc7\x4d\x41\xc7\xa1\xa6\x04\x21\x34\x05\x5e\x27\xf9\x3c\ +\x29\x7f\x97\x00\x14\x17\x95\xa9\xb8\xfd\xd1\x01\xfe\x35\xfc\x6b\ +\x1b\x34\x04\xb7\xc8\x36\x79\xa8\xe7\xd0\x52\xbb\xa9\x2e\xa7\x1f\ +\x3f\x7f\x6c\x99\x0e\x72\xa3\x32\xea\x75\xd3\xa0\x7f\x34\xee\xd1\ +\x94\xa4\xc1\x4a\x17\xeb\x20\xd4\xc5\xb4\xa1\x57\xed\xb7\x71\x54\ +\x2e\x67\xb6\x60\xeb\x5d\x75\xbf\xd4\xf1\x62\x59\xf6\x08\x71\x34\ +\xb3\xc1\x42\x22\xb1\xa8\xee\x7b\x0e\x84\x0f\x02\x75\x77\x7e\xcb\ +\x41\x2e\x93\x2e\x75\xb1\x95\x2b\x29\x0f\xad\x1a\xcd\xfd\x28\x0b\ +\x8d\x2a\x33\xfb\xef\x79\xb8\xfc\xfa\x8f\x4d\x9c\x18\xff\x73\x0d\ +\x86\xb7\x20\x78\x13\xe9\x79\x61\x1a\x1c\x06\x36\x77\x30\xb2\xac\ +\x78\xc0\x05\xf4\x74\x90\xff\x92\x07\x51\x0c\x3e\x73\x90\x3b\x48\ +\x1e\x73\xa8\x90\xb8\x6e\x03\xad\x8a\x32\x5b\x37\xb2\xb5\x41\x40\ +\xa1\x42\x79\x76\x47\xce\xe6\xf3\x42\x83\xe1\xa8\x47\x2b\xca\x7d\ +\xa2\x0f\xd2\x4e\x98\x25\x59\xee\x5f\xcf\xe7\x73\x8c\xd1\x87\x8a\ +\x94\x01\x9e\x71\xb9\xf7\xf1\x07\xdb\x9a\x5e\x18\x6d\xa0\x8b\x70\ +\xee\x21\x24\xcf\xba\x38\x57\x05\xdb\x43\x5a\x4b\xde\x8e\x76\x33\ +\x3d\x36\xbb\xa6\xb6\x33\xb2\x86\x19\x59\xeb\xd0\xc4\x4e\xd3\x53\ +\x3b\x11\xe5\xde\xb8\xcb\xb1\x28\x8d\xda\x11\xbb\x59\x5d\x7f\xdd\ +\x01\x2a\x96\x6f\x51\x02\xff\xe1\x41\x89\xfd\x41\x02\x43\x38\xc0\ +\x1f\x34\x28\xf3\xcd\x38\xd5\x23\xdd\xd4\x1a\x38\x59\x1e\x2f\x62\ +\xf0\xa2\x4a\x8e\x60\x97\x56\xbf\xe3\x36\x00\x46\xcf\x36\x22\x09\ +\xeb\x30\x79\xcc\xfa\x93\x86\x54\x10\xf2\xb4\x22\xc8\xe5\xc6\xa8\ +\x5a\x91\x53\x55\x8e\x2d\xc4\x95\x24\xff\x43\x40\xd5\x70\x9f\x76\ +\xf3\xd4\xcc\x7d\x2f\x00\x8e\x1a\x39\x04\x9c\x8e\x1c\x00\x8f\x8f\ +\x1c\x80\xde\x42\x30\x4a\x00\x3c\x32\xa0\xc3\xa8\x00\x60\x23\x5f\ +\x07\x3c\xc1\x46\x0e\x80\x1c\x79\x12\x94\x48\x8c\x1e\x00\x67\xe4\ +\x95\x80\xa4\x23\x0f\x02\x81\x47\x9e\x06\x01\x00\x47\x8e\x1c\x02\ +\x36\xf2\x2c\x00\x00\x8c\x3d\x11\x0a\x6f\xe4\xf5\x20\x00\xe0\x8c\ +\x7c\x2d\xf0\xd0\x33\x1e\x52\xbd\x71\x00\xc6\xbe\x16\x78\xec\x0d\ +\x16\xc5\xeb\xa0\x2c\x75\x9e\x36\xed\xea\xdb\xcf\x79\x90\x16\xf3\ +\x2c\x5f\xcd\xec\x55\x50\xe6\xf1\xee\x1d\x72\x05\x6c\x0b\xa9\x47\ +\xe4\xc4\x41\xae\xc4\x92\x28\xcc\xf9\x84\xb8\x8c\x7b\x92\x62\x36\ +\xc1\xae\x94\x8c\x71\xce\x26\x0e\x11\x40\x45\x02\x89\x09\x96\x2e\ +\x51\x4c\x31\xef\xfd\xf1\xe3\xda\xc3\x28\x9c\xd0\x4e\xe3\xea\x65\ +\x88\xbf\xcc\xf5\x7c\x66\x5f\x7f\x82\x31\xd7\x05\xfe\x8a\x9d\x81\ +\x12\x2c\xcc\x92\x04\xa6\x64\x66\x07\xc9\x36\xd8\x17\xdf\x35\x99\ +\x9c\x90\x37\x58\xdc\x9d\x4c\x66\x2b\x58\x94\x59\x78\x6f\x10\xa8\ +\x70\xd5\x85\x85\xfd\xe3\xe7\xe7\x43\x78\x3f\xe6\x0a\xc2\x03\x47\ +\x60\x74\xe2\x60\x17\x21\xc8\x0d\xb2\xf2\x04\x22\xb0\xf4\x24\x5c\ +\x51\x8c\x19\x67\x72\x42\x5d\xe6\x09\xa4\xa4\x07\x57\x9c\x32\x45\ +\x68\xe7\x07\xcd\xbb\xa5\x4e\x91\xfa\xed\x13\x39\xd5\xe0\x4b\x1a\ +\x97\xc5\xcc\xde\x14\x3a\xff\x64\x5e\x5a\xfd\x3b\xfd\x52\xe8\xa7\ +\xdd\xa2\x7d\x07\x93\x03\xb5\x91\x3e\x98\x6b\x28\x8c\x49\xda\xb3\ +\xb6\x53\x88\xf4\x68\xb5\x4a\xfd\x77\x2f\x30\x8f\x10\x00\xbc\x47\ +\xd9\x0d\xbe\x27\x9a\xc7\x49\xe2\xdf\x25\x41\x78\xff\xa1\x28\xf3\ +\xec\x5e\xfb\x69\x96\xea\xde\xdb\x9a\xda\xba\xef\xf3\xdd\xb7\xf8\ +\x9c\xfe\x05\xa9\xe8\xb9\xfe\xa7\x5c\x20\x51\x89\x27\xd2\x55\x42\ +\x11\x89\xd8\xc5\x44\xd4\xf3\x85\x0b\xa9\x68\x20\xfb\xbf\x56\x2a\ +\x7a\x8b\x25\xf6\x2b\x24\x23\x31\xaa\x64\x84\xfe\x34\xc9\xe8\x25\ +\x91\xc8\x31\xa5\x92\x54\xe0\x0b\x8a\x89\x52\x06\x7c\x0c\xc5\x02\ +\xa2\xe6\x8a\x41\xa1\xe0\xc1\xdc\x30\xe5\x7a\x82\x70\x61\xd8\x8a\ +\x33\x21\xd1\xa5\x9a\x40\x89\xe1\x40\xec\xc7\xea\x40\xb8\xbc\x4e\ +\x28\xca\x37\x58\xe3\xbe\x7e\x5e\x35\x15\x1e\xa5\x02\x44\x27\x18\ +\x8a\x41\xe9\x61\x75\xb9\xc2\xeb\x4d\xd6\xa5\x1a\xef\x45\xf3\xf9\ +\x1a\x45\x4e\x6f\xc0\x31\x64\x16\xd6\xcb\xa4\x7f\x9d\xdc\xc2\x00\ +\x7b\x26\xa5\x30\x1b\x0e\x41\x60\xb7\x21\x99\x82\x6d\x06\xe7\x90\ +\x5c\x84\x07\x57\x8c\x62\xaa\xc4\x84\x78\xae\x62\x92\x99\x3d\x08\ +\x75\x29\x12\x8c\x8b\x61\x67\xa4\x14\x3d\xe5\x8a\x03\x65\xd5\xab\ +\x24\x16\x4a\xfe\xbf\xc2\x77\xc8\x0c\xe1\x3d\x86\x38\xa4\x7f\x9a\ +\x28\x7c\x91\xef\x8a\x71\x3f\xfb\xe2\x54\xbe\xc1\xe0\x7d\x09\x00\ +\x0c\xbf\x41\x0f\xb8\x70\x7c\xf4\x52\x7c\x0f\x2e\x1c\x03\x07\x4d\ +\xfb\x18\x9e\xb1\xbb\xa3\x45\x3b\x3c\xb3\xa9\xe7\x4a\xe5\xf1\x6e\ +\x6d\xde\x03\x91\x41\x8e\x83\xb4\xa6\xba\x42\x74\x47\x80\x0a\xd5\ +\x35\xe2\x1e\xee\xb2\xc5\xde\x50\x91\x8b\x85\xe4\xaa\xdb\xba\x2e\ +\xea\xb1\x86\x93\xd8\xff\xd2\x76\xc5\xcf\x6d\x87\x15\xde\x3b\x36\ +\xde\x9c\x16\x66\x5e\xef\x85\x8b\x31\x5e\x10\x17\x31\xe9\x79\xea\ +\xc8\x78\x81\x5c\xa8\x2e\x31\xf6\x9e\x69\xfc\xa9\xd4\xd0\x4a\x43\ +\x18\x21\x1e\xc2\xea\x50\x72\x30\x8e\x3d\x45\x26\xd5\x2e\x47\x50\ +\x04\xa5\x06\x48\x10\x0f\x4a\x0c\xc2\x27\xdc\x15\x88\x29\xc4\xe5\ +\x84\x11\x17\x88\x98\xca\xf7\x35\xc0\x37\x53\x73\x54\xb9\xba\x6a\ +\xbd\xd1\x9c\x73\x8e\x1e\x62\xbd\xbd\x6a\x11\xba\x0b\x5a\xad\xd6\ +\xc1\x42\x57\x07\x82\x01\xd7\x79\xf5\xab\x19\x77\x59\x1e\xe9\xbc\ +\x61\x89\xea\x77\xc4\xaa\xcf\x0c\x1f\x8e\xf0\x5f\x9d\x44\x28\xf4\ +\xda\xf2\xd1\x30\xbf\x58\x06\x51\xb6\xed\x96\xa1\x96\xf9\x2d\xcb\ +\x00\x19\x0a\xd5\xbd\x02\x7f\x3c\x63\x87\x10\x7e\xb4\x2a\xc1\x30\ +\xf2\xce\x98\x46\x1f\xe6\xc2\xae\x40\x12\x7c\xc6\xdc\xe4\x39\xc0\ +\xef\x24\xc1\x5e\x83\x51\xd5\x9f\x46\xa8\x58\x66\xdb\x45\x6e\xc0\ +\x29\xf3\x8d\x3e\x6d\x19\x65\xe1\xc6\x7c\x1e\xe0\x6c\x0e\x13\x5c\ +\x1f\x4a\xef\x49\x98\xb6\xce\xdd\x5d\xb6\x1b\xee\xa0\x48\x83\xf5\ +\x23\x6c\xc3\x71\x60\x9d\x5c\x16\x8f\xf0\xd3\x2c\xd2\x17\xf8\x6d\ +\xf7\x8e\x8e\x16\xda\x59\xc5\xd1\x3a\x8b\xd3\xf2\x49\xe9\x27\x04\ +\xb3\xbb\xdf\x20\x18\x1f\x53\xac\x96\x78\x44\xb5\x6d\x9c\xc2\x34\ +\x3b\x4d\x81\x41\xe4\x99\x33\xd4\x12\x4d\x59\xe2\x71\x79\x41\xa2\ +\x57\x7f\x9c\xb2\xcc\xb4\xab\x0b\xbc\x55\xb0\x8b\x57\xf1\x37\x1d\ +\x99\xe6\x75\x9c\xac\x74\x19\x44\x41\x19\x74\x31\xd1\x50\x88\x71\ +\x9c\x3a\x59\xe5\xd1\xdc\xff\xcf\xc7\x9f\xdb\x02\x2b\x0c\xfd\xff\ +\x66\xf9\x7d\x57\x02\x19\x81\xe0\x2e\xdb\x80\xda\x6d\x19\x66\xbe\ +\x1e\x08\x7d\x13\xde\x41\x79\x1b\xaf\xc0\xd3\xcd\xa7\x19\x7f\xdb\ +\xad\x12\x88\xce\x96\x71\x24\x6c\x16\x8c\xae\xd3\x43\xb7\xb9\x3e\ +\x7c\x7a\x31\xf8\xb5\x4a\x14\xae\x62\xd3\x68\xfa\xa9\x84\xea\xeb\ +\x57\x33\x48\xef\xec\x7f\xdd\x69\x5c\x26\xfa\xb6\x1a\xf3\x70\xd9\ +\x58\x31\xad\xcd\x68\xea\xb3\x9e\x95\x37\xd3\x06\x86\xea\x6e\xd1\ +\xc1\x73\x14\x2c\x2d\xc2\x49\x70\xa7\x93\x99\xfd\x4f\xc3\xb4\xce\ +\xb8\x8b\x3c\xdb\xac\x57\xe0\x1a\x75\x73\xbb\xab\xde\x97\xed\xa2\ +\xd9\x2b\x22\xaf\x55\x20\x38\x62\x1f\xcc\x4d\xef\x93\x84\xba\xaa\ +\xbc\xa6\x1a\x9c\x47\xd4\xb7\x07\x87\xf2\x21\xf7\x40\xa8\x23\xc8\ +\x87\x0d\xdd\x64\x7f\x18\xdd\xbf\xdb\x94\x65\x9f\xf6\x1b\xf8\xb9\ +\x0f\x0a\xa5\x51\x43\x05\x08\x75\x9e\x80\x6b\x94\x3e\x6b\x68\xa7\ +\xa3\x3a\x51\x00\x79\x2a\xcf\x83\xfd\xa1\xaa\x6d\xd4\x06\x44\xfe\ +\x65\x11\x48\xcf\x54\x21\x4f\x4c\x18\x77\xb9\x14\x1e\x22\x16\xa4\ +\x64\x89\x14\x57\xb0\x4f\xa0\x2e\x26\x9c\x23\x6c\x31\x05\x9b\x43\ +\xe5\x61\x6f\xa2\x5c\x05\x49\x4d\x51\x8b\x40\x3e\xc7\xb0\xad\x24\ +\x13\x02\xe9\x9c\xc3\x6a\x44\xad\x6f\xa7\x5b\xc7\x25\x51\x68\xa0\ +\x02\x09\xb3\x14\x4c\x2c\xb3\xdc\x81\x84\xf6\x10\x94\x9b\x5c\xf7\ +\x0b\xf3\x2e\xf1\x03\xf2\xc6\x49\x20\x30\x43\xf3\x3b\xda\x3e\x0d\ +\x4e\x00\x78\xd8\xbb\xb3\xd5\x55\xf1\xf7\x7f\x99\x19\x19\x40\xda\ +\x2c\xe1\x04\x33\x4a\x27\x44\x98\xe7\x7f\xb0\xa4\x58\x94\x03\xcd\ +\x83\xd5\x7e\xc2\x61\xba\xcc\x4a\xfe\xdc\x09\x91\x6a\xf0\x59\xfc\ +\x1f\x9a\x90\x9b\xe9\xe2\xf6\xea\xc6\x24\x89\xdb\xab\xdf\x01\x64\ +\xd9\x31\x4e\ \x00\x00\x13\xbe\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ @@ -9013,118 +9487,118 @@ qt_resource_data = "\ \x36\x14\x14\xa2\xad\xa3\xa0\xac\xa6\x04\x91\x00\x07\x92\x33\x46\ \x6d\xa5\x0d\x85\xb6\x3c\x63\xeb\xf9\x5a\xeb\xd5\x95\xd6\xd4\x5b\ \xcd\x6f\xa6\xf6\x72\x72\x7e\xf3\x07\x32\x2c\xc5\xda\ -\x00\x00\x06\xd7\ +\x00\x00\x06\xd6\ \x00\ -\x00\x27\xd0\x78\x9c\xed\x59\xdd\x6f\xe3\xb8\x11\x7f\xcf\x5f\xa1\ -\x7a\x5f\xee\x50\x93\xe2\xa7\x48\x2a\xb6\xef\xa1\x8b\x03\x0e\x68\ -\x5f\xda\x2b\xfa\x58\xc8\x12\x6d\xeb\x22\x4b\x86\x24\xc7\xc9\xfe\ -\xf5\x1d\xca\x92\x2c\x7f\xc4\xc9\x6d\x76\x7b\xc0\x39\x5a\x38\x12\ -\x39\x33\xe4\x70\x7e\x33\xe4\x0c\x77\xf2\xd3\xd3\x3a\xf3\x1e\x6d\ -\x59\xa5\x45\x3e\x1d\x51\x4c\x46\x9e\xcd\xe3\x22\x49\xf3\xe5\x74\ -\xf4\xef\x5f\x7f\x46\x7a\xe4\x55\x75\x94\x27\x51\x56\xe4\x76\x3a\ -\xca\x8b\xd1\x4f\xb3\xbb\xc9\x5f\x10\xf2\xfe\x56\xda\xa8\xb6\x89\ -\xb7\x4b\xeb\x95\xf7\x4b\xfe\x50\xc5\xd1\xc6\x7a\x3f\xac\xea\x7a\ -\x13\xfa\xfe\x6e\xb7\xc3\x69\xdb\x89\x8b\x72\xe9\xff\xe8\x21\x34\ -\xbb\xbb\x9b\x54\x8f\xcb\x3b\xcf\xf3\x60\xde\xbc\x0a\x93\x78\x3a\ -\x6a\x05\x36\xdb\x32\x6b\x18\x93\xd8\xb7\x99\x5d\xdb\xbc\xae\x7c\ -\x8a\xa9\x3f\x3a\xb0\xc7\x07\xf6\xd8\xcd\x9e\x3e\xda\xb8\x58\xaf\ -\x8b\xbc\x6a\x24\xf3\xea\xd3\x80\xb9\x4c\x16\x3d\xb7\xd3\x66\xc7\ -\x1b\x26\x6a\x8c\xf1\x09\xf3\x19\x43\xc0\x81\xaa\xe7\xbc\x8e\x9e\ -\xd0\xb1\x28\xe8\x78\x49\x94\x11\x42\x7c\xa0\x1d\x38\xdf\xc6\x15\ -\x56\x60\xd0\x0d\xfc\x7a\xf6\xae\x03\x57\xc5\xb6\x8c\xed\x02\xe4\ -\x2c\xce\x6d\xed\x7f\xfe\xf5\x73\x4f\x44\x04\x27\x75\x32\x18\xa6\ -\xb3\xe7\xd1\xac\x47\x46\xce\xa3\xb5\xad\x36\x51\x6c\x2b\xbf\xeb\ -\x6f\xe4\x77\x69\x52\xaf\xa6\xa3\x40\x6c\x9e\x9a\xf6\xca\xa6\xcb\ -\x55\x3d\xe8\x48\x93\xe9\x08\x74\x66\x9a\x06\x4d\x7b\xe0\x12\x74\ -\xcf\xd0\x0e\x17\xf6\x14\x82\x85\xc6\xd4\x2b\x8d\x0a\x48\xc3\xd2\ -\xe9\x1d\x26\x45\xec\x14\x99\x8e\x36\xa5\x5d\xd8\x12\x1c\xca\x56\ -\x28\x2a\xe3\x15\x76\x66\x99\x01\xef\x24\xb1\x8b\xca\xc9\xec\x67\ -\x76\x2d\x98\x5a\x37\x34\xa0\xf6\x93\x6d\x60\xb2\x8d\x8d\x1d\xd0\ -\x7b\xee\xc1\x2c\xf5\xb3\xb3\xc4\x31\x2b\xdf\x9b\xcb\x3b\x52\x78\ -\xf3\xdf\x27\xd0\xd6\x0b\x3d\xce\xe0\x0f\xbd\xc8\xf1\xbc\xe7\xa0\ -\x80\x1d\xbc\xc8\x45\x9e\x2f\xce\x5e\x57\x86\x69\x35\x40\x45\x99\ -\x2e\x53\x30\x50\xc3\xc7\x28\xe6\xcd\x73\x2c\x03\x8b\x1e\xac\x8d\ -\x69\x26\x46\x9e\xff\x86\xd5\x9f\x08\xf2\x80\xb1\xd7\x15\x21\x58\ -\xba\x45\xb5\x8a\x9c\xaa\x72\xbc\x42\xda\x70\xca\x77\x19\xaa\x35\ -\xf7\xe9\x30\xaf\x21\xf7\xb5\x06\x40\xe6\xc6\x4d\x20\xf9\x8d\x1b\ -\x40\xc9\x1b\x37\x80\x51\xb7\x6d\x00\xc5\x2e\xe8\x70\x53\x06\x10\ -\x37\x7e\x0e\xa8\x40\xdc\xb8\x01\xf4\x8d\x6f\x82\x9a\x04\x37\x6f\ -\x00\x74\xe3\x99\x80\xe6\x7f\xb6\x20\x98\xf8\xae\x38\x6a\xbe\x7a\ -\x01\x57\x5c\x25\x8f\xa9\xdd\x1d\x2a\xa8\x79\x54\xd9\x76\xe4\x4d\ -\xb4\x84\xaa\x38\x2b\xca\xe9\xe8\xd3\xa2\x79\x5a\xc2\xbc\x28\x13\ -\x5b\x76\xa4\xa0\x79\x8e\x48\x05\x54\x8e\x69\xfd\xbc\xbf\x07\xb8\ -\x3b\x31\x22\x8c\xda\xd3\xc9\x65\x7a\xb5\x8a\x92\x62\x37\x1d\xb1\ -\x53\xe2\x97\xa2\x58\x3b\x29\x26\x38\x09\x94\x09\x4e\xe9\x31\x98\ -\x08\x71\x26\x30\x64\xf3\xca\x9c\x51\x61\x46\xc4\x24\xc7\x84\x52\ -\x2a\xcf\xa8\xdb\x12\x2a\xcc\x1a\x65\xd1\xb3\x85\x75\x35\xaf\xce\ -\xc8\xd5\xaa\xd8\x2d\x4b\x67\x9f\xba\xdc\xda\x53\x49\x28\x53\xb7\ -\xee\x9a\x01\x6d\xf3\xb4\x86\x52\xbe\x2d\x85\x07\x1c\x4e\x16\xcd\ -\xe7\xc5\xd3\xe5\x01\xaa\x3c\xda\x5c\x21\x3b\x0a\xda\x44\xf5\xaa\ -\xba\x42\xcf\x8b\xc4\xbe\x40\xef\x87\x47\x36\x59\x5a\xb4\x4e\x93\ -\x4d\x91\xe6\xf5\xab\xdc\xaf\x30\x16\xf3\xdf\x20\x5a\xae\x29\xd6\ -\x72\x5c\x51\x6d\x97\xe6\x80\x34\x6a\xaf\x15\x28\xd3\x67\xfe\xd0\ -\x72\x74\x17\x0d\x4a\xea\x17\x38\x5c\x74\xbc\x40\x72\x9e\x78\xe6\ -\x0d\x2d\x6d\x1d\x3d\xa5\xeb\xf4\x8b\x4d\x9c\x78\x1b\x2a\x6b\x5b\ -\x47\x49\x54\x47\x87\xb0\xe8\x7a\xa0\xc0\xa6\xdd\xe5\x42\x99\x2c\ -\xc2\x7f\x7e\xfe\x79\xd6\xc6\xe1\x24\x8e\xc3\xff\x14\xe5\x43\x17\ -\x96\x9e\xe7\x18\xa2\x79\xb1\x05\xb5\x47\xb3\xbe\x7b\x92\xc4\xe1\ -\xa2\x28\xd7\x51\x3d\x4b\xd7\xe0\xec\xee\x8a\xe7\xaf\x4f\xeb\x0c\ -\x02\xb4\x27\x1c\x31\xbb\xb0\x3e\x0c\xba\x1f\xb6\xb4\xfb\x0b\x9f\ -\x8b\xb7\x5e\x49\xbc\x4e\x9d\x90\xff\xaf\x3a\xcd\xb2\x5f\xdc\x24\ -\xfd\x2e\xd8\x0f\x9a\xd6\x99\x9d\x35\x73\xee\x3f\xbb\x55\xf8\xed\ -\x32\xda\x45\xfa\x83\x55\x4e\xfc\xce\x0c\x4d\x6b\x79\x30\xcf\x51\ -\xb0\xf4\x16\xce\xa2\xb9\xcd\xa6\xa3\xbf\x3b\xa2\x77\x46\x5d\x96\ -\xc5\x76\xb3\x06\xd7\x68\xc5\x7b\xb3\x82\xcb\xf4\x5b\x5b\xfd\x9c\ -\x01\xbd\xd9\x6a\xc2\x4f\xa4\x79\xee\x17\xb0\xa8\xf0\x53\x14\x09\ -\xd1\x36\x50\xbb\x9f\x84\x74\xdf\x2c\xb7\x99\x0d\xed\xa3\x05\xbf\ -\x4b\xee\xab\xba\x2c\x1e\x6c\x2f\xbc\x6f\xee\x1d\x2e\xe4\x58\x88\ -\x40\x30\x46\x68\xd7\x9f\xa5\xb9\x05\xed\xc2\xf9\xb6\xae\x87\x7d\ -\xbf\x41\x1c\x84\xa0\x70\xde\x0d\x08\xc1\x51\xdb\x32\x03\xd7\xa9\ -\x43\xd1\xf5\x1d\xf4\x68\x3b\x92\x08\xb6\xb2\xb2\x8c\x9e\xc3\xbc\ -\xc8\xed\xb0\xb7\x58\x2c\x2a\x5b\x87\xe4\x7e\x1d\x95\x0f\xb6\xdc\ -\xd3\x1f\xd3\x2a\x9d\xa7\x99\x1b\xa2\xf9\xcc\xec\x7d\x92\x56\x1b\ -\x30\x4f\x98\xe6\x4e\x8d\xfb\xe2\xd1\x96\x8b\xac\xd8\xf5\x74\x9b\ -\x47\xf0\x42\xf3\x28\x7e\x58\x36\xfa\x85\x51\x0c\xbb\xd1\x36\x8b\ -\x6a\x7b\x38\x44\x00\x22\x67\x56\xa6\x05\x41\x1c\x09\x44\x90\xee\ -\x89\x5d\xec\x49\x6c\x78\xc0\xd9\xe1\x0e\xa4\x0b\x39\xca\xb0\xd4\ -\x52\x90\x83\xc8\x93\xbb\x93\xc2\xc6\x28\x33\x48\x95\x20\xc8\xa4\ -\xc1\x01\xc4\xf0\xa1\x82\xa8\xcb\x28\xaf\x9c\x4f\x43\x04\x45\x75\ -\x99\x3e\xfd\x40\xb0\x92\x4a\x51\x21\xc7\x88\xe0\x40\x32\xa9\x03\ -\x6a\xc6\x64\x4c\xe1\x47\x7e\x3c\x1c\xd6\x6f\xf4\x82\xc5\x42\x2d\ -\x58\xf4\x5e\x2f\x20\x46\xc3\xca\x95\xfe\xf6\x88\x7f\x47\x74\xaf\ -\xb9\xec\xd0\xc3\x2e\x7a\xc1\x29\xfa\x70\x64\xf2\x80\x99\x40\x5d\ -\x42\x5f\x68\x26\x8d\x18\xa2\xcf\x30\x87\x23\x94\x99\x23\xf4\x99\ -\xc6\x5a\x6b\x00\xf7\x2a\xfc\x86\x2b\x2e\x29\x01\xcc\x31\x17\x9a\ -\x7f\xc0\xff\x47\xc0\x3f\xb8\xe9\xfc\x4a\x07\xd0\xd8\x04\x80\xe3\ -\x99\x03\x04\x01\xf8\xc0\x37\x70\x00\x97\x55\xbc\xc9\x01\x8c\x91\ -\xf2\x9d\x0e\xf0\x1e\xdc\xff\x40\x84\xaf\x1f\x2c\x3d\x06\x00\xfb\ -\x3f\x3c\x2a\x20\x67\xa6\x92\xa9\x31\x35\x98\x19\x41\x89\xf6\xb8\ -\xc2\x44\x69\xaa\xc7\x4c\x61\xf7\x66\xc6\x63\x12\x13\xc2\x8c\xe1\ -\x63\xae\x31\xd5\x34\x90\xca\x63\x98\x06\x01\xe7\x06\xf8\x60\x7b\ -\x37\x1c\x4e\x89\x8b\xc3\x7d\x79\xe9\xb8\x91\xee\x77\x5e\xad\xb8\ -\xac\xd0\x65\x29\x90\x19\xc6\xee\xf9\xc0\xfe\x3b\x61\xcf\x01\x22\ -\x40\x4b\x89\x31\x04\xa8\x90\x42\x31\xe5\x05\x0c\x93\x80\x68\x00\ -\x90\x07\xd8\x08\x26\x84\xf6\x84\xc1\x46\xcb\x40\x8c\x85\x82\xc8\ -\x84\x02\x2a\xf0\xc0\x33\xa8\xd0\x46\x2b\xe7\x0f\x90\x03\x48\x29\ -\x2f\x0e\x77\x0d\xfb\x77\x22\xbf\xc7\xfa\x08\xbb\x37\x40\xf9\x62\ -\x0e\xd7\x20\x7a\x0e\x65\xf7\x05\x39\x09\xe1\x44\x72\x97\x5b\xee\ -\x1f\x79\xcd\x17\x8e\xa1\x18\x9a\x7d\xed\xec\xe4\xb6\x39\xad\xc7\ -\x02\xca\x60\x30\x23\xe7\x1e\xe5\x98\x13\x45\x8d\x18\x23\x0a\xd9\ -\x0f\xa5\x46\x79\x02\x83\x81\xe1\xdf\x18\x09\x4c\xb8\x94\xc6\x78\ -\x88\x81\x1e\x5c\x1b\xc3\xc6\x48\xe1\x40\x18\xc2\xb8\x87\x34\x86\ -\xca\x16\x1a\x63\x00\x25\x30\x01\x40\x41\x9b\x6c\x4a\x48\x3d\x0e\ -\x5c\x90\xd2\x40\x9c\x20\xe1\xec\xc9\xb5\x30\xaf\x63\x10\x7f\x9c\ -\xbd\xff\xaf\xb3\x97\xbf\xf3\xec\xa5\x6e\xbb\xd6\x4a\x0f\x8f\x5e\ -\x70\x2c\x2d\x14\x1d\xfc\x07\xde\x77\xcf\xbd\xbe\x5f\x01\xf6\x67\ -\xc7\x1f\x89\x53\x0f\xf8\x9d\xc5\x57\x00\xec\x81\x36\xf2\x28\xfb\ -\x32\x00\xaa\x61\x8a\x5c\xcf\xbe\xbe\x69\xf5\xf5\xe1\x02\x5f\xef\ -\x02\xe8\xac\x06\xfb\x9d\x4e\x20\x21\x31\x13\xc2\x48\x3a\x74\x02\ -\x38\xd7\xe1\x38\x10\x83\xc2\xec\xeb\x9d\xe0\x23\x0d\xfb\xa6\x69\ -\x18\x64\x4b\x0a\xe0\x62\x63\xc8\x0b\x04\xd5\x8a\x79\x92\x62\x67\ -\x7b\xc5\xc6\x54\x63\x48\xbb\xa5\xe1\x7d\xd6\x20\x9b\xec\x0a\x52\ -\x6b\x46\x3d\x1a\xe0\x40\x09\xce\x99\xcb\xb6\x21\xd9\x56\x17\xc6\ -\x7a\x39\x03\x7b\x73\xfe\x35\xf1\x97\xb3\xbb\x89\xbb\x8e\x9c\xdd\ -\xfd\x0f\x63\x62\xcf\x20\ +\x00\x27\xf1\x78\x9c\xed\x59\xdd\x6f\xdb\x36\x10\x7f\xcf\x5f\xa1\ +\xa9\x2f\x1b\x66\x51\xfc\x14\x49\xc5\xce\x30\xac\x28\x30\x60\x7b\ +\xd9\x3a\xec\xb1\x90\x25\xda\xd6\x22\x4b\x86\x24\xc7\x4e\xff\xfa\ +\x1d\x65\x49\x96\x1d\xc7\xc9\x9a\x74\x03\xe6\xc8\x48\x6d\xf1\x3e\ +\x78\xbc\xfb\x1d\x79\xc7\x8e\x7f\xd8\x2e\x33\xe7\xce\x94\x55\x5a\ +\xe4\x13\x97\x20\xec\x3a\x26\x8f\x8b\x24\xcd\xe7\x13\xf7\x8f\x8f\ +\x1f\x3c\xe5\x3a\x55\x1d\xe5\x49\x94\x15\xb9\x99\xb8\x79\xe1\xfe\ +\x70\x73\x35\xfe\xc6\xf3\x9c\x9f\x4a\x13\xd5\x26\x71\x36\x69\xbd\ +\x70\x7e\xce\x6f\xab\x38\x5a\x19\xe7\xdb\x45\x5d\xaf\x42\xdf\xdf\ +\x6c\x36\x28\x6d\x07\x51\x51\xce\xfd\xef\x1c\xcf\xbb\xb9\xba\x1a\ +\x57\x77\xf3\x2b\xc7\x71\x60\xde\xbc\x0a\x93\x78\xe2\xb6\x02\xab\ +\x75\x99\x35\x8c\x49\xec\x9b\xcc\x2c\x4d\x5e\x57\x3e\x41\xc4\x77\ +\xf7\xec\xf1\x9e\x3d\xb6\xb3\xa7\x77\x26\x2e\x96\xcb\x22\xaf\x1a\ +\xc9\xbc\x7a\x37\x60\x2e\x93\x59\xcf\x6d\xad\xd9\xb0\x86\x89\x68\ +\xad\x7d\x4c\x7d\x4a\x3d\xe0\xf0\xaa\xfb\xbc\x8e\xb6\xde\xa1\x28\ +\xd8\x78\x4a\x94\x62\x8c\x7d\xa0\xed\x39\x9f\xc7\x15\x56\xe0\xd0\ +\x15\xfc\xf5\xec\xdd\x00\xaa\x8a\x75\x19\x9b\x19\xc8\x19\x94\x9b\ +\xda\x7f\xff\xf1\x7d\x4f\xf4\x30\x4a\xea\x64\xa0\xa6\xf3\xe7\xc1\ +\xac\x07\x4e\xce\xa3\xa5\xa9\x56\x51\x6c\x2a\xbf\x1b\x6f\xe4\x37\ +\x69\x52\x2f\x26\x6e\xc0\x57\xdb\xe6\x7d\x61\xd2\xf9\xa2\x1e\x0c\ +\xa4\xc9\xc4\x05\x9b\xa9\x22\x41\xf3\x3e\x80\x04\xd9\x31\xb4\xea\ +\xc2\x9e\x82\x11\x57\x88\x21\xe2\x94\x5a\xa9\x9d\x54\x67\x79\x98\ +\x14\xb1\x35\x65\xe2\xfe\x58\xc6\x8b\x4f\x7f\x46\x59\xf6\xe9\x63\ +\x69\x0c\xb2\x6e\xb9\x01\xce\x71\x62\x66\x95\x95\xd8\xcd\x6c\xdf\ +\x60\x6a\xd5\xd0\x80\xda\x4f\xb6\x82\xc9\x56\x26\xb6\x81\xde\x71\ +\x0f\xe6\xa8\xef\xad\x27\x0e\x59\xd9\xce\x5d\xce\x81\xc1\xab\x4f\ +\x5b\xb0\xd6\x09\x1d\x46\xe1\x1f\x72\x92\xe3\x7e\xc7\x41\x20\x76\ +\xf0\x85\x4f\xf2\x7c\xb6\xfe\x3a\xa3\xa6\xb5\xc0\x2b\xca\x74\x9e\ +\x82\x83\x1a\x3e\x4a\x10\x6b\x9e\x43\x19\x58\xf4\x60\x6d\x54\x51\ +\xee\x3a\xfe\x33\x56\x7f\x24\xc8\x02\x4a\x9f\x36\x04\x23\x61\x17\ +\xd5\x1a\x72\x6c\xca\xe1\x0a\x49\xc3\x29\x5e\xe4\xa8\xd6\xdd\xc7\ +\x6a\x9e\x8a\xdc\x97\x3a\xc0\xd3\x17\xee\x02\xc1\x2e\xdc\x01\x52\ +\x5c\xb8\x03\xb4\xbc\x6c\x07\x48\x7a\xc2\x86\x8b\x72\x00\xbf\xf0\ +\x73\x40\x06\xfc\xc2\x1d\xa0\x2e\x7c\x13\x54\x38\xb8\x78\x07\x78\ +\x17\x5e\x09\x28\xf6\x7f\x4b\x82\xb1\x6f\x9b\xa3\xe6\x57\x2f\x60\ +\x5b\xab\xe4\x2e\x35\x9b\x7d\x07\x35\x8d\x2a\xd3\x6a\x5e\x45\x73\ +\xe8\x8a\xb3\xa2\x9c\xb8\xef\x66\xcd\xd3\x12\xa6\x45\x99\x98\xb2\ +\x23\x05\xcd\x73\x40\x2a\xa0\x73\x4c\xeb\xfb\xdd\x3d\xc0\xd5\x91\ +\x13\x41\x6b\x4f\xc7\xa7\xe9\xd5\x22\x4a\x8a\xcd\xc4\xa5\xc7\xc4\ +\xcf\x45\xb1\x9c\xb8\x02\x09\x6c\x1f\x72\x4c\x8e\xc1\x43\x5c\x20\ +\x4c\x45\xc0\x1f\x12\x61\x3e\x2a\x91\x22\x1a\x93\xe0\x01\x71\x5d\ +\x96\x26\xaf\xbd\x2c\xba\x37\xb0\xa8\xe6\xab\xd3\x50\x2d\x8a\xcd\ +\xbc\xb4\xce\xa9\xcb\xb5\x39\x96\x84\x0e\x75\x6d\xef\x18\xbc\x75\ +\x9e\xd6\xd0\xc7\xb7\x7d\xf0\x80\xc3\xca\x7a\xd3\x69\xb1\x3d\xad\ +\xa0\xca\xa3\xd5\x19\xb2\xa5\x78\xab\xa8\x5e\x54\x67\xe8\x79\x91\ +\x98\x47\xe8\xbd\x7a\xcf\x24\x73\xe3\x2d\xd3\x64\x55\xa4\x79\xfd\ +\x24\xf7\x13\x8c\xc5\xf4\x2f\x48\x95\x73\x86\xb5\x1c\x67\x4c\xdb\ +\xa4\x39\x84\xd9\x6b\xef\x14\x08\x55\x0f\xc0\xd0\x72\x74\xb7\x0c\ +\x52\xa8\x47\x38\x6c\x6a\x3c\x42\xb2\x30\xd4\x8f\xd0\x96\xd1\x36\ +\x5d\xa6\x9f\x4d\x62\xc5\xdb\x3c\x59\x9a\x3a\x4a\xa2\x3a\xda\xe7\ +\x44\x37\x02\xdd\x35\xe9\x6e\x16\xca\x64\x16\xfe\xf6\xfe\xc3\x4d\ +\x9b\x84\xe3\x38\x0e\xff\x2c\xca\xdb\x2e\x27\x1d\xc7\x32\x44\xd3\ +\x62\x0d\x66\xbb\x37\xfd\xf0\x38\x89\xc3\x59\x51\x2e\xa3\xfa\x26\ +\x5d\x02\xd2\xed\xfd\xce\xf7\xdb\x65\x06\xd9\xd9\x13\x0e\x98\x6d\ +\x4e\xef\x95\xee\xd4\x96\x66\x77\xdb\x73\xf2\xca\x2b\x89\x97\xa9\ +\x15\xf2\x7f\xaf\xd3\x2c\xfb\xd9\x4e\xd2\x6f\x81\xbd\xd2\xb4\xce\ +\xcc\x7e\x70\xec\xb7\xd6\xb7\x6b\xf3\x07\x8b\x1b\xfb\xdd\xea\x9b\ +\xb7\xf9\xde\x2b\x07\x39\xd2\x3b\x36\x8b\xa6\x26\x9b\xb8\xbf\x58\ +\xa2\xf3\x80\x3a\x2f\x8b\xf5\x6a\x09\x88\x68\xc5\x7b\x6f\x02\x52\ +\xfa\xed\xac\xbe\xcf\x80\xde\x6c\x2f\xe1\xbb\x26\xd1\xf1\xf5\x0c\ +\xd6\x12\xbe\x8b\x22\xce\xdb\x17\xaf\xdd\x43\x42\xb2\x7b\x2d\xd7\ +\x99\x09\xcd\x9d\x01\xb8\x25\xd7\x55\x5d\x16\xb7\xa6\x17\xde\xbd\ +\xee\x70\x16\x32\xc4\x79\xc0\x29\xc5\xa4\x1b\xcf\xd2\xdc\x80\x75\ +\xe1\x74\x5d\xd7\xc3\xb1\xbf\x00\xfe\x21\x18\x9c\x77\x0a\x21\x27\ +\x6a\x53\x66\x80\x98\x3a\xe4\xdd\xd8\xde\x8e\x76\x20\x89\x60\xfb\ +\x2a\xcb\xe8\x3e\xcc\x8b\xdc\x0c\x47\x8b\xd9\xac\x32\x75\x88\xaf\ +\x97\x51\x79\x6b\xca\x1d\xfd\x2e\xad\xd2\x69\x9a\x59\x15\xcd\xcf\ +\xcc\x5c\x27\x69\xb5\x02\xf7\x84\x69\x6e\xcd\xb8\x2e\xee\x4c\x39\ +\xcb\x8a\x4d\x4f\x37\x79\x04\x5f\xde\x34\x8a\x6f\xe7\x8d\x7d\x61\ +\x14\xc3\x26\xb4\xce\xa2\xda\xec\x0f\x0e\x08\x91\x75\x2b\x55\x1c\ +\x7b\xcc\xe3\x1e\xf6\x54\x4f\xec\x52\x4e\x20\xcd\x02\x46\xf7\xf7\ +\x1e\x5d\xa6\x11\x8a\x84\x12\x1c\xef\x45\xb6\xf6\x1e\x0a\x69\x2d\ +\xf5\xa0\x3c\x82\xdc\x12\x1a\x05\x90\xba\xfb\xae\xa1\x2e\xa3\xbc\ +\xb2\x50\x86\xc4\x89\xea\x32\xdd\x7e\x8b\x91\x14\x52\x12\x2e\x46\ +\x1e\x46\x81\xa0\x42\x05\x44\x8f\xf0\x88\xc0\x1f\xfe\x6e\x7f\x40\ +\x3f\x13\x05\xbb\xb3\xe8\xa5\x28\xc0\x5a\xc1\xca\xa5\xd4\xed\xa3\ +\x5e\x3f\xf4\x5f\x31\xcc\xe7\xb0\x3b\x84\xda\x49\x38\x1c\xc3\x80\ +\x72\xc4\x02\xaa\x03\x79\x0a\x06\x5c\x51\xa1\xf9\x10\x06\x14\x31\ +\x42\x08\xf0\x0f\x61\x40\x15\x52\x4a\x41\x94\xcf\xe2\x40\x33\xc9\ +\x04\xc1\x10\x7c\xc4\xb8\x62\x6f\x38\xf8\x4f\x71\x30\xb8\xef\xfc\ +\x42\x24\x28\xa4\x03\x08\xe8\x03\x24\x04\x01\x80\xe1\x15\x90\x60\ +\xcb\x8b\x67\x20\x21\x96\xf6\xf3\x42\x24\xbc\x24\xee\xff\x61\x84\ +\xcf\x1f\x35\x7d\x0c\x20\xec\xbf\x3a\x84\x23\xca\x89\xa0\x72\x44\ +\x34\xa2\x9a\x13\xac\x1c\x26\x11\x96\x8a\xa8\x11\xd4\xc6\xf6\x9b\ +\x6a\x87\x42\x09\x8d\xa9\xd6\x6c\xc4\x14\x22\x8a\x04\x42\x3a\x14\ +\x91\x20\x60\x4c\x03\x1f\x6c\xf8\x9a\xc1\xb9\x71\x52\xdd\xe7\xc7\ +\x0e\x20\x61\xff\x1e\xf6\x2c\xb6\x3c\xb4\xe5\x0a\x94\x88\xb1\x7d\ +\xde\x62\xff\x95\x62\xcf\x20\x44\x10\x2d\xc9\x47\x90\xa0\x5c\x70\ +\x49\xa5\x13\x50\x84\x03\xac\x20\x80\x2c\x40\x9a\x53\xce\x95\xc3\ +\x35\xd2\x0a\xfa\xa7\x11\x97\x90\x99\x94\xca\xc0\x01\x64\x10\xae\ +\xb4\x92\x16\x0f\x50\x15\x08\x21\x4e\xaa\x3b\x17\xfb\x17\x46\x7e\ +\x17\xeb\x83\xd8\x3d\x23\x94\x8f\x56\x75\x4d\x44\x1f\x86\xb2\xfb\ +\x05\x55\x0a\x66\x58\x30\x5b\x6d\xee\x1e\x71\x0e\x0b\x87\xa1\x18\ +\xba\x7d\x69\xfd\x64\xb7\x39\xa5\x46\x1c\x9a\x61\x70\x23\x63\x0e\ +\x61\x88\x61\x49\x34\x1f\x79\x04\xea\x21\x42\xb4\x74\x38\x02\x07\ +\xc3\x67\xe4\x71\x84\x99\x10\x5a\x3b\x1e\x05\x3b\x98\xd2\x9a\x8e\ +\x3c\x89\x02\xae\x31\x65\x8e\xa7\x10\xa3\x50\xc0\xea\x11\x04\x25\ +\xd0\x01\x84\x82\x34\xf5\x15\x17\x6a\x14\xd8\x24\x25\x01\x3f\x8a\ +\x84\xf5\x27\x53\x5c\x3f\x1d\x83\xf8\xed\x10\xfe\xd7\x0f\x61\xf6\ +\xc2\x43\x98\xd8\x7d\x5b\x49\x35\x3c\x83\x01\x61\x8a\x4b\x32\xf8\ +\xff\xbc\xaf\x5e\x8d\xc9\xc8\x7e\x5e\xab\x37\xeb\xf2\x8e\x5f\x12\ +\x10\x3c\x7e\x0c\x85\x7f\xd8\xa0\x05\xc0\x1e\x28\x2d\x0e\xea\x31\ +\x0d\xd1\xd5\x54\xe2\xf3\xf5\xd8\xab\x76\x68\x6f\x58\x78\x05\x2c\ +\x78\x0f\xfa\xb4\x7f\x88\x06\x01\x35\x1b\xe7\x5a\x90\x21\x1a\xe0\ +\xc8\x87\x93\x82\x0f\x9a\xb7\x2f\x47\xc3\x5b\x85\xf6\xaa\x15\x1a\ +\x14\x52\x12\xc2\x45\x47\x50\x32\x70\xa2\x24\x75\x04\x41\xd6\xf7\ +\x92\x8e\x88\x42\x50\x91\x0b\xcd\xfa\x82\x42\x34\x85\x17\x54\xdd\ +\x94\x38\x24\x40\x81\xe4\x8c\x51\x5b\x88\x43\x1d\x2e\x4f\xe8\x7a\ +\xbc\x38\x7b\x76\x69\x36\xf6\xe7\x37\x57\x63\x7b\x65\x79\x73\xf5\ +\x37\x0f\x85\xd5\xfb\ \x00\x00\x11\xff\ \x3c\ \x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ @@ -9719,6 +10193,130 @@ qt_resource_data = "\ \x9a\x32\x44\x99\x70\x39\x33\x94\xd2\xeb\xa7\x55\xab\x4f\x8c\xe1\ \x70\xaa\x5e\x6a\x8c\x9b\xd9\xea\xf6\xea\xc6\x24\x6c\xb7\x57\xff\ \x06\x6a\xf1\x08\x6d\ +\x00\x00\x07\x91\ +\x00\ +\x00\x36\x0d\x78\x9c\xed\x5b\xdd\x6f\xdb\x38\x12\x7f\xcf\x5f\xa1\ +\x53\x5e\x5a\x9c\x25\xf3\x4b\x14\xa9\xda\x59\x1c\xae\xd8\xc3\x02\ +\x77\x38\x60\xdb\xe2\x1e\x0b\x59\xa2\x6d\x6d\x64\xd1\x90\xe4\xd8\ +\xee\x5f\x7f\x43\x59\x5f\x76\xe4\xa4\xe9\xe6\xa1\x17\x9d\x83\x24\ +\xd2\xcc\x90\x1c\xfe\x66\x38\x33\x94\xe8\xd9\x2f\x87\x4d\x6a\x3d\ +\xa8\xbc\x48\x74\x36\xb7\xb1\x8b\x6c\x4b\x65\x91\x8e\x93\x6c\x35\ +\xb7\xbf\x7c\xfe\xd5\x11\xb6\x55\x94\x61\x16\x87\xa9\xce\xd4\xdc\ +\xce\xb4\xfd\xcb\xdd\xcd\xec\x2f\x8e\x63\xfd\x3d\x57\x61\xa9\x62\ +\x6b\x9f\x94\x6b\xeb\xb7\xec\xbe\x88\xc2\xad\xb2\xde\xad\xcb\x72\ +\x1b\x4c\xa7\xfb\xfd\xde\x4d\x6a\xa2\xab\xf3\xd5\xf4\xbd\xe5\x38\ +\x77\x37\x37\xb3\xe2\x61\x75\x63\x59\x16\x8c\x9b\x15\x41\x1c\xcd\ +\xed\xba\xc1\x76\x97\xa7\x95\x60\x1c\x4d\x55\xaa\x36\x2a\x2b\x8b\ +\x29\x76\xf1\xd4\xee\xc4\xa3\x4e\x3c\x32\xa3\x27\x0f\x2a\xd2\x9b\ +\x8d\xce\x8a\xaa\x65\x56\xdc\xf6\x84\xf3\x78\xd9\x4a\x1b\x6d\xf6\ +\xb4\x12\xc2\x52\xca\x29\x22\x53\x42\x1c\x90\x70\x8a\x63\x56\x86\ +\x07\xe7\xbc\x29\xe8\x38\xd4\x94\x20\x84\xa6\xc0\xeb\x24\xbf\x4f\ +\x2a\x38\xa4\x00\xc5\x55\x65\x2a\x6e\x7f\x74\x80\x7f\x0b\xbf\x6d\ +\x83\x86\xe0\x16\x7a\x97\x47\x6a\x09\x2d\x95\x9b\xa9\x72\xfa\xf1\ +\xf3\xc7\x96\xe9\x20\x37\x2e\xe3\x5e\x37\x0d\xfa\x67\xe3\x9e\x99\ +\x24\x0b\x37\xaa\xd8\x86\x91\x2a\xa6\x0d\xbd\x6a\xbf\x4f\xe2\x72\ +\x3d\xb7\x39\xdb\x1e\xaa\xfb\xb5\x4a\x56\xeb\xb2\x47\x48\xe2\xb9\ +\x0d\x33\x24\x02\xf3\xea\xbe\xe7\x40\xf8\x24\x50\x77\x17\xb4\x1c\ +\xe4\x32\xe1\x52\x17\x5b\xb9\x14\xe2\xd4\xaa\xd1\x3c\x88\x75\x64\ +\x54\x99\xdb\x7f\xcb\xa3\xf5\xd7\xdf\xb5\x5e\xba\x06\xbf\x3b\x10\ +\x9a\xc5\x6a\x59\x18\xe1\xd3\xa0\xe6\x0e\x46\x15\x15\x0f\xb8\x80\ +\x9c\x0a\xf3\x7f\xe4\x61\x9c\x80\xbf\x9c\xe4\x4e\x92\xe7\x1c\xca\ +\x05\xae\xdb\x40\xab\xa2\xd4\xdb\x46\xb6\x9e\x0c\x50\x28\x97\xbe\ +\xdd\x91\xf5\x72\x59\x28\x98\x34\xea\xd1\x8a\xf2\x98\xaa\x93\xb4\ +\x13\xe9\x54\xe7\xc1\xed\xb2\xfa\x7c\xa8\x48\x1a\xb0\x4c\xca\x63\ +\x80\x3f\xd8\xd6\xf4\xca\x68\x03\x5d\x88\x85\xf9\x79\xd4\xc5\x63\ +\x55\xb0\x3d\xa4\xb5\xf0\xda\xd1\x66\xd3\xf3\x69\xd7\xd4\xd6\x1a\ +\x5b\xb0\xc6\x56\x45\x66\xdd\x34\x3d\xb5\x46\x28\x8f\xc6\x55\xce\ +\x45\x69\xdc\x8e\xd8\x59\x74\xfb\xf5\x00\xa8\x58\x81\x45\x09\xfc\ +\xc1\x83\x12\xc7\x93\x04\x86\xa5\x00\xff\xd0\xa0\xcc\x37\xe3\x50\ +\x4f\x74\x53\x6b\xe0\xe8\x3c\x59\x25\xe0\x41\x95\x1c\xc1\x2e\xad\ +\x3e\xe7\x6d\x00\x8c\xde\xdc\x88\x20\xac\xc3\xe4\xa9\xd9\x5f\x34\ +\xa4\x9c\x90\xe7\x15\x41\xae\x67\x26\x55\x2b\x72\xa9\xca\xf9\x0c\ +\x71\x25\xe9\xfd\x29\xa0\x6a\xb8\x2f\xbb\x79\xce\x72\x3f\x0a\x80\ +\x23\x47\x0e\x81\x47\x47\x0e\x80\xef\x8d\x1c\x80\x5e\x22\x18\x25\ +\x00\x3e\x19\xd0\x61\x54\x00\xb0\x91\xe7\x01\x9f\xb3\x91\x03\x20\ +\x46\x1e\x04\x05\xe2\xa3\x07\xc0\x19\x79\x25\x20\xe8\xc8\x17\x01\ +\xc7\x23\x0f\x83\x00\x80\x23\x46\x0e\x01\x1b\x79\x14\x00\x00\xc6\ +\x1e\x08\xb9\x3f\xf2\x7a\x10\x00\x70\x46\x9e\x0b\x7c\xf4\x1d\x0f\ +\xa9\xde\x38\x00\x63\xcf\x05\x3e\x7b\x83\x45\xf1\x36\x2c\x4b\x95\ +\x67\x4d\xbb\xfa\xf6\x73\x1e\x66\xc5\x52\xe7\x9b\xb9\xbd\x09\xcb\ +\x3c\x39\xbc\x43\x2e\x87\x6d\x21\xf5\x89\x98\x38\xc8\x15\x58\x10\ +\x89\x3d\x6f\x42\x5c\xe6\xf9\x82\x62\x36\xc1\xae\x10\x8c\x79\x1e\ +\x9b\x38\x84\x03\x15\x71\xc4\x27\x58\xb8\x44\x32\xc9\xfc\xf7\xe7\ +\x8f\x6b\x4f\xa3\x78\x84\x76\x1a\x57\x2f\x42\x82\x75\xae\x96\x73\ +\xfb\xf6\x13\x8c\xb9\x2d\xf0\x57\xec\x0c\x94\x60\x91\x4e\x53\x30\ +\xc9\xdc\x0e\xd3\x7d\x78\x2c\x7e\xc8\x98\x1e\x21\x6f\xb0\xb8\xbb\ +\x30\x66\x2b\x58\x94\x3a\xba\x37\x08\x54\xb8\xaa\xc2\xc2\xc1\xf9\ +\xf3\xf3\x21\xbc\x9f\x72\x05\xee\x83\x23\x30\x3a\x71\xb0\x8b\x10\ +\xc4\x06\x51\x79\x02\xe1\x58\xf8\x02\xae\x28\xc6\xcc\x63\x62\x42\ +\x5d\xe6\x73\x24\x85\x0f\x57\x1e\x65\x92\xd0\xce\x0f\x9a\xf7\x4a\ +\x9d\x22\xf5\x9b\x27\x72\xa9\xc1\x97\x2c\x29\x8b\xb9\xbd\x2b\x54\ +\xfe\xc9\xbc\xb0\xfa\x77\xf6\xa5\x50\xcf\xbb\x45\xfb\x0e\x26\x07\ +\x6a\x23\x7d\x9a\xae\xa1\x30\x26\x68\x6f\xb6\x9d\x42\xa4\x47\xab\ +\x55\xea\xbf\x7b\x01\x3b\xc2\x02\xf0\x7a\x94\xc3\xe0\x7b\xa2\x65\ +\x92\xa6\xc1\x22\x0d\xa3\xfb\x0f\x45\x99\xeb\x7b\x15\x64\x3a\x53\ +\xbd\xb7\x35\xf5\xec\x7e\xcc\x77\xdf\xe2\x73\xfa\x17\x84\xa2\xef\ +\xf5\x3f\xe9\x02\x89\x0a\x3c\x11\xae\xe4\x92\x08\xc4\xae\x06\xa2\ +\x9e\x2f\x5c\x09\x45\x03\xd1\xff\xb5\x42\xd1\x5b\x2c\xb1\x5f\x21\ +\x18\xf1\x51\x05\x23\xf4\xd3\x04\xa3\x97\xac\x44\x0f\x53\x2a\x48\ +\x05\x3e\xa7\x98\x48\x69\xc0\xc7\x50\x2c\x20\x6a\xae\x18\x14\x0a\ +\x3e\xd8\x86\x49\xd7\xe7\xc4\xe3\x86\x2d\x3d\xc6\x05\xba\x56\x13\ +\x48\x3e\xbc\x10\xfb\x6b\x75\x60\xb9\xbc\xce\x52\x14\x6f\xb0\xc6\ +\x7d\xfd\xb8\x6a\x2a\x3c\x4a\x39\x88\x4e\x30\x14\x83\xc2\xc7\xf2\ +\x7a\x85\xd7\x33\xd6\xb5\x1a\xef\x45\xf6\x7c\x8d\x22\xa7\x37\xe0\ +\x18\x22\x0b\xeb\x45\xd2\xff\x9d\xd8\xc2\x00\x7b\x26\x04\x37\x1b\ +\x0e\x4e\x60\xb7\x21\x98\x84\x6d\x86\xe7\x41\x70\xe1\x3e\x5c\x31\ +\x8a\xa9\xe4\x13\xe2\xbb\x92\x09\x66\xf6\x20\xd4\xa5\x88\x33\x8f\ +\x0f\x3b\x23\xa5\xe8\x39\x57\x1c\x28\xab\x5e\x25\xb0\x50\xf2\xff\ +\x0c\xdf\x21\x33\x84\xf7\x18\xd6\x21\xfd\x69\x56\xe1\x8b\x7c\x97\ +\x8f\xfb\xd9\x97\x47\xc5\x1b\x5c\xbc\x2f\x01\x80\xe1\x37\xe8\x01\ +\x57\x8e\x8f\x5e\x5b\xdf\x83\x89\x63\xe0\xa0\x69\x1f\xc3\x4b\xb6\ +\xec\xd6\xf1\x01\xcf\x6d\xea\xbb\x42\x42\x96\xeb\x0e\x1c\x1d\x81\ +\xca\xcc\x69\x59\xe6\xf7\x5e\x3a\x1c\xc8\xdc\xe6\xc4\x45\x4c\xf8\ +\x7e\x17\x30\x8f\x86\x8a\x5c\xa8\xb0\x30\xee\x7a\x58\xd5\x83\x3d\ +\x1d\xc5\x1a\xa9\xa1\x68\x4b\x18\x21\x3e\xc2\xf2\x94\x76\x99\x87\ +\x7d\x49\x26\x55\xa5\xcf\x29\x82\x74\x0b\x12\xc4\x87\x34\x4b\xbc\ +\x89\xe7\x72\xc4\x24\xf2\xc4\x84\x11\x17\x88\x98\x8a\xf7\x35\xc0\ +\xb3\xa9\x39\xae\x5b\x5d\xb5\x16\x31\xe7\x7c\xe3\x87\x44\xed\x6f\ +\x5a\x84\x16\x61\xab\xd5\x36\x5c\xa9\xea\x50\x2c\xe0\x7a\x3a\x58\ +\x5b\x33\x16\x3a\x8f\x55\xde\xb0\x78\xf5\x39\x63\xd5\xe7\x66\x4f\ +\x47\xd8\x6f\x2e\xbc\x14\x7a\x6d\xf9\x68\x98\x5f\xac\xc3\x58\xef\ +\xbb\x50\xdc\x32\xbf\x69\x0d\xc8\x50\xa8\x70\x25\x12\xfe\x23\x76\ +\x04\x2e\xe8\x60\xd8\xcf\x10\xea\xfb\xec\x11\xd7\x28\xc4\x5c\x28\ +\x8d\x05\xc1\x8f\x98\xbb\x3c\x07\xfc\x9d\x34\x3c\x2a\x98\x55\xf5\ +\xaf\x11\x2a\xd6\x7a\xbf\xca\x0d\x3a\x65\xbe\x53\x97\x2d\x63\x1d\ +\xed\xcc\xf9\x78\x67\x77\xb2\x70\x7d\x2a\xbb\x27\x61\xda\x3a\x8b\ +\x85\x3e\x0c\x77\x50\x64\xe1\xf6\x09\xb6\xe1\x38\x90\x2c\xd6\xc5\ +\x13\xfc\x4c\xc7\xea\x0a\xbf\xed\xde\x51\xf1\x4a\x39\x9b\x24\xde\ +\xea\x24\x2b\x9f\x95\x7e\x46\x50\x2f\xfe\x80\xd5\xf8\x94\x62\xb5\ +\xc4\x13\xaa\xed\x93\x0c\xec\xec\x34\x59\x96\x88\x47\xde\x50\x4b\ +\x34\xb9\xd9\xf7\xc4\x15\x89\x5e\x12\xbe\x64\x19\xb3\xcb\x2b\xbc\ +\x4d\x78\x48\x36\xc9\x37\x15\x9b\xe6\xf5\x42\xd9\xa8\x32\x8c\xc3\ +\x32\xec\x16\x45\x43\x21\xc6\x71\xea\x68\x95\xc7\xcb\xe0\xf7\x8f\ +\xbf\xb6\x55\x46\x14\x05\xff\xd1\xf9\x7d\x57\x07\x18\x81\x70\xa1\ +\x77\xa0\x76\x5b\x8b\x98\x23\xf4\x51\x60\xd6\x77\x58\xde\x25\x1b\ +\x70\x75\xf3\xdd\x84\xbf\x1e\x36\x29\x2c\xcf\x96\x71\x26\x6c\xa2\ +\x66\xd7\xe9\xa9\xdb\x5c\x9d\xbe\x7b\x30\xf8\x75\x8d\x38\xda\x24\ +\xa6\xd1\xf4\x53\x09\x25\xc8\x6f\x66\x90\xde\x01\xf8\xba\xd3\xa4\ +\x4c\xd5\x5d\x35\xe6\xe9\xb2\x99\xc5\xb4\x9e\x46\x53\xa4\xf4\x66\ +\x39\x9b\x36\x30\x54\x77\xab\x0e\x9e\xb3\xc5\xd2\x22\x9c\x86\x0b\ +\x95\xce\xed\x7f\x1a\xa6\xf5\x88\xbb\xca\xf5\x6e\xbb\x01\xd7\xa8\ +\x9b\xdb\x5d\x09\xbb\x6e\x33\x47\xaf\x92\xba\xe5\x0b\xf3\xf3\xc1\ +\xdc\xf4\xce\xe5\xd7\xa5\xd5\x2d\xaa\x3e\xf5\xed\xc9\xa1\x02\xda\ +\xdc\x9a\xa8\x0f\x83\x06\x8b\x5d\x59\xf6\x69\x7f\x80\x7b\x07\xa0\ +\x47\x16\x37\x54\x40\x4e\xe5\x29\x78\x44\x19\xb0\x86\x76\x39\x98\ +\x13\x87\x10\x9f\xf2\x3c\x3c\x9e\x2a\xba\x46\x5b\x00\xe2\x5f\x16\ +\x81\xb0\x4c\x25\xf2\xf9\x84\x79\xae\x27\xb8\x8f\x88\x05\xa1\x58\ +\x20\xe9\x49\xa8\x91\xa9\x8b\x89\xe7\x21\x6c\x31\x09\x1b\x23\xe9\ +\x63\x7f\x22\x5d\x09\xc1\x4c\x52\x8b\x40\x1c\xc7\xb0\xa5\x22\x13\ +\x02\x61\xdc\x83\x2c\x44\xad\x6f\x97\xdb\xa6\x35\x91\x68\x20\xfb\ +\x46\x3a\x83\x29\x96\x3a\x77\x20\x8e\x3d\x84\xe5\x2e\x57\xfd\xa2\ +\xb4\x0b\xf8\x00\xb8\xf1\x0d\x58\x8f\x91\xf9\x9c\x6d\x1d\x06\x71\ +\x07\xc7\x7a\xf7\x28\xab\x4a\xef\xfd\xcf\x6e\x88\x01\x80\x4d\xc6\ +\x26\x98\x51\x3a\x21\xdc\x3c\xf2\x82\x0c\x62\x51\x0f\x68\x3e\x24\ +\xf7\x89\x07\x56\x32\x89\xfb\x7b\xed\x20\xe4\xe0\xe3\xe7\x3f\x65\ +\x87\xd9\x74\x75\x77\x33\x33\x21\xe1\xee\xe6\xbf\x41\x63\xea\xe4\ +\ \x00\x00\x06\xdd\ \x00\ \x00\x22\x8f\x78\x9c\xed\x59\xdb\x6e\xe3\x46\x12\x7d\xf7\x57\xf4\ @@ -9867,6 +10465,10 @@ qt_resource_name = "\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x66\x00\x72\x00\x2e\x00\x71\x00\x6d\ \x00\x0a\ +\x0e\x6f\xe4\x5d\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x70\x00\x6c\x00\x2e\x00\x71\x00\x6d\ +\x00\x0a\ \x0e\x69\x64\x5d\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x69\x00\x74\x00\x2e\x00\x71\x00\x6d\ @@ -9976,6 +10578,10 @@ qt_resource_name = "\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x53\x00\x70\x00\x6c\x00\x69\x00\x74\x00\x4d\x00\x65\x00\x73\x00\x68\x00\x2e\x00\x73\x00\x76\ \x00\x67\ \x00\x0d\ +\x07\x4a\x92\xc7\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x52\x00\x6f\x00\x6f\x00\x66\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0d\ \x01\xb7\x92\xa7\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x53\x00\x69\x00\x74\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ @@ -10022,6 +10628,11 @@ qt_resource_name = "\ \x00\x41\ \x00\x72\x00\x63\x00\x68\x00\x5f\x00\x46\x00\x6c\x00\x6f\x00\x6f\x00\x72\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x2e\x00\x73\ \x00\x76\x00\x67\ +\x00\x12\ +\x08\x61\x2a\xa7\ +\x00\x41\ +\x00\x72\x00\x63\x00\x68\x00\x5f\x00\x52\x00\x6f\x00\x6f\x00\x66\x00\x5f\x00\x54\x00\x72\x00\x65\x00\x65\x00\x2e\x00\x73\x00\x76\ +\x00\x67\ \x00\x14\ \x02\xc8\x0e\x47\ \x00\x41\ @@ -10031,50 +10642,53 @@ qt_resource_name = "\ qt_resource_struct = "\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x01\ -\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2c\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x18\x00\x00\x00\x14\ -\x00\x00\x00\x1a\x00\x02\x00\x00\x00\x10\x00\x00\x00\x04\ -\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x01\x4b\x12\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00\x01\x00\x00\x00\x2f\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1a\x00\x00\x00\x15\ +\x00\x00\x00\x1a\x00\x02\x00\x00\x00\x11\x00\x00\x00\x04\ +\x00\x00\x01\xd8\x00\x00\x00\x00\x00\x01\x00\x01\x60\x78\ \x00\x00\x00\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x55\x20\ \x00\x00\x00\x6c\x00\x00\x00\x00\x00\x01\x00\x00\x26\xb4\ -\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x01\x34\xf6\ -\x00\x00\x00\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x83\xa2\ +\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x01\x4a\x5c\ +\x00\x00\x00\xee\x00\x00\x00\x00\x00\x01\x00\x00\x99\x08\ \x00\x00\x00\x52\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xf6\ -\x00\x00\x01\x22\x00\x00\x00\x00\x00\x01\x00\x00\xc5\x12\ -\x00\x00\x01\x56\x00\x00\x00\x00\x00\x01\x00\x00\xf1\xa2\ -\x00\x00\x01\x3c\x00\x00\x00\x00\x00\x01\x00\x00\xdb\x3a\ -\x00\x00\x00\xee\x00\x00\x00\x00\x00\x01\x00\x00\x99\x06\ -\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x00\xaf\x16\ -\x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x6c\x7e\ -\x00\x00\x01\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x1e\xd2\ +\x00\x00\x01\x3c\x00\x00\x00\x00\x00\x01\x00\x00\xda\x78\ +\x00\x00\x01\x56\x00\x00\x00\x00\x00\x01\x00\x00\xf0\xa0\ +\x00\x00\x01\x70\x00\x00\x00\x00\x00\x01\x00\x01\x07\x08\ +\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x00\xae\x6c\ +\x00\x00\x01\x22\x00\x00\x00\x00\x00\x01\x00\x00\xc4\x7c\ +\x00\x00\x00\xd4\x00\x00\x00\x00\x00\x01\x00\x00\x81\xe4\ +\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x01\x34\x38\ \x00\x00\x00\x86\x00\x00\x00\x00\x00\x01\x00\x00\x3e\x30\ -\x00\x00\x01\x70\x00\x00\x00\x00\x00\x01\x00\x01\x08\x08\ +\x00\x00\x01\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x6e\ +\x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x6c\x7e\ \x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x05\x12\x00\x01\x00\x00\x00\x01\x00\x02\x2d\xc6\ -\x00\x00\x04\x1e\x00\x00\x00\x00\x00\x01\x00\x01\xef\xf7\ -\x00\x00\x02\xfc\x00\x00\x00\x00\x00\x01\x00\x01\xa1\x85\ -\x00\x00\x05\xb2\x00\x01\x00\x00\x00\x01\x00\x02\x59\x58\ -\x00\x00\x04\xe4\x00\x01\x00\x00\x00\x01\x00\x02\x26\xf4\ -\x00\x00\x03\x36\x00\x01\x00\x00\x00\x01\x00\x01\xaf\xf4\ -\x00\x00\x03\x88\x00\x01\x00\x00\x00\x01\x00\x01\xc3\x7b\ -\x00\x00\x02\xa0\x00\x01\x00\x00\x00\x01\x00\x01\x86\xe5\ -\x00\x00\x04\x5e\x00\x00\x00\x00\x00\x01\x00\x02\x09\xd1\ -\x00\x00\x02\x7e\x00\x01\x00\x00\x00\x01\x00\x01\x7d\xec\ -\x00\x00\x03\x64\x00\x01\x00\x00\x00\x01\x00\x01\xb9\x4c\ -\x00\x00\x02\x34\x00\x01\x00\x00\x00\x01\x00\x01\x6d\x44\ -\x00\x00\x02\x5e\x00\x01\x00\x00\x00\x01\x00\x01\x76\xec\ -\x00\x00\x04\x8e\x00\x01\x00\x00\x00\x01\x00\x02\x19\x3f\ -\x00\x00\x03\xf4\x00\x00\x00\x00\x00\x01\x00\x01\xdf\x76\ -\x00\x00\x04\xbc\x00\x01\x00\x00\x00\x01\x00\x02\x1e\x8f\ -\x00\x00\x05\x3c\x00\x00\x00\x00\x00\x01\x00\x02\x34\xa1\ -\x00\x00\x03\xac\x00\x01\x00\x00\x00\x01\x00\x01\xc8\x92\ -\x00\x00\x05\x86\x00\x01\x00\x00\x00\x01\x00\x02\x50\xde\ -\x00\x00\x05\x66\x00\x01\x00\x00\x00\x01\x00\x02\x46\xa4\ -\x00\x00\x04\x3e\x00\x01\x00\x00\x00\x01\x00\x02\x03\xb9\ -\x00\x00\x02\xd2\x00\x00\x00\x00\x00\x01\x00\x01\x8f\x27\ -\x00\x00\x03\xd6\x00\x00\x00\x00\x00\x01\x00\x01\xd0\x7a\ -\x00\x00\x02\x00\x00\x01\x00\x00\x00\x01\x00\x01\x65\xf4\ -\x00\x00\x01\xd8\x00\x01\x00\x00\x00\x01\x00\x01\x61\x46\ +\x00\x00\x05\x4c\x00\x01\x00\x00\x00\x01\x00\x02\x4b\x1c\ +\x00\x00\x04\x58\x00\x00\x00\x00\x00\x01\x00\x02\x0d\x4d\ +\x00\x00\x03\x16\x00\x00\x00\x00\x00\x01\x00\x01\xb7\x13\ +\x00\x00\x06\x16\x00\x01\x00\x00\x00\x01\x00\x02\x7e\x42\ +\x00\x00\x05\x1e\x00\x01\x00\x00\x00\x01\x00\x02\x44\x4a\ +\x00\x00\x03\x50\x00\x01\x00\x00\x00\x01\x00\x01\xc5\x82\ +\x00\x00\x03\xa2\x00\x01\x00\x00\x00\x01\x00\x01\xd9\x09\ +\x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x01\x9c\x71\ +\x00\x00\x04\x98\x00\x00\x00\x00\x00\x01\x00\x02\x27\x27\ +\x00\x00\x04\x38\x00\x01\x00\x00\x00\x01\x00\x02\x05\x85\ +\x00\x00\x02\x98\x00\x01\x00\x00\x00\x01\x00\x01\x93\x78\ +\x00\x00\x05\xec\x00\x01\x00\x00\x00\x01\x00\x02\x76\xad\ +\x00\x00\x03\x7e\x00\x01\x00\x00\x00\x01\x00\x01\xce\xda\ +\x00\x00\x02\x4e\x00\x01\x00\x00\x00\x01\x00\x01\x82\xd0\ +\x00\x00\x02\x78\x00\x01\x00\x00\x00\x01\x00\x01\x8c\x78\ +\x00\x00\x04\xc8\x00\x01\x00\x00\x00\x01\x00\x02\x36\x95\ +\x00\x00\x04\x0e\x00\x00\x00\x00\x00\x01\x00\x01\xf5\x04\ +\x00\x00\x04\xf6\x00\x01\x00\x00\x00\x01\x00\x02\x3b\xe5\ +\x00\x00\x05\x76\x00\x00\x00\x00\x00\x01\x00\x02\x51\xf6\ +\x00\x00\x03\xc6\x00\x01\x00\x00\x00\x01\x00\x01\xde\x20\ +\x00\x00\x05\xc0\x00\x01\x00\x00\x00\x01\x00\x02\x6e\x33\ +\x00\x00\x05\xa0\x00\x01\x00\x00\x00\x01\x00\x02\x63\xf9\ +\x00\x00\x04\x78\x00\x01\x00\x00\x00\x01\x00\x02\x21\x0f\ +\x00\x00\x02\xec\x00\x00\x00\x00\x00\x01\x00\x01\xa4\xb3\ +\x00\x00\x03\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xe6\x08\ +\x00\x00\x02\x1a\x00\x01\x00\x00\x00\x01\x00\x01\x7b\x80\ +\x00\x00\x01\xf2\x00\x01\x00\x00\x00\x01\x00\x01\x76\xac\ " def qInitResources(): diff --git a/src/Mod/Arch/CMakeLists.txt b/src/Mod/Arch/CMakeLists.txt index 0e924ec08c..fcfd728bb8 100644 --- a/src/Mod/Arch/CMakeLists.txt +++ b/src/Mod/Arch/CMakeLists.txt @@ -19,6 +19,8 @@ SET(Arch_SRCS importOBJ.py ArchWindow.py ArchAxis.py + ArchVRM.py + ArchRoof.py ) SOURCE_GROUP("" FILES ${Arch_SRCS}) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 75f85e3e25..7f4c510795 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -58,9 +58,9 @@ class ArchWorkbench(Workbench): def Initialize(self): import DraftTools,DraftGui,Arch_rc,Arch - self.archtools = ["Arch_Wall","Arch_Structure","Arch_Cell", + self.archtools = ["Arch_Wall","Arch_Structure", "Arch_Floor","Arch_Building","Arch_Site", - "Arch_Window","Arch_Axis", + "Arch_Window","Arch_Roof","Arch_Axis", "Arch_SectionPlane","Arch_Add","Arch_Remove"] self.drafttools = ["Draft_Line","Draft_Wire","Draft_Rectangle", "Draft_Polygon","Draft_Arc", @@ -69,26 +69,31 @@ class ArchWorkbench(Workbench): "Draft_Offset","Draft_Upgrade", "Draft_Downgrade","Draft_Trimex"] self.draftcontexttools = ["Draft_ApplyStyle","Draft_ToggleDisplayMode", - "Draft_AddToGroup","Draft_SelectGroup", - "Draft_SelectPlane"] + "Draft_AddToGroup","Draft_SelectGroup", + "Draft_SelectPlane","Draft_ToggleSnap", + "Draft_ShowSnapBar","Draft_ToggleGrid"] self.meshtools = ["Arch_SplitMesh","Arch_MeshToShape", "Arch_SelectNonSolidMeshes","Arch_RemoveShape"] self.appendToolbar(str(DraftTools.translate("arch","Arch tools")),self.archtools) self.appendToolbar(str(DraftTools.translate("arch","Draft tools")),self.drafttools) - self.appendMenu([str(DraftTools.translate("arch","Architecture")),str(DraftTools.translate("arch","Tools"))],self.meshtools) - self.appendMenu(str(DraftTools.translate("arch","Architecture")),self.archtools) - self.appendMenu(str(DraftTools.translate("arch","Draft")),self.drafttools+self.draftcontexttools) + self.appendMenu([str(DraftTools.translate("arch","&Architecture")),str(DraftTools.translate("arch","Conversion Tools"))],self.meshtools) + self.appendMenu(str(DraftTools.translate("arch","&Architecture")),self.archtools) + self.appendMenu(str(DraftTools.translate("arch","&Draft")),self.drafttools+self.draftcontexttools) FreeCADGui.addIconPath(":/icons") FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addPreferencePage(":/ui/archprefs-base.ui","Arch") Log ('Loading Arch module... done\n') def Activated(self): - FreeCADGui.draftToolBar.Activated() + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.Activated() + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.show() Msg("Arch workbench activated\n") def Deactivated(self): - FreeCADGui.draftToolBar.Deactivated() + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.Deactivated() Msg("Arch workbench deactivated\n") def ContextMenu(self, recipient): @@ -100,6 +105,13 @@ class ArchWorkbench(Workbench): FreeCADGui.addWorkbench(ArchWorkbench) FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC") FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ") -FreeCAD.addImportType("Collada (*.dae)","importDAE") -FreeCAD.addExportType("Collada (*.dae)","importDAE") +# check for pycollada +try: + import collada +except: + from DraftTools import translate + FreeCAD.Console.PrintMessage(str(translate("arch","pycollada not found, collada support will be disabled.\n"))) +else: + FreeCAD.addImportType("Collada (*.dae)","importDAE") + FreeCAD.addExportType("Collada (*.dae)","importDAE") diff --git a/src/Mod/Arch/Makefile.am b/src/Mod/Arch/Makefile.am index 75b1680f34..e30ec2a6a5 100644 --- a/src/Mod/Arch/Makefile.am +++ b/src/Mod/Arch/Makefile.am @@ -26,7 +26,9 @@ data_DATA = \ ArchSectionPlane.py \ ArchWindow.py \ ArchCommands.py \ - ArchAxis.py + ArchAxis.py \ + ArchVRM.py \ + ArchRoof.py CLEANFILES = $(BUILT_SOURCES) @@ -58,6 +60,8 @@ EXTRA_DIST = \ Resources/icons/Arch_Structure_Tree.svg \ Resources/icons/Arch_Window_Tree.svg \ Resources/icons/Arch_Axis.svg \ - Resources/icons/Arch_Axis_Tree.svg + Resources/icons/Arch_Axis_Tree.svg \ + Resources/icons/Arch_Roof.svg \ + Resources/icons/Arch_Roof_Tree.svg Resources/ui/archprefs-base.ui diff --git a/src/Mod/Arch/Resources/Arch.qrc b/src/Mod/Arch/Resources/Arch.qrc index ba886872b9..b3667134cf 100644 --- a/src/Mod/Arch/Resources/Arch.qrc +++ b/src/Mod/Arch/Resources/Arch.qrc @@ -24,6 +24,8 @@ icons/Arch_Window_Tree.svg icons/Arch_Axis.svg icons/Arch_Axis_Tree.svg + icons/Arch_Roof.svg + icons/Arch_Roof_Tree.svg ui/archprefs-base.ui translations/Arch_af.qm translations/Arch_de.qm @@ -36,6 +38,7 @@ translations/Arch_ru.qm translations/Arch_se.qm translations/Arch_uk.qm + translations/Arch_pl.qm translations/Arch_pt.qm translations/Arch_hr.qm translations/Arch_zh.qm diff --git a/src/Mod/Arch/Resources/icons/Arch_Roof.svg b/src/Mod/Arch/Resources/icons/Arch_Roof.svg new file mode 100644 index 0000000000..0d72e27b02 --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Roof.svg @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/Mod/Arch/Resources/icons/Arch_Roof_Tree.svg b/src/Mod/Arch/Resources/icons/Arch_Roof_Tree.svg new file mode 100644 index 0000000000..8b105168a9 --- /dev/null +++ b/src/Mod/Arch/Resources/icons/Arch_Roof_Tree.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/src/Mod/Arch/Resources/icons/Arch_Site_Tree.svg b/src/Mod/Arch/Resources/icons/Arch_Site_Tree.svg index 4e4bd79310..d43aee6133 100644 --- a/src/Mod/Arch/Resources/icons/Arch_Site_Tree.svg +++ b/src/Mod/Arch/Resources/icons/Arch_Site_Tree.svg @@ -14,8 +14,8 @@ height="64px" id="svg2985" version="1.1" - inkscape:version="0.48.1 r9760" - sodipodi:docname="Arch_Site.svg"> + inkscape:version="0.48.3.1 r9886" + sodipodi:docname="Arch_Site_Tree.svg"> @@ -99,7 +99,7 @@ image/svg+xml - + @@ -118,7 +118,7 @@ id="path3869" inkscape:connector-curvature="0" /> diff --git a/src/Mod/Arch/Resources/icons/Arch_Wall_Tree.svg b/src/Mod/Arch/Resources/icons/Arch_Wall_Tree.svg index 94c448db00..9ab2fe9307 100644 --- a/src/Mod/Arch/Resources/icons/Arch_Wall_Tree.svg +++ b/src/Mod/Arch/Resources/icons/Arch_Wall_Tree.svg @@ -13,8 +13,8 @@ height="64px" id="svg2816" version="1.1" - inkscape:version="0.48.1 r9760" - sodipodi:docname="preferences-arch.svg"> + inkscape:version="0.48.3.1 r9886" + sodipodi:docname="Arch_Wall_Tree.svg"> image/svg+xml - + @@ -160,7 +160,7 @@ y="59.61282" transform="matrix(0.7577145,-0.65258619,0,1,0,0)" /> @@ -191,7 +191,7 @@ id="path3849" sodipodi:nodetypes="cccccc" /> diff --git a/src/Mod/Arch/Resources/ui/archprefs-base.ui b/src/Mod/Arch/Resources/ui/archprefs-base.ui index 88b1ba306f..ec9b787c0f 100644 --- a/src/Mod/Arch/Resources/ui/archprefs-base.ui +++ b/src/Mod/Arch/Resources/ui/archprefs-base.ui @@ -165,20 +165,17 @@ - + - + - if this is checked, the internal Arch IFC parser will be use to build Arch objects from known IFC types. + If this is checked, the IFCOpenShell importer will be used, allowing to import more IFC types - use internal IFC parser - - - true + Use IFCOpenShell if available - useIfcParser + useIfcOpenShell Mod/Arch @@ -188,17 +185,34 @@ - + - + - If this is checked, the IFCOpenShell importer will be used for objects not handled by the internal parser + Creates groups for each Arch object type - Use IFCOpenShell + Group components by types - useIfcOpenShell + createIfcGroups + + + Mod/Arch + + + + + + + + + + + Import furniture (can make the model heavy) + + + importIfcFurniture Mod/Arch diff --git a/src/Mod/Arch/importDAE.py b/src/Mod/Arch/importDAE.py index 92f9f52fa4..123adadae0 100644 --- a/src/Mod/Arch/importDAE.py +++ b/src/Mod/Arch/importDAE.py @@ -51,6 +51,17 @@ def open(filename): read(filename) return doc +def insert(filename,docname): + "called when freecad wants to import a file" + if not checkCollada(): return + try: + doc = FreeCAD.getDocument(docname) + except: + doc = FreeCAD.newDocument(docname) + FreeCAD.ActiveDocument = doc + read(filename) + return doc + def decode(name): "decodes encoded strings" try: diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index e676114293..17dc3d1662 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -21,17 +21,20 @@ #* * #*************************************************************************** -import ifcReader, FreeCAD, Arch, Draft, os, sys, time, tempfile, Part -from draftlibs import fcvec +import ifcReader, FreeCAD, Arch, Draft, os, sys, time, Part, DraftVecUtils __title__="FreeCAD IFC importer" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" +# config DEBUG = True SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.exp" -SKIP = ["IfcOpeningElement"] -pyopen = open # because we'll redefine open below +SKIP = ["IfcOpeningElement","IfcSpace"] +# end config + +if open.__module__ == '__builtin__': + pyopen = open # because we'll redefine open below def open(filename): "called when freecad opens a file" @@ -39,13 +42,33 @@ def open(filename): doc = FreeCAD.newDocument(docname) doc.Label = decode(docname) FreeCAD.ActiveDocument = doc + global createIfcGroups, useIfcOpenShell, importIfcFurniture + createIfcGroups = useIfcOpenShell = importIfcFurniture = False p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") - op = p.GetBool("useIfcOpenShell") - ip = p.GetBool("useIfcParser") - if op: - readOpenShell(filename,useParser=ip) - else: - read(filename) + useIfcOpenShell = p.GetBool("useIfcOpenShell") + createIfcGroups = p.GetBool("createIfcGroups") + importIfcFurniture = p.GetBool("importIfcFurniture") + if not importIfcFurniture: + SKIP.append("IfcFurnishingElement") + read(filename) + return doc + +def insert(filename,docname): + "called when freecad wants to import a file" + try: + doc = FreeCAD.getDocument(docname) + except: + doc = FreeCAD.newDocument(docname) + FreeCAD.ActiveDocument = doc + global createIfcGroups, useIfcOpenShell, importIfcFurniture + createIfcGroups = useIfcOpenShell = importIfcFurniture = False + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") + useIfcOpenShell = p.GetBool("useIfcOpenShell") + createIfcGroups = p.GetBool("createIfcGroups") + importIfcFurniture = p.GetBool("importIfcFurniture") + if not importIfcFurniture: + SKIP.append("IfcFurnishingElement") + read(filename) return doc def decode(name): @@ -83,41 +106,72 @@ def getIfcOpenShell(): else: return True -def readOpenShell(filename,useParser=False): - "Parses an IFC file with IfcOpenShell" +def read(filename): + "Parses an IFC file" - altifc = None - if useParser: - altifc = parseFile(filename) + # parsing the IFC file + t1 = time.time() + schema=getSchema() + if schema: + if DEBUG: global ifc + if DEBUG: print "opening",filename,"..." + ifc = ifcReader.IfcDocument(filename,schema=schema,debug=DEBUG) + else: + FreeCAD.Console.PrintWarning("IFC Schema not found, IFC import disabled.\n") + return None + t2 = time.time() + if DEBUG: print "Successfully loaded",ifc,"in %s s" % ((t2-t1)) - if getIfcOpenShell(): - USESHAPES = False + if useIfcOpenShell and getIfcOpenShell(): + # use the IfcOpenShell parser + + useShapes = False if hasattr(IfcImport,"USE_BREP_DATA"): IfcImport.Settings(IfcImport.USE_BREP_DATA,True) - USESHAPES = True + useShapes = True if IfcImport.Init(filename): while True: obj = IfcImport.Get() if DEBUG: print "parsing ",obj.id,": ",obj.name," of type ",obj.type meshdata = [] - n = obj.name - if not n: n = "Unnamed" + # retrieving name + n = obj.name + if not n: + n = "Unnamed" + + # build shape + shape = None + if useShapes: + shape = getShape(obj) + + # skip types if obj.type in SKIP: pass - - elif altifc and (obj.type == "IfcWallStandardCase"): - if USESHAPES: - makeWall(altifc.Entities[obj.id],shape=getShape(obj)) - else: - makeWall(altifc.Entities[obj.id]) + + # walls + elif obj.type == "IfcWallStandardCase": + makeWall(ifc.Entities[obj.id],shape) + + # windows + elif obj.type in ["IfcWindow","IfcDoor"]: + makeWindow(ifc.Entities[obj.id],shape) + + # structs + elif obj.type in ["IfcBeam","IfcColumn","IfcSlab"]: + makeStructure(ifc.Entities[obj.id],shape) + + # furniture + elif obj.type == "IfcFurnishingElement": + nobj = FreeCAD.ActiveDocument.addObject("Part::Feature","Furniture") + nobj.Shape = shape - elif USESHAPES: - # treat as Parts - sh = getShape(obj) + elif shape: + # treat as dumb parts nobj = FreeCAD.ActiveDocument.addObject("Part::Feature",n) - nobj.Shape = sh + nobj.Shape = shape + else: # treat as meshes me,pl = getMesh(obj) @@ -127,8 +181,212 @@ def readOpenShell(filename,useParser=False): if not IfcImport.Next(): break - IfcImport.CleanUp() + + IfcImport.CleanUp() + + else: + # use only the internal python parser + + # getting walls + for w in ifc.getEnt("IfcWallStandardCase"): + makeWall(w) + + # getting windows and doors + for w in (ifc.getEnt("IfcWindow") + ifc.getEnt("IfcDoor")): + makeWindow(w) + + # getting structs + for w in (ifc.getEnt("IfcSlab") + ifc.getEnt("IfcBeam") + ifc.getEnt("IfcColumn")): + makeStructure(w) + + order(ifc) + FreeCAD.ActiveDocument.recompute() + t3 = time.time() + if DEBUG: print "done processing",ifc,"in %s s" % ((t3-t1)) + return None + +def order(ifc): + "orders the already generated elements by building and by floor" + + # getting floors + for f in ifc.getEnt("IfcBuildingStorey"): + group(f,"Floor") + # getting buildings + for b in ifc.getEnt("IfcBuilding"): + group(b,"Building") + # getting sites + for s in ifc.getEnt("IfcSite"): + group(s,"Site") + +def group(entity,mode=None): + "gathers the children of the given entity" + + try: + if DEBUG: print "=====> making group",entity.id + placement = None + placement = getPlacement(entity.ObjectPlacement) + if DEBUG: print "got cell placement",entity.id,":",placement + subelements = ifc.find("IFCRELCONTAINEDINSPATIALSTRUCTURE","RelatingStructure",entity) + subelements.extend(ifc.find("IFCRELAGGREGATES","RelatingObject",entity)) + elts = [] + for s in subelements: + if hasattr(s,"RelatedElements"): + s = s.RelatedElements + if not isinstance(s,list): s = [s] + elts.extend(s) + elif hasattr(s,"RelatedObjects"): + s = s.RelatedObjects + if not isinstance(s,list): s = [s] + elts.extend(s) + elif hasattr(s,"RelatedObject"): + s = s.RelatedObject + if not isinstance(s,list): s = [s] + elts.extend(s) + print "found dependent elements: ",elts + + groups = [['Wall','IfcWallStandardCase',[]], + ['Window','IfcWindow',[]], + ['Door','IfcDoor',[]], + ['Slab','IfcSlab',[]], + ['Beam','IfcBeam',[]], + ['Column','IfcColumn',[]], + ['Floor','IfcBuildingStorey',[]], + ['Building','IfcBuilding',[]], + ['Furniture','IfcFurnishingElement',[]]] + + for e in elts: + for g in groups: + if e.type.upper() == g[1].upper(): + o = FreeCAD.ActiveDocument.getObject(g[0] + str(e.id)) + if o: + g[2].append(o) + print "groups:",groups + + comps = [] + if createIfcGroups: + if DEBUG: print "creating subgroups" + for g in groups: + if g[2]: + if g[0] in ['Building','Floor']: + comps.extend(g[2]) + else: + fcg = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup",g[0]+"s") + for o in g[2]: + fcg.addObject(o) + comps.append(fcg) + else: + for g in groups: + comps.extend(g[2]) + + name = mode + str(entity.id) + if mode == "Site": + cell = Arch.makeSite(comps,name=name) + elif mode == "Floor": + cell = Arch.makeFloor(comps,name=name) + elif mode == "Building": + cell = Arch.makeBuilding(comps,name=name) + except: + if DEBUG: print "error: skipping group ",entity.id + +def makeWall(entity,shape=None): + "makes a wall in the freecad document" + try: + if DEBUG: print "=====> making wall",entity.id + if shape: + sh = FreeCAD.ActiveDocument.addObject("Part::Feature","WallBody") + sh.Shape = shape + wall = Arch.makeWall(sh,name="Wall"+str(entity.id)) + if DEBUG: print "made wall object ",entity.id,":",wall + return + placement = wall = wire = body = width = height = None + placement = getPlacement(entity.ObjectPlacement) + if DEBUG: print "got wall placement",entity.id,":",placement + width = entity.getProperty("Width") + height = entity.getProperty("Height") + if width and height: + if DEBUG: print "got width, height ",entity.id,":",width,"/",height + for r in entity.Representation.Representations: + if r.RepresentationIdentifier == "Axis": + wire = getWire(r.Items,placement) + wall = Arch.makeWall(wire,width,height,align="Center",name="Wall"+str(entity.id)) + else: + if DEBUG: print "no height or width properties found..." + for r in entity.Representation.Representations: + if r.RepresentationIdentifier == "Body": + for b in r.Items: + if b.type == "IFCEXTRUDEDAREASOLID": + norm = getVector(b.ExtrudedDirection) + norm.normalize() + wire = getWire(b.SweptArea,placement) + wall = Arch.makeWall(wire,width=0,height=b.Depth,name="Wall"+str(entity.id)) + wall.Normal = norm + if wall: + if DEBUG: print "made wall object ",entity.id,":",wall + except: + if DEBUG: print "error: skipping wall",entity.id + +def makeWindow(entity,shape=None): + "makes a window in the freecad document" + try: + typ = "Window" if entity.type == "IFCWINDOW" else "Door" + if DEBUG: print "=====> making window",entity.id + if shape: + window = Arch.makeWindow(name=typ+str(entity.id)) + window.Shape = shape + if DEBUG: print "made window object ",entity.id,":",window + return + placement = window = wire = body = width = height = None + placement = getPlacement(entity.ObjectPlacement) + if DEBUG: print "got window placement",entity.id,":",placement + width = entity.getProperty("Width") + height = entity.getProperty("Height") + for r in entity.Representation.Representations: + if r.RepresentationIdentifier == "Body": + for b in r.Items: + if b.type == "IFCEXTRUDEDAREASOLID": + wire = getWire(b.SweptArea,placement) + window = Arch.makeWindow(wire,width=b.Depth,name=typ+str(entity.id)) + if window: + if DEBUG: print "made window object ",entity.id,":",window + except: + if DEBUG: print "error: skipping window",entity.id + +def makeStructure(entity,shape=None): + "makes a structure in the freecad document" + try: + if entity.type == "IFCSLAB": + typ = "Slab" + elif entity.type == "IFCBEAM": + typ = "Beam" + else: + typ = "Column" + + if DEBUG: print "=====> making struct",entity.id + if shape: + sh = FreeCAD.ActiveDocument.addObject("Part::Feature","StructureBody") + sh.Shape = shape + structure = Arch.makeStructure(sh,name=typ+str(entity.id)) + if DEBUG: print "made structure object ",entity.id,":",structure + return + placement = structure = wire = body = width = height = None + placement = getPlacement(entity.ObjectPlacement) + if DEBUG: print "got window placement",entity.id,":",placement + width = entity.getProperty("Width") + height = entity.getProperty("Height") + for r in entity.Representation.Representations: + if r.RepresentationIdentifier == "Body": + for b in r.Items: + if b.type == "IFCEXTRUDEDAREASOLID": + wire = getWire(b.SweptArea,placement) + structure = Arch.makeStructure(wire,height=b.Depth,name=typ+str(entity.id)) + if structure: + if DEBUG: print "made structure object ",entity.id,":",structure + except: + if DEBUG: print "error: skipping structure",entity.id + + +# geometry helpers ################################################################### def getMesh(obj): "gets mesh and placement from an IfcOpenShell object" @@ -163,127 +421,21 @@ def getShape(obj): 0, 0, 0, 1) sh.Placement = FreeCAD.Placement(mat) return sh - -def read(filename): - "processes an ifc file and add its objects to the given document" - t1 = time.time() - ifc = parseFile(filename) - t2 = time.time() - if DEBUG: print "Successfully loaded",ifc,"in %s s" % ((t2-t1)) - # getting walls - for w in ifc.getEnt("IFCWALLSTANDARDCASE"): - makeWall(w) - # getting floors - for f in ifc.getEnt("IFCBUILDINGSTOREY"): - makeCell(f,"Floor") - # getting buildings - for b in ifc.getEnt("IFCBUILDING"): - makeCell(b,"Building") - FreeCAD.ActiveDocument.recompute() - t3 = time.time() - if DEBUG: print "done processing",ifc,"in %s s" % ((t3-t1)) - -def parseFile(filename): - "parses an IFC file" - schema=getSchema() - if schema: - if DEBUG: global ifc - if DEBUG: print "opening",filename,"..." - ifc = ifcReader.IfcDocument(filename,schema=schema,debug=DEBUG) - return ifc - else: - FreeCAD.Console.PrintWarning("IFC Schema not found, IFC import disabled.\n") - return None - -def makeCell(entity,mode="Cell"): - "makes a cell in the freecad document" - try: - if DEBUG: print "=====> making cell",entity.id - placement = None - placement = getPlacement(entity.ObjectPlacement) - if DEBUG: print "got cell placement",entity.id,":",placement - subelements = ifc.find("IFCRELCONTAINEDINSPATIALSTRUCTURE","RelatingStructure",entity) - subelements.extend(ifc.find("IFCRELAGGREGATES","RelatingObject",entity)) - fcelts = [] - for s in subelements: - if hasattr(s,"RelatedElements"): - s = s.RelatedElements - if not isinstance(s,list): s = [s] - for r in s: - if r.type == "IFCWALLSTANDARDCASE": - o = FreeCAD.ActiveDocument.getObject("Wall"+str(r.id)) - if o: fcelts.append(o) - elif hasattr(s,"RelatedObjects"): - s = s.RelatedObjects - if not isinstance(s,list): s = [s] - for r in s: - if r.type == "IFCBUILDINGSTOREY": - o = FreeCAD.ActiveDocument.getObject("Floor"+str(r.id)) - if o: fcelts.append(o) - name = mode+str(entity.id) - if mode == "Site": - cell = Arch.makeSite(fcelts,name=name) - elif mode == "Floor": - cell = Arch.makeFloor(fcelts,join=True,name=name) - elif mode == "Building": - cell = Arch.makeBuilding(fcelts,name=name) - else: - cell = Arch.makeCell(fcelts,join=True,name=name) - cell.CellType = type - except: - if DEBUG: print "error: skipping cell",entity.id - -def makeWall(entity,shape=None): - "makes a wall in the freecad document" - try: - if DEBUG: print "=====> making wall",entity.id - if shape: - sh = FreeCAD.ActiveDocument.addObject("Part::Feature","WallBody") - sh.Shape = shape - wall = Arch.makeWall(sh) - if DEBUG: print "made wall object ",entity.id,":",wall - return - placement = wall = wire = body = width = height = None - placement = getPlacement(entity.ObjectPlacement) - if DEBUG: print "got wall placement",entity.id,":",placement - width = entity.getProperty("Width") - height = entity.getProperty("Height") - if width and height: - if DEBUG: print "got width, height ",entity.id,":",width,"/",height - for r in entity.Representation.Representations: - if r.RepresentationIdentifier == "Axis": - wire = makeWire(r.Items,placement) - wall = Arch.makeWall(wire,width,height,align="Center",name="Wall"+str(entity.id)) - else: - if DEBUG: print "no height or width properties found..." - for r in entity.Representation.Representations: - if r.RepresentationIdentifier == "Body": - for b in r.Items: - if b.type == "IFCEXTRUDEDAREASOLID": - norm = getVector(b.ExtrudedDirection) - norm.normalize() - wire = makeWire(b.SweptArea,placement) - wall = Arch.makeWall(wire,width=0,height=b.Depth,name="Wall"+str(entity.id)) - wall.Normal = norm - if wall: - if DEBUG: print "made wall object ",entity.id,":",wall - except: - if DEBUG: print "error: skipping wall",entity.id - -def makeWire(entity,placement=None): - "makes a wire in the freecad document" + +def getWire(entity,placement=None): + "returns a wire (created in the freecad document) from the given entity" if DEBUG: print "making Wire from :",entity if not entity: return None if entity.type == "IFCPOLYLINE": pts = [] for p in entity.Points: pts.append(getVector(p)) - return Draft.makeWire(pts,placement=placement) + return Draft.getWire(pts,placement=placement) elif entity.type == "IFCARBITRARYCLOSEDPROFILEDEF": pts = [] for p in entity.OuterCurve.Points: pts.append(getVector(p)) - return Draft.makeWire(pts,closed=True,placement=placement) + return Draft.getWire(pts,closed=True,placement=placement) def getPlacement(entity): "returns a placement from the given entity" @@ -295,7 +447,7 @@ def getPlacement(entity): z = getVector(entity.Axis) y = z.cross(x) loc = getVector(entity.Location) - m = fcvec.getPlaneRotation(x,y,z) + m = DraftVecUtils.getPlaneRotation(x,y,z) pl = FreeCAD.Placement(m) pl.move(loc) elif entity.type == "IFCLOCALPLACEMENT": @@ -313,6 +465,7 @@ def getPlacement(entity): return pl def getVector(entity): + "returns a vector from the given entity" if DEBUG: print "getting point from",entity if entity.type == "IFCDIRECTION": if len(entity.DirectionRatios) == 3: diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index 4c452eb72a..4622e1adfb 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -21,10 +21,10 @@ #* * #*************************************************************************** -import FreeCAD -from draftlibs import fcgeo +import FreeCAD, DraftGeomUtils -pythonopen = open +if open.__module__ == '__builtin__': + pythonopen = open def findVert(aVertex,aList): "finds aVertex in aList, returns index" @@ -41,7 +41,7 @@ def getIndices(shape,offset): for f in shape.Faces: fi = "" # OCC vertices are unsorted. We need to sort in the right order... - edges = fcgeo.sortEdges(f.Wire.Edges) + edges = DraftGeomUtils.sortEdges(f.Wire.Edges) print edges for e in edges: print e.Vertexes[0].Point,e.Vertexes[1].Point diff --git a/src/Mod/Assembly/Gui/Makefile.am b/src/Mod/Assembly/Gui/Makefile.am index 249b578b2b..55eba4b7bc 100644 --- a/src/Mod/Assembly/Gui/Makefile.am +++ b/src/Mod/Assembly/Gui/Makefile.am @@ -2,14 +2,11 @@ SUBDIRS=Resources lib_LTLIBRARIES=libAssemblyGui.la AssemblyGui.la -BUILT_SOURCES=\ - moc_AssemblyView.cpp +#BUILT_SOURCES libAssemblyGui_la_SOURCES=\ AppAssemblyGuiPy.cpp \ Command.cpp \ - AssemblyView.cpp \ - AssemblyView.h \ PreCompiled.cpp \ PreCompiled.h \ Workbench.cpp \ diff --git a/src/Mod/Assembly/Gui/Resources/Makefile.am b/src/Mod/Assembly/Gui/Resources/Makefile.am index 8d058c97f7..c6339530be 100644 --- a/src/Mod/Assembly/Gui/Resources/Makefile.am +++ b/src/Mod/Assembly/Gui/Resources/Makefile.am @@ -1,45 +1,48 @@ noinst_LTLIBRARIES=libResources.la BUILT_SOURCES=\ - qrc_Drawing.cpp + qrc_Assembly.cpp nodist_libResources_la_SOURCES=\ - qrc_Drawing.cpp + qrc_Assembly.cpp EXTRA_DIST = \ - icons/actions/document-new.png \ - icons/actions/document-new.svg \ - icons/actions/drawing-landscape-A0.svg \ - icons/actions/drawing-landscape-A1.svg \ - icons/actions/drawing-landscape-A2.svg \ - icons/actions/drawing-landscape.svg \ - icons/actions/drawing-view.svg \ - icons/actions/drawing-landscape-A3.svg \ - icons/actions/drawing-landscape-A4.svg \ - icons/actions/drawing-landscape-new.svg \ - icons/actions/drawing-portrait-A4.svg \ - icons/Page.svg \ - icons/Pages.svg \ - icons/View.svg \ + icons/actions/Axle_constraint.svg \ translations/Assembly_af.qm \ translations/Assembly_de.qm \ + translations/Assembly_es.qm \ translations/Assembly_fi.qm \ translations/Assembly_fr.qm \ + translations/Assembly_hr.qm \ + translations/Assembly_hu.qm \ translations/Assembly_it.qm \ + translations/Assembly_ja.qm \ translations/Assembly_nl.qm \ translations/Assembly_no.qm \ + translations/Assembly_pl.qm \ + translations/Assembly_pt.qm \ translations/Assembly_ru.qm \ + translations/Assembly_se.qm \ translations/Assembly_uk.qm \ + translations/Assembly_zh.qm \ translations/Assembly_af.ts \ translations/Assembly_de.ts \ + translations/Assembly_es.ts \ translations/Assembly_fi.ts \ translations/Assembly_fr.ts \ + translations/Assembly_hr.ts \ + translations/Assembly_hu.ts \ + translations/Assembly_ja.ts \ translations/Assembly_it.ts \ translations/Assembly_nl.ts \ translations/Assembly_no.ts \ + translations/Assembly_pl.ts \ + translations/Assembly_pt.ts \ translations/Assembly_ru.ts \ + translations/Assembly_se.ts \ translations/Assembly_uk.ts \ - Drawing.qrc \ + translations/Assembly_zh.ts \ + Assembly.qrc \ UpdateResources.bat diff --git a/src/Mod/Cam/App/CMakeLists.txt b/src/Mod/Cam/App/CMakeLists.txt index 3080a60dc6..0b41913746 100644 --- a/src/Mod/Cam/App/CMakeLists.txt +++ b/src/Mod/Cam/App/CMakeLists.txt @@ -88,7 +88,11 @@ SET(Cam_SRCS add_library(Cam SHARED ${Cam_SRCS}) target_link_libraries(Cam ${Cam_LIBS}) -fc_copy_script("Mod/Cam" "Cam" Init.py) + +fc_target_copy_resource(Cam + ${CMAKE_SOURCE_DIR}/src/Mod/Cam + ${CMAKE_BINARY_DIR}/Mod/Cam + Init.py) if(MSVC) set_target_properties(Cam PROPERTIES SUFFIX ".pyd") diff --git a/src/Mod/Cam/App/Makefile.am b/src/Mod/Cam/App/Makefile.am index a53c5c3865..5b63a2c399 100644 --- a/src/Mod/Cam/App/Makefile.am +++ b/src/Mod/Cam/App/Makefile.am @@ -14,8 +14,12 @@ libCam_la_SOURCES=\ ConvertDyna.h \ cutting_tools.cpp \ cutting_tools.h \ + deviation.cpp \ + deviation.h \ edgesort.cpp \ edgesort.h \ + mergedata.cpp \ + mergedata.h \ path_simulate.cpp \ path_simulate.h \ PreCompiled.cpp \ @@ -31,16 +35,16 @@ libCam_la_SOURCES=\ WireExplorer.h # the library search path. -libCam_la_LDFLAGS = -L../../../3rdParty/OCCAdaptMesh -L../../../Base -L../../../App \ - -L../../../Mod/Part/App -L../../../Mod/Mesh/App -L/usr/X11R6/lib -L$(OCC_LIB) \ +libCam_la_LDFLAGS = -L../../../Base -L../../../App \ + $(sim_ac_coin_ldflags) $(sim_ac_coin_libs) \ + -L../../../Mod/Part/App -L../../../Mod/Mesh/App -L/usr/X11R6/lib -L$(OCC_LIB) -L/usr/lib/atlas \ $(GTS_LIBS) $(all_libraries) -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ -libCam_la_CPPFLAGS = -DAppCamExport= +libCam_la_CPPFLAGS = $(sim_ac_coin_cppflags) $(sim_ac_soqt_cppflags) -DAppCamExport= libCam_la_LIBADD = \ -lxerces-c \ -lboost_filesystem \ -l@PYTHON_LIB@ \ - -lOCCAdaptMesh \ -lFreeCADBase \ -lFreeCADApp \ -lPart \ @@ -65,7 +69,14 @@ libCam_la_LIBADD = \ -lTKMesh \ -lblas \ -lumfpack \ - -lamd + -lamd \ + -lcblas \ + -lANN \ + -lSMDS \ + -lSMESHDS \ + -lSMESH \ + -lclapack + %.cpp: %.xml $(top_srcdir)/src/Tools/generateTemplates/templateClassPyExport.py $(PYTHON) $(top_srcdir)/src/Tools/generate.py --outputPath $(@D) $< @@ -90,8 +101,8 @@ Cam_la_DEPENDENCIES = libCam.la # set the include path found by configure AM_CXXFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(all_includes) -I$(OCC_INC) $(GTS_CFLAGS) \ - -I$(top_srcdir)/src/3rdParty -I$(top_srcdir)/src/3rdParty/OCCAdaptMesh/Include - + -I$(top_srcdir)/src/3rdParty $(QT4_CORE_CXXFLAGS) \ + -I$(top_srcdir)/src/3rdParty/salomesmesh/inc -I$(top_srcdir)/src/3rdParty/ANN/include libdir = $(prefix)/Mod/Cam diff --git a/src/Mod/Cam/App/deviation.cpp b/src/Mod/Cam/App/deviation.cpp index fdc9b76987..843bc9cd96 100644 --- a/src/Mod/Cam/App/deviation.cpp +++ b/src/Mod/Cam/App/deviation.cpp @@ -1,229 +1,229 @@ -/*************************************************************************** -* Copyright (c) 2007 * -* Joachim Zettler * -* Human Rezai * -* * -* 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 "deviation.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -Deviation::Deviation() -{} - -Deviation::~Deviation() -{} - -void Deviation::ImportGeometry(const TopoDS_Shape& aShape, const MeshCore::MeshKernel& aMesh) -{ - m_Mesh = aMesh; - m_Cad = aShape; -} - -bool Deviation::GenNormals() -{ - Base::Builder3D log; - TopExp_Explorer aExpFace; - - MeshPnt aMeshStruct; - std::pair inp; - std::map::iterator meshIt; - - MeshCore::MeshKernel FaceMesh; - MeshCore::MeshPointArray MeshPnts; - - int n; - - MeshPnts = m_MeshCad.GetPoints(); - m_pnts.resize(m_MeshCad.CountPoints()); - m_nlvec.resize((m_MeshCad.CountPoints())); - - for (unsigned int i=0; iNodes(); - - // create array of node points in absolute coordinate system - TColgp_Array1OfPnt aPoints(1, aNodes.Length()); - for (Standard_Integer i = 1; i <= aNodes.Length(); i++) - aPoints(i) = aNodes(i).Transformed(aLocation); - - const TColgp_Array1OfPnt2d& aUVNodes = aTr->UVNodes(); - - BRepAdaptor_Surface aSurface(aFace); - Base::Vector3f pnt, normal; - gp_Pnt2d par; - gp_Pnt P; - gp_Vec D1U, D1V; - - for (int i=1; i FailProj; - - MeshCore::MeshFacetGrid aFacetGrid(m_Mesh,10); - MeshCore::MeshAlgorithm malg(m_Mesh); - MeshCore::MeshAlgorithm malg2(m_Mesh); - MeshCore::MeshPointIterator p_it(m_MeshCad); - - Base::Vector3f projPoint, distVec, nvec(0,0,0), projPoint2; - unsigned long facetIndex; - std::stringstream text; - - unsigned int c=0; - int i=0; - - for (p_it.Begin(); p_it.More(); p_it.Next()) - { - if (malg.NearestFacetOnRay(*p_it, m_nlvec[i], aFacetGrid, projPoint, facetIndex)) // gridoptimiert - { - distVec = projPoint - *p_it; - m_nlvec[i] = distVec; // berschreibt normalenvektor - } - else - { - if (!malg2.NearestFacetOnRay(*p_it, m_nlvec[i], projPoint, facetIndex)) // nicht gridoptimiert - { - c++; - FailProj.push_back(i); - m_nlvec[i] = nvec; - } - else - { - distVec = projPoint - *p_it; - m_nlvec[i] = distVec; // berschreibt normalenvektor - } - } - - ++i; - } - - for(int i=0; i -#include -void Deviation::WriteOutput(const QString &dateiname) -{ - QFile anOutputFile(dateiname); - if (!anOutputFile.open(QIODevice::WriteOnly | QIODevice::Text)) - return; - QTextStream out(&anOutputFile); - - out << m_nlvec.size() << endl; - - for(int i=0; i * +* Human Rezai * +* * +* 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 "deviation.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +Deviation::Deviation() +{} + +Deviation::~Deviation() +{} + +void Deviation::ImportGeometry(const TopoDS_Shape& aShape, const MeshCore::MeshKernel& aMesh) +{ + m_Mesh = aMesh; + m_Cad = aShape; +} + +bool Deviation::GenNormals() +{ + Base::Builder3D log; + TopExp_Explorer aExpFace; + + MeshPnt aMeshStruct; + std::pair inp; + std::map::iterator meshIt; + + MeshCore::MeshKernel FaceMesh; + MeshCore::MeshPointArray MeshPnts; + + int n; + + MeshPnts = m_MeshCad.GetPoints(); + m_pnts.resize(m_MeshCad.CountPoints()); + m_nlvec.resize((m_MeshCad.CountPoints())); + + for (unsigned int i=0; iNodes(); + + // create array of node points in absolute coordinate system + TColgp_Array1OfPnt aPoints(1, aNodes.Length()); + for (Standard_Integer i = 1; i <= aNodes.Length(); i++) + aPoints(i) = aNodes(i).Transformed(aLocation); + + const TColgp_Array1OfPnt2d& aUVNodes = aTr->UVNodes(); + + BRepAdaptor_Surface aSurface(aFace); + Base::Vector3f pnt, normal; + gp_Pnt2d par; + gp_Pnt P; + gp_Vec D1U, D1V; + + for (int i=1; i FailProj; + + MeshCore::MeshFacetGrid aFacetGrid(m_Mesh,10); + MeshCore::MeshAlgorithm malg(m_Mesh); + MeshCore::MeshAlgorithm malg2(m_Mesh); + MeshCore::MeshPointIterator p_it(m_MeshCad); + + Base::Vector3f projPoint, distVec, nvec(0,0,0), projPoint2; + unsigned long facetIndex; + std::stringstream text; + + unsigned int c=0; + int i=0; + + for (p_it.Begin(); p_it.More(); p_it.Next()) + { + if (malg.NearestFacetOnRay(*p_it, m_nlvec[i], aFacetGrid, projPoint, facetIndex)) // gridoptimiert + { + distVec = projPoint - *p_it; + m_nlvec[i] = distVec; // berschreibt normalenvektor + } + else + { + if (!malg2.NearestFacetOnRay(*p_it, m_nlvec[i], projPoint, facetIndex)) // nicht gridoptimiert + { + c++; + FailProj.push_back(i); + m_nlvec[i] = nvec; + } + else + { + distVec = projPoint - *p_it; + m_nlvec[i] = distVec; // berschreibt normalenvektor + } + } + + ++i; + } + + for(int i=0; i +#include +void Deviation::WriteOutput(const QString &dateiname) +{ + QFile anOutputFile(dateiname); + if (!anOutputFile.open(QIODevice::WriteOnly | QIODevice::Text)) + return; + QTextStream out(&anOutputFile); + + out << m_nlvec.size() << endl; + + for(int i=0; i * -* Human Rezai * -* * -* 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 DEVIATION_H -#define DEVIATION_H - -#include "best_fit.h" -#include "SpringbackCorrection.h" -#include -#include - -class CamExport Deviation : public SpringbackCorrection -{ -public: - Deviation(); - ~Deviation(); - - bool GenNormals(); - void ImportGeometry(const TopoDS_Shape& aShape, const MeshCore::MeshKernel& aMesh); - void WriteOutput(const QString &dateiname); - bool Compute(); - - TopoDS_Shape m_Cad; // CAD-Geometrie - MeshCore::MeshKernel m_MeshCad; - MeshCore::MeshKernel m_Mesh; - - std::vector m_pnts, m_nlvec; -}; - - +/*************************************************************************** +* Copyright (c) 2007 * +* Joachim Zettler * +* Human Rezai * +* * +* 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 DEVIATION_H +#define DEVIATION_H + +#include "best_fit.h" +#include "SpringbackCorrection.h" +#include +#include + +class CamExport Deviation : public SpringbackCorrection +{ +public: + Deviation(); + ~Deviation(); + + bool GenNormals(); + void ImportGeometry(const TopoDS_Shape& aShape, const MeshCore::MeshKernel& aMesh); + void WriteOutput(const QString &dateiname); + bool Compute(); + + TopoDS_Shape m_Cad; // CAD-Geometrie + MeshCore::MeshKernel m_MeshCad; + MeshCore::MeshKernel m_Mesh; + + std::vector m_pnts, m_nlvec; +}; + + #endif //DEVIATION_H \ No newline at end of file diff --git a/src/Mod/Cam/App/mergedata.cpp b/src/Mod/Cam/App/mergedata.cpp index 073768bf4e..f7a8368d56 100644 --- a/src/Mod/Cam/App/mergedata.cpp +++ b/src/Mod/Cam/App/mergedata.cpp @@ -1,106 +1,106 @@ - -#include "PreCompiled.h" -#include "mergedata.h" -#include - -#include -#include - - - -MergeData::MergeData(): -m_howmanypoints(0) -{ - -} - -MergeData::~MergeData() -{ - -} - - - - - -bool MergeData::Einlesen (const QStringList &dateinamen) -{ - for (int i=0;i + +#include +#include + + + +MergeData::MergeData(): +m_howmanypoints(0) +{ + +} + +MergeData::~MergeData() +{ + +} + + + + + +bool MergeData::Einlesen (const QStringList &dateinamen) +{ + for (int i=0;i * -* Human Rezai * -* * -* 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 MERGEDATA_H -#define MERGEDATA_H - -#include -#include - -class CamExport MergeData -{ -public: - MergeData(); - ~MergeData(); - - bool WriteOutput(const QString &dateiname); - void Open(); - bool Einlesen(const QStringList &filenames); - -private: - std::vector > m_mergedvalues; - bool m_fit; - long m_howmanypoints; -}; - - +/*************************************************************************** +* Copyright (c) 2007 * +* Joachim Zettler * +* Human Rezai * +* * +* 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 MERGEDATA_H +#define MERGEDATA_H + +#include +#include + +class CamExport MergeData +{ +public: + MergeData(); + ~MergeData(); + + bool WriteOutput(const QString &dateiname); + void Open(); + bool Einlesen(const QStringList &filenames); + +private: + std::vector > m_mergedvalues; + bool m_fit; + long m_howmanypoints; +}; + + #endif \ No newline at end of file diff --git a/src/Mod/Cam/Gui/CMakeLists.txt b/src/Mod/Cam/Gui/CMakeLists.txt index dd86a49402..1d8fa71b83 100644 --- a/src/Mod/Cam/Gui/CMakeLists.txt +++ b/src/Mod/Cam/Gui/CMakeLists.txt @@ -65,7 +65,11 @@ SET(CamGui_SRCS add_library(CamGui SHARED ${CamGui_SRCS}) target_link_libraries(CamGui ${CamGui_LIBS}) -fc_copy_script("Mod/Cam" "CamGui" InitGui.py) + +fc_target_copy_resource(CamGui + ${CMAKE_SOURCE_DIR}/src/Mod/Cam + ${CMAKE_BINARY_DIR}/Mod/Cam + InitGui.py) if(MSVC) set_target_properties(CamGui PROPERTIES SUFFIX ".pyd") diff --git a/src/Mod/Cam/Gui/Cutting.cpp b/src/Mod/Cam/Gui/Cutting.cpp index 85c8931f93..b72364aae5 100644 --- a/src/Mod/Cam/Gui/Cutting.cpp +++ b/src/Mod/Cam/Gui/Cutting.cpp @@ -899,7 +899,9 @@ void Cutting::zLevelCallback(void * ud, SoEventCallback * n) if (!vp || !vp->getTypeId().isDerivedFrom(PartGui::ViewProviderPart::getClassTypeId())) return; PartGui::ViewProviderPart* vpp = static_cast(vp); - TopoDS_Shape sh = vpp->getShape(point); + std::string element = vpp->getElement(point->getDetail()); + TopoDS_Shape sh = static_cast(vpp->getObject())-> + Shape.getShape().getSubShape(element.c_str()); if (!sh.IsNull()) { // ok a shape was picked diff --git a/src/Mod/Cam/Gui/Makefile.am b/src/Mod/Cam/Gui/Makefile.am index 983d99f662..266570c4a4 100644 --- a/src/Mod/Cam/Gui/Makefile.am +++ b/src/Mod/Cam/Gui/Makefile.am @@ -1,60 +1,62 @@ - -lib_LTLIBRARIES=libCamGui.la CamGui.la - -BUILT_SOURCES=\ + +lib_LTLIBRARIES=libCamGui.la CamGui.la + +BUILT_SOURCES=\ ui_Cutting.h \ moc_Cutting.cpp - -libCamGui_la_SOURCES=\ + +libCamGui_la_SOURCES=\ Command.cpp \ Cutting.cpp \ Cutting.h \ PreCompiled.cpp \ - PreCompiled.h \ - Workbench.cpp \ - Workbench.h - -# the library search path. + PreCompiled.h \ + Workbench.cpp \ + Workbench.h + +# the library search path. libCamGui_la_LDFLAGS = -L../../../Base -L../../../App -L../../../Gui -L../App $(QT_LIBS) $(sim_ac_coin_ldflags) \ - $(sim_ac_coin_libs) $(sim_ac_soqt_ldflags) $(sim_ac_soqt_libs) -L$(OCC_LIB) $(all_libraries) \ - -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ -libCamGui_la_CPPFLAGS = -DAppCamExport= -DAppCamGuiExport= - -libCamGui_la_LIBADD = \ - -lxerces-c \ - -l@PYTHON_LIB@ \ - -lFreeCADBase \ - -lFreeCADApp \ - -lFreeCADGui \ - -lTKernel \ - -lCam - -#-------------------------------------------------------------------------------------- -# Loader of libCamGui - -CamGui_la_SOURCES=\ - AppCamGui.cpp - -# the library search path. -CamGui_la_LDFLAGS = $(libCamGui_la_LDFLAGS) -module -avoid-version -CamGui_la_CPPFLAGS = $(libCamGui_la_CPPFLAGS) - -CamGui_la_LIBADD = \ - $(libCamGui_la_LIBADD) \ - -lCamGui + -L../../Part/Gui \ + $(sim_ac_coin_libs) $(sim_ac_soqt_ldflags) $(sim_ac_soqt_libs) -L$(OCC_LIB) $(all_libraries) \ + -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ +libCamGui_la_CPPFLAGS = $(sim_ac_coin_cppflags) -DAppCamExport= -DAppCamGuiExport= + +libCamGui_la_LIBADD = \ + -lxerces-c \ + -l@PYTHON_LIB@ \ + -lFreeCADBase \ + -lFreeCADApp \ + -lFreeCADGui \ + -lTKernel \ + -lPartGui \ + -lCam + +#-------------------------------------------------------------------------------------- +# Loader of libCamGui + +CamGui_la_SOURCES=\ + AppCamGui.cpp + +# the library search path. +CamGui_la_LDFLAGS = $(libCamGui_la_LDFLAGS) -module -avoid-version +CamGui_la_CPPFLAGS = $(libCamGui_la_CPPFLAGS) + +CamGui_la_LIBADD = \ + $(libCamGui_la_LIBADD) \ + -lCamGui CamGui_la_DEPENDENCIES = libCamGui.la - -#-------------------------------------------------------------------------------------- - -# rule for Qt MetaObject Compiler: -moc_%.cpp: %.h + +#-------------------------------------------------------------------------------------- + +# rule for Qt MetaObject Compiler: +moc_%.cpp: %.h $(QT_MOC) $< -o $(@F) - -# rule for Qt MetaObject Compiler: -%.moc: %.h + +# rule for Qt MetaObject Compiler: +%.moc: %.h $(QT_MOC) $< -o $(@F) - + # rules for Qt User Interface Compiler: ui_%.h: %.ui $(QT_UIC) $< -o $(@F) @@ -63,14 +65,14 @@ ui_%.h: %.ui qrc_%.cpp: %.qrc $(QT_RCC) -name $(*F) $< -o $(@F) -# set the include path found by configure -AM_CXXFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(QT_CXXFLAGS) -I$(OCC_INC) $(all_includes) - - -libdir = $(prefix)/Mod/Cam - -CLEANFILES = $(BUILT_SOURCES) - -EXTRA_DIST = \ +# set the include path found by configure +AM_CXXFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(QT_CXXFLAGS) -I$(OCC_INC) $(all_includes) + + +libdir = $(prefix)/Mod/Cam + +CLEANFILES = $(BUILT_SOURCES) + +EXTRA_DIST = \ CMakeLists.txt \ - Cutting.ui + Cutting.ui diff --git a/src/Mod/Complete/Gui/Resources/Complete.qrc b/src/Mod/Complete/Gui/Resources/Complete.qrc index d7115bce7d..97769440c8 100644 --- a/src/Mod/Complete/Gui/Resources/Complete.qrc +++ b/src/Mod/Complete/Gui/Resources/Complete.qrc @@ -9,6 +9,7 @@ translations/Complete_it.qm translations/Complete_nl.qm translations/Complete_no.qm + translations/Complete_pl.qm translations/Complete_pt.qm translations/Complete_ru.qm translations/Complete_se.qm diff --git a/src/Mod/Complete/Gui/Resources/Makefile.am b/src/Mod/Complete/Gui/Resources/Makefile.am index c895368eed..6cfd345e7a 100644 --- a/src/Mod/Complete/Gui/Resources/Makefile.am +++ b/src/Mod/Complete/Gui/Resources/Makefile.am @@ -16,6 +16,7 @@ EXTRA_DIST = \ translations/Complete_it.qm \ translations/Complete_nl.qm \ translations/Complete_no.qm \ + translations/Complete_pl.qm \ translations/Complete_pt.qm \ translations/Complete_ru.qm \ translations/Complete_se.qm \ @@ -30,6 +31,7 @@ EXTRA_DIST = \ translations/Complete_it.ts \ translations/Complete_nl.ts \ translations/Complete_no.ts \ + translations/Complete_pl.ts \ translations/Complete_pt.ts \ translations/Complete_ru.ts \ translations/Complete_se.ts \ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_af.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_af.qm index 129a3fc9a7..4661e9716c 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_af.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_af.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_af.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_af.ts index ad183f4d5a..d1adc14ef2 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_af.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_af.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Teken - Ske&tch + S&ketch &Skets diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_de.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_de.qm index 83e0263a6b..11eb3fd4d0 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_de.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_de.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_de.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_de.ts index 8543422eae..8b39f34e46 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_de.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_de.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Zeichnung - Ske&tch + S&ketch Ski&zze diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_es.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_es.qm index 11eeb5138f..e0609785c1 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_es.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_es.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_es.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_es.ts index be0d669775..a4befd9feb 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_es.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_es.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing %Dibujo - Ske&tch + S&ketch Boc&eto diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_fi.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_fi.qm index 9f5dee7447..3a02f3bd99 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_fi.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_fi.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_fi.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_fi.ts index 910ed1ee36..1dfd6c849a 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_fi.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_fi.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Piirustus - Ske&tch + S&ketch Ske&tch diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_fr.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_fr.qm index 2c96f695df..0817a13e8b 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_fr.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_fr.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_fr.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_fr.ts index 4cf54ae22d..aedbd4a84f 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_fr.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_fr.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Dessin - Ske&tch + S&ketch Es&quisse diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_hr.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_hr.qm index f4e9747ea8..85bf319cd9 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_hr.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_hr.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_hr.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_hr.ts index d061d8923d..e386f67a5c 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_hr.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_hr.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Crtež - Ske&tch + S&ketch Sk&ica diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_hu.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_hu.qm index 21c0a053a8..6080e9c88d 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_hu.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_hu.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_hu.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_hu.ts index 8cee0ef4c8..3210bbb880 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_hu.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_hu.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing Rajzolás - Ske&tch + S&ketch Vázlat diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_it.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_it.qm index 625eb325cd..d4157f8fb9 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_it.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_it.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_it.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_it.ts index 48466f7e13..3f8e834252 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_it.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_it.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Disegno - Ske&tch + S&ketch S&ketch diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_ja.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_ja.qm index 8365b44eaa..4954238143 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_ja.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_ja.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_ja.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_ja.ts index 1bbd50762e..0a05b50ae5 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_ja.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_ja.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing ドローイング (&D) - Ske&tch + S&ketch スケッチ(&T) diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_nl.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_nl.qm index e80a5e9047..51d5ff4fc6 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_nl.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_nl.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_nl.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_nl.ts index 4af85c5430..c3d1b6a818 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_nl.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_nl.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Tekenen - Ske&tch + S&ketch Sche&ts diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_no.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_no.qm index de3d432d68..5dd6372503 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_no.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_no.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_no.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_no.ts index 02900feaf4..6d80d05096 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_no.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_no.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Tegning - Ske&tch + S&ketch Sk&isser diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_pl.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_pl.qm index 20ac1afe70..959ad6b126 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_pl.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_pl.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_pl.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_pl.ts index 761a193323..58b62fd97c 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_pl.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_pl.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Rysunek - Ske&tch + S&ketch Szki&c diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_pt.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_pt.qm index 34a16816c5..55f13d3b7c 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_pt.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_pt.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_pt.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_pt.ts index 90d092c663..408fba3d31 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_pt.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_pt.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Desenho - Ske&tch + S&ketch Sk&etch diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_ru.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_ru.qm index 517679124c..b0977c27cc 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_ru.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_ru.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_ru.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_ru.ts index 28d46c787c..ac8194f3cd 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_ru.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_ru.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Рисование - Ske&tch + S&ketch Эс&киз diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_se.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_se.qm index f01b401a6a..c3fc4c5445 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_se.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_se.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_se.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_se.ts index fe2bf21e66..868c35e03e 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_se.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_se.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing R&itning - Ske&tch + S&ketch S&kiss diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_uk.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_uk.qm index 6b81115345..1aba32e8e7 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_uk.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_uk.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_uk.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_uk.ts index ecac8e1834..49840b58ca 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_uk.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_uk.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing &Малювання - Ske&tch + S&ketch Ес&кіз diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_zh.qm b/src/Mod/Complete/Gui/Resources/translations/Complete_zh.qm index 8b3fc5bc23..e770a01e0f 100644 Binary files a/src/Mod/Complete/Gui/Resources/translations/Complete_zh.qm and b/src/Mod/Complete/Gui/Resources/translations/Complete_zh.qm differ diff --git a/src/Mod/Complete/Gui/Resources/translations/Complete_zh.ts b/src/Mod/Complete/Gui/Resources/translations/Complete_zh.ts index 106c42019e..26cfdf2178 100644 --- a/src/Mod/Complete/Gui/Resources/translations/Complete_zh.ts +++ b/src/Mod/Complete/Gui/Resources/translations/Complete_zh.ts @@ -32,11 +32,11 @@ Workbench - &Drawing + Dr&awing 图纸(&D) - Ske&tch + S&ketch 草绘(&T) diff --git a/src/Mod/Complete/Gui/Workbench.cpp b/src/Mod/Complete/Gui/Workbench.cpp index 45a2faa030..9b0b0fcf0f 100644 --- a/src/Mod/Complete/Gui/Workbench.cpp +++ b/src/Mod/Complete/Gui/Workbench.cpp @@ -45,12 +45,12 @@ using namespace CompleteGui; #if 0 // needed for Qt's lupdate utility - qApp->translate("Workbench", "Ske&tch"); - qApp->translate("Workbench", "&Drawing"); + qApp->translate("Workbench", "S&ketch"); + qApp->translate("Workbench", "Dr&awing"); qApp->translate("Workbench", "&Raytracing"); qApp->translate("Workbench", "&Drafting"); qApp->translate("Workbench", "Sketch based"); - qApp->translate("Workbench", "Parametric"); + qApp->translate("Workbench", "Primitives"); qApp->translate("Workbench", "Object appearence"); qApp->translate("Workbench", "Wire Tools"); // taken from TestGui.py @@ -132,7 +132,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const edit->setCommand("&Edit"); *edit << "Std_Undo" << "Std_Redo" << "Separator" << "Std_Cut" << "Std_Copy" << "Std_Paste" << "Std_DuplicateSelection" << "Separator" - << "Std_Refresh" << "Std_SelectAll" << "Std_Delete" << "Std_Placement" + << "Std_Refresh" << "Std_BoxSelection" << "Std_SelectAll" << "Std_Delete" + << "Std_Placement" << "Std_Alignment" << "Separator" << "Std_DlgPreferences"; // Standard views @@ -228,6 +229,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_ToolMesh" + << "Mesh_Segmentation" << "Mesh_VertexCurvature"; // Part **************************************************************************************************** @@ -237,7 +239,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const // submenu boolean Gui::MenuItem* para = new Gui::MenuItem(); - para->setCommand("Parametric"); + para->setCommand("Primitives"); *para << "Part_Box" << "Part_Cylinder" << "Part_Sphere" @@ -305,7 +307,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* drawing = new Gui::MenuItem(menuBar); - drawing->setCommand("&Drawing"); + drawing->setCommand("Dr&awing"); *drawing << "Drawing_Open" << "Separator" diff --git a/src/Mod/Draft/CMakeLists.txt b/src/Mod/Draft/CMakeLists.txt index 99e27d0f96..3d12885618 100644 --- a/src/Mod/Draft/CMakeLists.txt +++ b/src/Mod/Draft/CMakeLists.txt @@ -7,6 +7,8 @@ SET(Draft_SRCS DraftGui.py DraftSnap.py DraftTrackers.py + DraftVecUtils.py + DraftGeomUtils.py WorkingPlane.py importDXF.py importOCA.py @@ -22,8 +24,6 @@ SET(DraftLibs_SRCS draftlibs/dxfImportObjects.py draftlibs/dxfLibrary.py draftlibs/dxfReader.py - draftlibs/fcgeo.py - draftlibs/fcvec.py draftlibs/__init__.py ) SOURCE_GROUP("draftlibs" FILES ${DraftLibs_SRCS}) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 0a8e045f20..fc2596bebc 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -54,9 +54,9 @@ How it works / how to extend: - DraftTools.py: Contains the user tools of the Draft module (the commands from the Draft menu), and a couple of helpers such as the "Trackers" (temporary geometry used while drawing) - - draftlibs/fcvec.py: a vector math library, contains functions that are not + - DraftVecUtils.py: a vector math library, contains functions that are not implemented in the standard FreeCAD vector - - draftlibs/fcgeo.py: a library of misc functions to manipulate shapes. + - DraftGeomUtils.py: a library of misc functions to manipulate shapes. The Draft.py contains everything to create geometry in the scene. You should start there if you intend to modify something. Then, the DraftTools @@ -72,12 +72,17 @@ How it works / how to extend: ''' # import FreeCAD modules - -import FreeCAD, FreeCADGui, math, sys, os, WorkingPlane +import FreeCAD, math, sys, os, DraftVecUtils from FreeCAD import Vector -from draftlibs import fcvec from pivy import coin +if FreeCAD.GuiUp: + import FreeCADGui, WorkingPlane + gui = True +else: + print "FreeCAD Gui not present. Draft module will have some features disabled." + gui = False + #--------------------------------------------------------------------------- # General functions #--------------------------------------------------------------------------- @@ -96,12 +101,14 @@ def getParamType(param): "snapRange","gridEvery","linewidth","UiMode","modconstrain","modsnap", "modalt"]: return "int" - elif param in ["constructiongroupname","textfont","patternFile","template","maxSnapEdges"]: + elif param in ["constructiongroupname","textfont","patternFile","template","maxSnapEdges", + "snapModes"]: return "string" elif param in ["textheight","tolerance","gridSpacing"]: return "float" elif param in ["selectBaseObjects","alwaysSnap","grid","fillmode","saveonexit","maxSnap", - "SvgLinesBlack","dxfStdSize"]: + "SvgLinesBlack","dxfStdSize","showSnapBar","hideSnapBar","alwaysShowGrid", + "renderPolylineWidth","showPlaneTracker"]: return "bool" elif param in ["color","constructioncolor","snapcolor"]: return "unsigned" @@ -128,7 +135,7 @@ def setParam(param,value): elif t == "float": p.SetFloat(param,value) elif t == "bool": p.SetBool(param,value) elif t == "unsigned": p.SetUnsigned(param,value) - + def precision(): "precision(): returns the precision value from Draft user settings" return getParam("precision") @@ -160,10 +167,31 @@ def getType(obj): return "Annotation" if obj.isDerivedFrom("Mesh::Feature"): return "Mesh" + if obj.isDerivedFrom("Points::Feature"): + return "Points" if (obj.Type == "App::DocumentObjectGroup"): return "Group" return "Unknown" +def get3DView(): + "get3DView(): returns the current view if it is 3D, or the first 3D view found, or None" + v = FreeCADGui.ActiveDocument.ActiveView + if str(type(v)) == "": + return v + v = FreeCADGui.ActiveDocument.mdiViewsOfType("Gui::View3DInventor") + if v: + return v[0] + return None + +def isClone(obj,objtype): + """isClone(obj,objtype): returns True if the given object is + a clone of an object of the given type""" + if getType(obj) == "Clone": + if len(obj.Objects) == 1: + if getType(obj.Objects[0]) == objtype: + return True + return False + def getGroupNames(): "returns a list of existing groups in the document" glist = [] @@ -204,7 +232,21 @@ def shapify(obj): if not (obj.isDerivedFrom("Part::Feature")): return None if not "Shape" in obj.PropertiesList: return None shape = obj.Shape - name = getRealName(obj.Name) + if len(shape.Faces) == 1: + name = "Face" + elif len(shape.Solids) > 0: + name = "Solid" + elif len(shape.Faces) > 1: + name = "Shell" + elif len(shape.Wires) == 1: + name = "Wire" + elif len(shape.Edges) == 1: + if isinstance(shape.Edges[0].Curve,Part.Line): + name = "Line" + else: + name = "Circle" + else: + name = getRealName(obj.Name) FreeCAD.ActiveDocument.removeObject(obj.Name) newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name) newobj.Shape = shape @@ -231,52 +273,104 @@ def formatObject(target,origin=None): It also places the object in construction group if needed. ''' obrep = target.ViewObject - ui = FreeCADGui.draftToolBar - doc = FreeCAD.ActiveDocument - if ui.isConstructionMode(): - col = fcol = ui.getDefaultColor("constr") - gname = getParam("constructiongroupname") - if gname: + ui = None + if gui: + if hasattr(FreeCADGui,"draftToolBar"): + ui = FreeCADGui.draftToolBar + if ui: + doc = FreeCAD.ActiveDocument + if ui.isConstructionMode(): + col = fcol = ui.getDefaultColor("constr") + gname = getParam("constructiongroupname") + if not gname: + gname = "Construction" grp = doc.getObject(gname) - if not grp: grp = doc.addObject("App::DocumentObjectGroup",gname) + if not grp: + grp = doc.addObject("App::DocumentObjectGroup",gname) grp.addObject(target) - obrep.Transparency = 80 - else: - col = ui.getDefaultColor("ui") - fcol = ui.getDefaultColor("face") - col = (float(col[0]),float(col[1]),float(col[2]),0.0) - fcol = (float(fcol[0]),float(fcol[1]),float(fcol[2]),0.0) - lw = ui.linewidth - fs = ui.fontsize - if not origin: - if "FontSize" in obrep.PropertiesList: obrep.FontSize = fs - if "TextColor" in obrep.PropertiesList: obrep.TextColor = col - if "LineWidth" in obrep.PropertiesList: obrep.LineWidth = lw - if "PointColor" in obrep.PropertiesList: obrep.PointColor = col - if "LineColor" in obrep.PropertiesList: obrep.LineColor = col - if "ShapeColor" in obrep.PropertiesList: obrep.ShapeColor = fcol - else: - matchrep = origin.ViewObject - for p in matchrep.PropertiesList: - if not p in ["DisplayMode","BoundingBox","Proxy","RootNode"]: - if p in obrep.PropertiesList: - val = getattr(matchrep,p) - setattr(obrep,p,val) - if matchrep.DisplayMode in obrep.listDisplayModes(): - obrep.DisplayMode = matchrep.DisplayMode + obrep.Transparency = 80 + else: + col = ui.getDefaultColor("ui") + fcol = ui.getDefaultColor("face") + col = (float(col[0]),float(col[1]),float(col[2]),0.0) + fcol = (float(fcol[0]),float(fcol[1]),float(fcol[2]),0.0) + lw = ui.linewidth + fs = ui.fontsize + if not origin: + if "FontSize" in obrep.PropertiesList: obrep.FontSize = fs + if "TextColor" in obrep.PropertiesList: obrep.TextColor = col + if "LineWidth" in obrep.PropertiesList: obrep.LineWidth = lw + if "PointColor" in obrep.PropertiesList: obrep.PointColor = col + if "LineColor" in obrep.PropertiesList: obrep.LineColor = col + if "ShapeColor" in obrep.PropertiesList: obrep.ShapeColor = fcol + else: + matchrep = origin.ViewObject + for p in matchrep.PropertiesList: + if not p in ["DisplayMode","BoundingBox","Proxy","RootNode","Visibility"]: + if p in obrep.PropertiesList: + val = getattr(matchrep,p) + setattr(obrep,p,val) + if matchrep.DisplayMode in obrep.listDisplayModes(): + obrep.DisplayMode = matchrep.DisplayMode def getSelection(): "getSelection(): returns the current FreeCAD selection" - return FreeCADGui.Selection.getSelection() + if gui: + return FreeCADGui.Selection.getSelection() + return None def select(objs=None): "select(object): deselects everything and selects only the passed object or list" - FreeCADGui.Selection.clearSelection() - if objs: - if not isinstance(objs,list): - objs = [objs] - for obj in objs: - FreeCADGui.Selection.addSelection(obj) + if gui: + FreeCADGui.Selection.clearSelection() + if objs: + if not isinstance(objs,list): + objs = [objs] + for obj in objs: + FreeCADGui.Selection.addSelection(obj) + +def loadTexture(filename): + "loadTexture(filename): returns a SoSFImage from a file" + if gui: + from pivy import coin + from PyQt4 import QtGui + try: + p = QtGui.QImage(filename) + size = coin.SbVec2s(p.width(), p.height()) + buffersize = p.numBytes() + numcomponents = int (buffersize / ( size[0] * size[1] )) + + img = coin.SoSFImage() + width = size[0] + height = size[1] + bytes = "" + + for y in range(height): + #line = width*numcomponents*(height-(y)); + for x in range(width): + rgb = p.pixel(x,y) + if numcomponents == 1: + bytes = bytes + chr(QtGui.qGray( rgb )) + elif numcomponents == 2: + bytes = bytes + chr(QtGui.qGray( rgb )) + bytes = bytes + chr(QtGui.qAlpha( rgb )) + elif numcomponents == 3: + bytes = bytes + chr(QtGui.qRed( rgb )) + bytes = bytes + chr(QtGui.qGreen( rgb )) + bytes = bytes + chr(QtGui.qBlue( rgb )) + elif numcomponents == 4: + bytes = bytes + chr(QtGui.qRed( rgb )) + bytes = bytes + chr(QtGui.qGreen( rgb )) + bytes = bytes + chr(QtGui.qBlue( rgb )) + bytes = bytes + chr(QtGui.qAlpha( rgb )) + #line += numcomponents + + img.setValue(size, numcomponents, bytes) + except: + return None + else: + return img + return None def makeCircle(radius, placement=None, face=True, startangle=None, endangle=None, support=None): '''makeCircle(radius,[placement,face,startangle,endangle]) @@ -290,7 +384,6 @@ def makeCircle(radius, placement=None, face=True, startangle=None, endangle=None if placement: typecheck([(placement,FreeCAD.Placement)], "makeCircle") obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Circle") _Circle(obj) - _ViewProviderDraft(obj.ViewObject) if isinstance(radius,Part.Edge): edge = radius if isinstance(edge.Curve,Part.Circle): @@ -302,8 +395,8 @@ def makeCircle(radius, placement=None, face=True, startangle=None, endangle=None ref = placement.multVec(FreeCAD.Vector(1,0,0)) v1 = (edge.Vertexes[0].Point).sub(edge.Curve.Center) v2 = (edge.Vertexes[-1].Point).sub(edge.Curve.Center) - a1 = -math.degrees(fcvec.angle(v1,ref)) - a2 = -math.degrees(fcvec.angle(v2,ref)) + a1 = -math.degrees(DraftVecUtils.angle(v1,ref)) + a2 = -math.degrees(DraftVecUtils.angle(v2,ref)) obj.FirstAngle = a1 obj.LastAngle = a2 else: @@ -312,11 +405,13 @@ def makeCircle(radius, placement=None, face=True, startangle=None, endangle=None if startangle == -0: startangle = 0 obj.FirstAngle = startangle obj.LastAngle = endangle - if not face: obj.ViewObject.DisplayMode = "Wireframe" obj.Support = support if placement: obj.Placement = placement - formatObject(obj) - select(obj) + if gui: + _ViewProviderDraft(obj.ViewObject) + if not face: obj.ViewObject.DisplayMode = "Wireframe" + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -328,14 +423,16 @@ def makeRectangle(length, height, placement=None, face=True, support=None): if placement: typecheck([(placement,FreeCAD.Placement)], "makeRectangle") obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Rectangle") _Rectangle(obj) - _ViewProviderRectangle(obj.ViewObject) + obj.Length = length obj.Height = height obj.Support = support - if not face: obj.ViewObject.DisplayMode = "Wireframe" if placement: obj.Placement = placement - formatObject(obj) - select(obj) + if gui: + _ViewProviderRectangle(obj.ViewObject) + if not face: obj.ViewObject.DisplayMode = "Wireframe" + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -354,14 +451,25 @@ def makeDimension(p1,p2,p3=None,p4=None): ''' obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Dimension") _Dimension(obj) - _ViewProviderDimension(obj.ViewObject) + if gui: + _ViewProviderDimension(obj.ViewObject) if isinstance(p1,Vector) and isinstance(p2,Vector): obj.Start = p1 obj.End = p2 + if not p3: + p3 = p2.sub(p1) + p3.multiply(0.5) + p3 = p1.add(p3) elif isinstance(p2,int) and isinstance(p3,int): obj.Base = p1 - obj.LinkedVertices = [p2,p3] + obj.LinkedVertices = idx = [p2,p3] p3 = p4 + if not p3: + v1 = obj.Base.Shape.Vertexes[idx[0]].Point + v2 = obj.Base.Shape.Vertexes[idx[1]].Point + p3 = v2.sub(v1) + p3.multiply(0.5) + p3 = v1.add(p3) elif isinstance(p3,str): obj.Base = p1 if p3 == "radius": @@ -371,13 +479,12 @@ def makeDimension(p1,p2,p3=None,p4=None): obj.LinkedVertices = [p2,2,1] obj.ViewObject.Override = "ddim" p3 = p4 - if not p3: - p3 = p2.sub(p1) - p3.multiply(0.5) - p3 = p1.add(p3) + if not p3: + p3 = obj.Base.Shape.Edges[0].Curve.Center.add(Vector(1,0,0)) obj.Dimline = p3 - formatObject(obj) - select(obj) + if gui: + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -387,7 +494,6 @@ def makeAngularDimension(center,angles,p3): ''' obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Dimension") _AngularDimension(obj) - _ViewProviderAngularDimension(obj.ViewObject) obj.Center = center for a in range(len(angles)): if angles[a] > 2*math.pi: @@ -395,8 +501,10 @@ def makeAngularDimension(center,angles,p3): obj.FirstAngle = math.degrees(angles[1]) obj.LastAngle = math.degrees(angles[0]) obj.Dimline = p3 - formatObject(obj) - select(obj) + if gui: + _ViewProviderAngularDimension(obj.ViewObject) + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -406,27 +514,32 @@ def makeWire(pointslist,closed=False,placement=None,face=True,support=None): and last points are identical, the wire is closed. If face is true (and wire is closed), the wire will appear filled. Instead of a pointslist, you can also pass a Part Wire.''' - from draftlibs import fcgeo + import DraftGeomUtils, Part if not isinstance(pointslist,list): + e = pointslist.Wires[0].Edges + pointslist = Part.Wire(DraftGeomUtils.sortEdges(e)) nlist = [] for v in pointslist.Vertexes: nlist.append(v.Point) - if fcgeo.isReallyClosed(pointslist): - nlist.append(pointslist.Vertexes[0].Point) + if DraftGeomUtils.isReallyClosed(pointslist): + closed = True pointslist = nlist + print pointslist + print closed if placement: typecheck([(placement,FreeCAD.Placement)], "makeWire") if len(pointslist) == 2: fname = "Line" - else: fname = "Wire" + else: fname = "DWire" obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",fname) _Wire(obj) - _ViewProviderWire(obj.ViewObject) obj.Points = pointslist obj.Closed = closed obj.Support = support - if not face: obj.ViewObject.DisplayMode = "Wireframe" if placement: obj.Placement = placement - formatObject(obj) - select(obj) + if gui: + _ViewProviderWire(obj.ViewObject) + if not face: obj.ViewObject.DisplayMode = "Wireframe" + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -440,18 +553,19 @@ def makePolygon(nfaces,radius=1,inscribed=True,placement=None,face=True,support= if nfaces < 3: return None obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Polygon") _Polygon(obj) - _ViewProviderDraft(obj.ViewObject) obj.FacesNumber = nfaces obj.Radius = radius if inscribed: obj.DrawMode = "inscribed" else: obj.DrawMode = "circumscribed" - if not face: obj.ViewObject.DisplayMode = "Wireframe" obj.Support = support if placement: obj.Placement = placement - formatObject(obj) - select(obj) + if gui: + _ViewProviderDraft(obj.ViewObject) + if not face: obj.ViewObject.DisplayMode = "Wireframe" + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -476,14 +590,15 @@ def makeBSpline(pointslist,closed=False,placement=None,face=True,support=None): else: fname = "BSpline" obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython",fname) _BSpline(obj) - _ViewProviderBSpline(obj.ViewObject) obj.Points = pointslist obj.Closed = closed obj.Support = support - if not face: obj.ViewObject.DisplayMode = "Wireframe" if placement: obj.Placement = placement - formatObject(obj) - select(obj) + if gui: + _ViewProviderBSpline(obj.ViewObject) + if not face: obj.ViewObject.DisplayMode = "Wireframe" + formatObject(obj) + select(obj) FreeCAD.ActiveDocument.recompute() return obj @@ -515,51 +630,68 @@ def makeCopy(obj,force=None,reparent=False): if (getType(obj) == "Rectangle") or (force == "Rectangle"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _Rectangle(newobj) - _ViewProviderRectangle(newobj.ViewObject) + if gui: + _ViewProviderRectangle(newobj.ViewObject) elif (getType(obj) == "Dimension") or (force == "Dimension"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _Dimension(newobj) - _ViewProviderDimension(newobj.ViewObject) + if gui: + _ViewProviderDimension(newobj.ViewObject) elif (getType(obj) == "Wire") or (force == "Wire"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _Wire(newobj) - _ViewProviderWire(newobj.ViewObject) + if gui: + _ViewProviderWire(newobj.ViewObject) elif (getType(obj) == "Circle") or (force == "Circle"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _Circle(newobj) - _ViewProviderDraft(newobj.ViewObject) + if gui: + _ViewProviderDraft(newobj.ViewObject) elif (getType(obj) == "Polygon") or (force == "Polygon"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _Polygon(newobj) - _ViewProviderPolygon(newobj.ViewObject) + if gui: + _ViewProviderPolygon(newobj.ViewObject) elif (getType(obj) == "BSpline") or (force == "BSpline"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _BSpline(newobj) - _ViewProviderBSpline(newobj.ViewObject) + if gui: + _ViewProviderBSpline(newobj.ViewObject) elif (getType(obj) == "Block") or (force == "BSpline"): newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) _Block(newobj) - _ViewProviderDraftPart(newobj.ViewObject) + if gui: + _ViewProviderDraftPart(newobj.ViewObject) elif (getType(obj) == "Structure") or (force == "Structure"): import ArchStructure newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) ArchStructure._Structure(newobj) - ArchStructure._ViewProviderStructure(newobj.ViewObject) + if gui: + ArchStructure._ViewProviderStructure(newobj.ViewObject) elif (getType(obj) == "Wall") or (force == "Wall"): import ArchWall newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) ArchWall._Wall(newobj) - ArchWall._ViewProviderWall(newobj.ViewObject) + if gui: + ArchWall._ViewProviderWall(newobj.ViewObject) elif (getType(obj) == "Window") or (force == "Window"): import ArchWindow newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) ArchWindow._Window(newobj) - Archwindow._ViewProviderWindow(newobj.ViewObject) + if gui: + Archwindow._ViewProviderWindow(newobj.ViewObject) elif (getType(obj) == "Cell") or (force == "Cell"): import ArchCell newobj = FreeCAD.ActiveDocument.addObject(obj.Type,getRealName(obj.Name)) ArchCell._Cell(newobj) - ArchCell._ViewProviderCell(newobj.ViewObject) + if gui: + ArchCell._ViewProviderCell(newobj.ViewObject) + elif (getType(obj) == "Sketch") or (force == "Sketch"): + newobj = FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject",getRealName(obj.Name)) + for geo in obj.Geometries: + newobj.addGeometry(geo) + for con in obj.constraints: + newobj.addConstraint(con) elif obj.isDerivedFrom("Part::Feature"): newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",getRealName(obj.Name)) newobj.Shape = obj.Shape @@ -587,11 +719,12 @@ def makeBlock(objectslist): '''makeBlock(objectslist): Creates a Draft Block from the given objects''' obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Block") _Block(obj) - _ViewProviderDraftPart(obj.ViewObject) obj.Components = objectslist - for o in objectslist: - o.ViewObject.Visibility = False - select(obj) + if gui: + _ViewProviderDraftPart(obj.ViewObject) + for o in objectslist: + o.ViewObject.Visibility = False + select(obj) return obj def makeArray(baseobject,arg1,arg2,arg3,arg4=None): @@ -605,7 +738,6 @@ def makeArray(baseobject,arg1,arg2,arg3,arg4=None): The result is a parametric Draft Array.''' obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Array") _Array(obj) - _ViewProviderDraftPart(obj.ViewObject) obj.Base = baseobject if arg4: obj.ArrayType = "ortho" @@ -617,9 +749,11 @@ def makeArray(baseobject,arg1,arg2,arg3,arg4=None): obj.ArrayType = "polar" obj.Center = arg1 obj.Angle = arg2 - obj.NumberPolar = arg3 - baseobject.ViewObject.hide() - select(obj) + obj.NumberPolar = arg3 + if gui: + _ViewProviderDraftPart(obj.ViewObject) + baseobject.ViewObject.hide() + select(obj) return obj def extrude(obj,vector): @@ -639,18 +773,33 @@ def fuse(object1,object2): the union of the 2 given objects. If the objects are coplanar, a special Draft Wire is used, otherwise we use a standard Part fuse.''' - from draftlibs import fcgeo - if fcgeo.isCoplanar(object1.Shape.fuse(object2.Shape).Faces): + import DraftGeomUtils, Part + # testing if we have holes: + holes = False + fshape = object1.Shape.fuse(object2.Shape) + fshape = fshape.removeSplitter() + for f in fshape.Faces: + if len(f.Wires) > 1: + holes = True + if DraftGeomUtils.isCoplanar(object1.Shape.fuse(object2.Shape).Faces) and not holes: obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Fusion") _Wire(obj) - _ViewProviderWire(obj.ViewObject) + if gui: + _ViewProviderWire(obj.ViewObject) + obj.Base = object1 + obj.Tool = object2 + elif holes: + # temporary hack, since Part::Fuse objects don't remove splitters + obj = FreeCAD.ActiveDocument.addObject("Part::Feature","Fusion") + obj.Shape = fshape else: obj = FreeCAD.ActiveDocument.addObject("Part::Fuse","Fusion") - obj.Base = object1 - obj.Tool = object2 - object1.ViewObject.Visibility = False - object2.ViewObject.Visibility = False - formatObject(obj,object1) + obj.Base = object1 + obj.Tool = object2 + if gui: + object1.ViewObject.Visibility = False + object2.ViewObject.Visibility = False + formatObject(obj,object1) FreeCAD.ActiveDocument.recompute() return obj @@ -694,7 +843,8 @@ def move(objectslist,vector,copy=False): if copy: newobj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",getRealName(obj.Name)) _Dimension(newobj) - _ViewProviderDimension(newobj.ViewObject) + if gui: + _ViewProviderDimension(newobj.ViewObject) else: newobj = obj newobj.Start = obj.Start.add(vector) @@ -727,12 +877,12 @@ def array(objectslist,arg1,arg2,arg3,arg4=None): typecheck([(xvector,Vector), (yvector,Vector), (xnum,int), (ynum,int)], "rectArray") if not isinstance(objectslist,list): objectslist = [objectslist] for xcount in range(xnum): - currentxvector=fcvec.scale(xvector,xcount) + currentxvector=DraftVecUtils.scale(xvector,xcount) if not xcount==0: move(objectslist,currentxvector,True) for ycount in range(ynum): currentxvector=FreeCAD.Base.Vector(currentxvector) - currentyvector=currentxvector.add(fcvec.scale(yvector,ycount)) + currentyvector=currentxvector.add(DraftVecUtils.scale(yvector,ycount)) if not ycount==0: move(objectslist,currentyvector,True) def polarArray(objectslist,center,angle,num): @@ -766,7 +916,7 @@ def rotate(objectslist,angle,center=Vector(0,0,0),axis=Vector(0,0,1),copy=False) newobj = obj if (obj.isDerivedFrom("Part::Feature")): shape = obj.Shape.copy() - shape.rotate(fcvec.tup(center), fcvec.tup(axis), angle) + shape.rotate(DraftVecUtils.tup(center), DraftVecUtils.tup(axis), angle) newobj.Shape = shape elif (obj.isDerivedFrom("App::Annotation")): if axis.normalize() == Vector(1,0,0): @@ -787,7 +937,7 @@ def rotate(objectslist,angle,center=Vector(0,0,0),axis=Vector(0,0,1),copy=False) elif hasattr(obj,"Placement"): shape = Part.Shape() shape.Placement = obj.Placement - shape.rotate(fcvec.tup(center), fcvec.tup(axis), angle) + shape.rotate(DraftVecUtils.tup(center), DraftVecUtils.tup(axis), angle) newobj.Placement = shape.Placement if copy: formatObject(newobj,obj) @@ -820,7 +970,7 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy sh = sh.transformGeometry(m) corr = Vector(center.x,center.y,center.z) corr.scale(delta.x,delta.y,delta.z) - corr = fcvec.neg(corr.sub(center)) + corr = DraftVecUtils.neg(corr.sub(center)) sh.translate(corr) if getType(obj) == "Rectangle": p = [] @@ -830,8 +980,8 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy diag = p[2].sub(p[0]) bb = p[1].sub(p[0]) bh = p[3].sub(p[0]) - nb = fcvec.project(diag,bb) - nh = fcvec.project(diag,bh) + nb = DraftVecUtils.project(diag,bb) + nh = DraftVecUtils.project(diag,bh) if obj.Length < 0: l = -nb.Length else: l = nb.Length if obj.Height < 0: h = -nh.Length @@ -860,20 +1010,21 @@ def scale(objectslist,delta=Vector(1,1,1),center=Vector(0,0,0),copy=False,legacy else: obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Scale") _Clone(obj) - _ViewProviderDraftPart(obj.ViewObject) obj.Objects = objectslist obj.Scale = delta corr = Vector(center.x,center.y,center.z) corr.scale(delta.x,delta.y,delta.z) - corr = fcvec.neg(corr.sub(center)) + corr = DraftVecUtils.neg(corr.sub(center)) p = obj.Placement p.move(corr) obj.Placement = p if not copy: for o in objectslist: o.ViewObject.hide() - formatObject(obj,objectslist[-1]) - select(obj) + if gui: + _ViewProviderDraftPart(obj.ViewObject) + formatObject(obj,objectslist[-1]) + select(obj) return obj def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): @@ -884,8 +1035,7 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): and the offsetted wires will be bound by their endpoints, forming a face if sym is True, bind must be true too, and the offset is made on both sides, the total width being the given delta length.''' - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils def getRect(p,obj): "returns length,heigh,placement" @@ -894,8 +1044,8 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): diag = p[2].sub(p[0]) bb = p[1].sub(p[0]) bh = p[3].sub(p[0]) - nb = fcvec.project(diag,bb) - nh = fcvec.project(diag,bh) + nb = DraftVecUtils.project(diag,bb) + nh = DraftVecUtils.project(diag,bh) if obj.Length < 0: l = -nb.Length else: l = nb.Length if obj.Height < 0: h = -nh.Length @@ -905,7 +1055,7 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): def getRadius(obj,delta): "returns a new radius for a regular polygon" an = math.pi/obj.FacesNumber - nr = fcvec.rotate(delta,-an) + nr = DraftVecUtils.rotate(delta,-an) nr.multiply(1/math.cos(an)) nr = obj.Shape.Vertexes[0].Point.add(nr) nr = nr.sub(obj.Placement.Base) @@ -922,18 +1072,18 @@ def offset(obj,delta,copy=False,bind=False,sym=False,occ=False): else: if sym: d1 = delta.multiply(0.5) - d2 = fcvec.neg(d1) - n1 = fcgeo.offsetWire(obj.Shape,d1) - n2 = fcgeo.offsetWire(obj.Shape,d2) + d2 = DraftVecUtils.neg(d1) + n1 = DraftGeomUtils.offsetWire(obj.Shape,d1) + n2 = DraftGeomUtils.offsetWire(obj.Shape,d2) else: - newwire = fcgeo.offsetWire(obj.Shape,delta) - p = fcgeo.getVerts(newwire) + newwire = DraftGeomUtils.offsetWire(obj.Shape,delta) + p = DraftGeomUtils.getVerts(newwire) if occ: newobj = FreeCAD.ActiveDocument.addObject("Part::Feature","Offset") - newobj.Shape = fcgeo.offsetWire(obj.Shape,delta,occ=True) + newobj.Shape = DraftGeomUtils.offsetWire(obj.Shape,delta,occ=True) formatObject(newobj,obj) elif bind: - if not fcgeo.isReallyClosed(obj.Shape): + if not DraftGeomUtils.isReallyClosed(obj.Shape): if sym: s1 = n1 s2 = n2 @@ -1008,8 +1158,7 @@ def draftify(objectslist,makeblock=False): '''draftify(objectslist,[makeblock]): turns each object of the given list (objectslist can also be a single object) into a Draft parametric wire. If makeblock is True, multiple objects will be grouped in a block''' - from draftlibs import fcgeo - import Part + import DraftGeomUtils, Part if not isinstance(objectslist,list): objectslist = [objectslist] @@ -1017,7 +1166,7 @@ def draftify(objectslist,makeblock=False): for obj in objectslist: if obj.isDerivedFrom('Part::Feature'): for w in obj.Shape.Wires: - if fcgeo.hasCurves(w): + if DraftGeomUtils.hasCurves(w): if (len(w.Edges) == 1) and isinstance(w.Edges[0].Curve,Part.Circle): nobj = makeCircle(w.Edges[0]) else: @@ -1040,26 +1189,37 @@ def draftify(objectslist,makeblock=False): return newobjlist[0] return newobjlist -def getSVG(obj,modifier=100,textmodifier=100,linestyle="continuous",fillstyle="shape color",direction=None): - '''getSVG(object,[modifier],[textmodifier],[linestyle],[fillstyle],[direction]): - returns a string containing a SVG representation of the given object. the modifier attribute - specifies a scale factor for linewidths in %, and textmodifier specifies - a scale factor for texts, in % (both default = 100). You can also supply - an arbitrary projection vector.''' - import Part - from draftlibs import fcgeo +def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None): + '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction]): + returns a string containing a SVG representation of the given object, + with the given linewidth and fontsize (used if the given object contains + any text). You can also supply an arbitrary projection vector. the + scale parameter allows to scale linewidths down, so they are resolution-independant.''' + import Part, DraftGeomUtils svg = "" - tmod = ((textmodifier-100)/2)+100 - if tmod == 0: tmod = 0.01 - modifier = 200-modifier - if modifier == 0: modifier = 0.01 - pmod = (200-textmodifier)/20 - if pmod == 0: pmod = 0.01 + linewidth = linewidth/scale + fontsize = (fontsize/scale)/2 plane = None if direction: - if direction != Vector(0,0,0): - plane = WorkingPlane.plane() - plane.alignToPointAndAxis(Vector(0,0,0),fcvec.neg(direction),0) + if isinstance(direction,FreeCAD.Vector): + if direction != Vector(0,0,0): + plane = WorkingPlane.plane() + plane.alignToPointAndAxis(Vector(0,0,0),DraftVecUtils.neg(direction),0) + elif isinstance(direction,WorkingPlane.plane): + plane = direction + + def getLineStyle(obj): + "returns a linestyle pattern for a given object" + if obj.ViewObject: + if hasattr(obj.ViewObject,"DrawStyle"): + ds = obj.ViewObject.DrawStyle + if ds == "Dashed": + return "0.09,0.05" + elif ds == "Dashdot": + return "0.09,0.05,0.02,0.05" + elif ds == "Dotted": + return "0.02,0.02" + return "none" def getrgb(color): "getRGB(color): returns a rgb value #000000 from a freecad color" @@ -1075,10 +1235,10 @@ def getSVG(obj,modifier=100,textmodifier=100,linestyle="continuous",fillstyle="s def getProj(vec): if not plane: return vec - nx = fcvec.project(vec,plane.u) + nx = DraftVecUtils.project(vec,plane.u) lx = nx.Length if abs(nx.getAngle(plane.u)) > 0.1: lx = -lx - ny = fcvec.project(vec,plane.v) + ny = DraftVecUtils.project(vec,plane.v) ly = ny.Length if abs(ny.getAngle(plane.v)) > 0.1: ly = -ly return Vector(lx,ly,0) @@ -1090,7 +1250,7 @@ def getSVG(obj,modifier=100,textmodifier=100,linestyle="continuous",fillstyle="s def getPath(edges): svg ='\n' + #svg +='scale('+str(tmod/2000)+','+str(-tmod/2000)+')' + svg += 'scale(1,-1) ' + svg += '">\n' for l in obj.LabelText: svg += ''+l+'\n' svg += '\n' + elif getType(obj) == "Axis": + "returns the SVG representation of an Arch Axis system" + color = getrgb(obj.ViewObject.LineColor) + lorig = getLineStyle(obj) + name = obj.Name + stroke = getrgb(obj.ViewObject.LineColor) + fill = 'none' + invpl = obj.Placement.inverse() + n = 0 + for e in obj.Shape.Edges: + lstyle = lorig + svg += getPath([e]) + p1 = invpl.multVec(e.Vertexes[0].Point) + p2 = invpl.multVec(e.Vertexes[1].Point) + dv = p2.sub(p1) + dv.normalize() + rad = obj.ViewObject.BubbleSize + center = p2.add(dv.scale(rad,rad,rad)) + lstyle = "none" + svg += getCircle(Part.makeCircle(rad,center)) + svg += '\n' + svg += '\n' + n += 1 + elif obj.isDerivedFrom('Part::Feature'): if obj.Shape.isNull(): return '' color = getrgb(obj.ViewObject.LineColor) @@ -1239,21 +1433,12 @@ def getSVG(obj,modifier=100,textmodifier=100,linestyle="continuous",fillstyle="s svg += getPattern(fillstyle) else: fill = 'none' - # setting linetype - if linestyle == "dashed": - lstyle = "0.09,0.05" - elif linestyle == "dashdotted": - lstyle = "0.09,0.05,0.02,0.05" - elif linestyle == "dotted": - lstyle = "0.02,0.02" - else: - lstyle = "none" + lstyle = getLineStyle(obj) name = obj.Name if obj.ViewObject.DisplayMode == "Shaded": stroke = "none" else: stroke = getrgb(obj.ViewObject.LineColor) - width = obj.ViewObject.LineWidth/modifier if len(obj.Shape.Vertexes) > 1: wiredEdges = [] @@ -1267,7 +1452,7 @@ def getSVG(obj,modifier=100,textmodifier=100,linestyle="continuous",fillstyle="s wiredEdges.extend(w.Edges) if len(wiredEdges) != len(obj.Shape.Edges): for e in obj.Shape.Edges: - if (fcgeo.findEdge(e,wiredEdges) == None): + if (DraftGeomUtils.findEdge(e,wiredEdges) == None): svg += getPath([e]) else: svg = getCircle(obj.Shape.Edges[0]) @@ -1297,7 +1482,8 @@ def makeShape2DView(baseobj,projectionVector=None): ''' obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython","Shape2DView") _Shape2DView(obj) - _ViewProviderDraft(obj.ViewObject) + if gui: + _ViewProviderDraft(obj.ViewObject) obj.Base = baseobj if projectionVector: obj.Projection = projectionVector @@ -1310,8 +1496,7 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"): constraints will be automatically added to wire nodes, rectangles and circles. If addTo is an existing sketch, geometry will be added to it instead of creating a new one.''' - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils from Sketcher import Constraint StartPoint = 1 @@ -1338,21 +1523,22 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"): # TODO add Radius constraits ok = True elif tp == "Rectangle": - for edge in obj.Shape.Edges: - nobj.addGeometry(edge.Curve) - if autoconstraints: - last = nobj.GeometryCount - 1 - segs = [last-3,last-2,last-1,last] - if obj.Placement.Rotation.Q == (0,0,0,1): - nobj.addConstraint(Constraint("Coincident",last-3,EndPoint,last-2,StartPoint)) - nobj.addConstraint(Constraint("Coincident",last-2,EndPoint,last-1,StartPoint)) - nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,last,StartPoint)) - nobj.addConstraint(Constraint("Coincident",last,EndPoint,last-3,StartPoint)) - nobj.addConstraint(Constraint("Horizontal",last-3)) - nobj.addConstraint(Constraint("Vertical",last-2)) - nobj.addConstraint(Constraint("Horizontal",last-1)) - nobj.addConstraint(Constraint("Vertical",last)) - ok = True + if obj.FilletRadius == 0: + for edge in obj.Shape.Edges: + nobj.addGeometry(edge.Curve) + if autoconstraints: + last = nobj.GeometryCount - 1 + segs = [last-3,last-2,last-1,last] + if obj.Placement.Rotation.Q == (0,0,0,1): + nobj.addConstraint(Constraint("Coincident",last-3,EndPoint,last-2,StartPoint)) + nobj.addConstraint(Constraint("Coincident",last-2,EndPoint,last-1,StartPoint)) + nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,last,StartPoint)) + nobj.addConstraint(Constraint("Coincident",last,EndPoint,last-3,StartPoint)) + nobj.addConstraint(Constraint("Horizontal",last-3)) + nobj.addConstraint(Constraint("Vertical",last-2)) + nobj.addConstraint(Constraint("Horizontal",last-1)) + nobj.addConstraint(Constraint("Vertical",last)) + ok = True elif tp in ["Wire","Polygon"]: closed = False if tp == "Polygon": @@ -1366,39 +1552,39 @@ def makeSketch(objectslist,autoconstraints=False,addTo=None,name="Sketch"): segs = range(last-len(obj.Shape.Edges),last-1) for seg in segs: nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint)) - if fcgeo.isAligned(nobj.Geometry[seg],"x"): + if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"): nobj.addConstraint(Constraint("Vertical",seg)) - elif fcgeo.isAligned(nobj.Geometry[seg],"y"): + elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"): nobj.addConstraint(Constraint("Horizontal",seg)) if closed: nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint)) ok = True - elif obj.isDerivedFrom("Part::Feature"): - if fcgeo.hasOnlyWires(obj.Shape): + if (not ok) and obj.isDerivedFrom("Part::Feature"): + if DraftGeomUtils.hasOnlyWires(obj.Shape): for w in obj.Shape.Wires: - for edge in fcgeo.sortEdges(w.Edges): - g = fcgeo.geom(edge) + for edge in DraftGeomUtils.sortEdges(w.Edges): + g = DraftGeomUtils.geom(edge) if g: - nobj.addGeometry(g) + nobj.addGeometry(g) if autoconstraints: last = nobj.GeometryCount segs = range(last-len(w.Edges),last-1) for seg in segs: nobj.addConstraint(Constraint("Coincident",seg,EndPoint,seg+1,StartPoint)) - if fcgeo.isAligned(nobj.Geometry[seg],"x"): + if DraftGeomUtils.isAligned(nobj.Geometry[seg],"x"): nobj.addConstraint(Constraint("Vertical",seg)) - elif fcgeo.isAligned(nobj.Geometry[seg],"y"): + elif DraftGeomUtils.isAligned(nobj.Geometry[seg],"y"): nobj.addConstraint(Constraint("Horizontal",seg)) if w.isClosed: nobj.addConstraint(Constraint("Coincident",last-1,EndPoint,segs[0],StartPoint)) else: for edge in obj.Shape.Edges: - nobj.addGeometry(fcgeo.geom(edge)) + nobj.addGeometry(DraftGeomUtils.geom(edge)) if autoconstraints: last = nobj.GeometryCount - 1 - if fcgeo.isAligned(nobj.Geometry[last],"x"): + if DraftGeomUtils.isAligned(nobj.Geometry[last],"x"): nobj.addConstraint(Constraint("Vertical",last)) - elif fcgeo.isAligned(nobj.Geometry[last],"y"): + elif DraftGeomUtils.isAligned(nobj.Geometry[last],"y"): nobj.addConstraint(Constraint("Horizontal",last)) ok = True if ok: @@ -1417,17 +1603,18 @@ def makePoint(X=0, Y=0, Z=0,color=None,name = "Point", point_size= 5): p1.X = 1 #move it in x p1.ViewObject.PointColor =(0.0,0.0,1.0) #change the color-make sure values are floats ''' - if not color: - color = FreeCADGui.draftToolBar.getDefaultColor('ui') obj=FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) _Point(obj,X,Y,Z) - _ViewProviderPoint(obj.ViewObject) obj.X = X obj.Y = Y obj.Z = Z - obj.ViewObject.PointColor = (float(color[0]), float(color[1]), float(color[2])) - obj.ViewObject.PointSize = point_size - obj.ViewObject.Visibility = True + if gui: + _ViewProviderPoint(obj.ViewObject) + if not color: + color = FreeCADGui.draftToolBar.getDefaultColor('ui') + obj.ViewObject.PointColor = (float(color[0]), float(color[1]), float(color[2])) + obj.ViewObject.PointSize = point_size + obj.ViewObject.Visibility = True FreeCAD.ActiveDocument.recompute() return obj @@ -1439,8 +1626,11 @@ def clone(obj,delta=None): if not isinstance(obj,list): obj = [obj] cl = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Clone") + cl.Label = "Clone of " + obj[0].Label _Clone(cl) - _ViewProviderDraftPart(cl.ViewObject) + if gui: + _ViewProviderClone(cl.ViewObject) + formatObject(cl,obj[0]) cl.Objects = obj if delta: cl.Placement.move(delta) @@ -1506,8 +1696,6 @@ class _ViewProviderDraft: def __init__(self, obj): obj.Proxy = self - obj.addProperty("App::PropertyEnumeration","DrawStyle","Base", - "The line style of this object") self.Object = obj.Object def attach(self, obj): @@ -1598,52 +1786,54 @@ class _ViewProviderDimension: obj.Override = '' def calcGeom(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils p1 = obj.Start p4 = obj.End base = Part.Line(p1,p4).toShape() - proj = fcgeo.findDistance(obj.Dimline,base) + proj = DraftGeomUtils.findDistance(obj.Dimline,base) if not proj: p2 = p1 p3 = p4 else: - p2 = p1.add(fcvec.neg(proj)) - p3 = p4.add(fcvec.neg(proj)) + p2 = p1.add(DraftVecUtils.neg(proj)) + p3 = p4.add(DraftVecUtils.neg(proj)) dmax = obj.ViewObject.ExtLines if dmax and (proj.Length > dmax): - p1 = p2.add(fcvec.scaleTo(proj,dmax)) - p4 = p3.add(fcvec.scaleTo(proj,dmax)) - midpoint = p2.add(fcvec.scale(p3.sub(p2),0.5)) + p1 = p2.add(DraftVecUtils.scaleTo(proj,dmax)) + p4 = p3.add(DraftVecUtils.scaleTo(proj,dmax)) + midpoint = p2.add(DraftVecUtils.scale(p3.sub(p2),0.5)) if not proj: - ed = fcgeo.vec(base) + ed = DraftGeomUtils.vec(base) proj = ed.cross(Vector(0,0,1)) if not proj: norm = Vector(0,0,1) - else: norm = fcvec.neg(p3.sub(p2).cross(proj)) - norm.normalize() - va = FreeCADGui.ActiveDocument.ActiveView.getViewDirection() + else: norm = DraftVecUtils.neg(p3.sub(p2).cross(proj)) + if not DraftVecUtils.isNull(norm): + norm.normalize() + va = get3DView().getViewDirection() if va.getAngle(norm) < math.pi/2: - norm = fcvec.neg(norm) + norm = DraftVecUtils.neg(norm) u = p3.sub(p2) u.normalize() - c = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() + c = get3DView().getCameraNode() r = c.orientation.getValue() ru = Vector(r.multVec(coin.SbVec3f(1,0,0)).getValue()) - if ru.getAngle(u) > math.pi/2: u = fcvec.neg(u) + if ru.getAngle(u) > math.pi/2: u = DraftVecUtils.neg(u) v = norm.cross(u) - offset = fcvec.scaleTo(v,obj.ViewObject.FontSize*.2) + offset = DraftVecUtils.scaleTo(v,obj.ViewObject.FontSize*.2) if obj.ViewObject: if hasattr(obj.ViewObject,"DisplayMode"): if obj.ViewObject.DisplayMode == "3D": - offset = fcvec.neg(offset) - if hasattr(obj.ViewObject,"TextPosition"): - if obj.ViewObject.TextPosition == Vector(0,0,0): - tbase = midpoint.add(offset) + offset = DraftVecUtils.neg(offset) + if hasattr(obj.ViewObject,"TextPosition"): + if obj.ViewObject.TextPosition == Vector(0,0,0): + tbase = midpoint.add(offset) + else: + tbase = obj.ViewObject.TextPosition else: - tbase = obj.ViewObject.TextPosition + tbase = midpoint.add(offset) else: - tbase = midpoint.add(offset) - rot = FreeCAD.Placement(fcvec.getPlaneRotation(u,v,norm)).Rotation.Q + tbase = midpoint + rot = FreeCAD.Placement(DraftVecUtils.getPlaneRotation(u,v,norm)).Rotation.Q return p1,p2,p3,p4,tbase,norm,rot def attach(self, obj): @@ -1661,7 +1851,7 @@ class _ViewProviderDimension: self.text.string = self.text3d.string = '' self.textpos = coin.SoTransform() self.textpos.translation.setValue([tbase.x,tbase.y,tbase.z]) - tm = fcvec.getPlaneRotation(p3.sub(p2),norm) + tm = DraftVecUtils.getPlaneRotation(p3.sub(p2),norm) rm = coin.SbRotation() self.textpos.rotation = rm label = coin.SoSeparator() @@ -1713,6 +1903,10 @@ class _ViewProviderDimension: self.onChanged(obj,"FontName") def updateData(self, obj, prop): + try: + dm = obj.ViewObject.DisplayMode + except: + dm = "2D" text = None if obj.Base and obj.LinkedVertices: if "Shape" in obj.Base.PropertiesList: @@ -1720,11 +1914,11 @@ class _ViewProviderDimension: # arc linked dimension e = obj.Base.Shape.Edges[obj.LinkedVertices[0]] c = e.Curve.Center - bray = fcvec.scaleTo(obj.Dimline.sub(c),e.Curve.Radius) + bray = DraftVecUtils.scaleTo(obj.Dimline.sub(c),e.Curve.Radius) if obj.LinkedVertices[1] == 1: v1 = c else: - v1 = c.add(fcvec.neg(bray)) + v1 = c.add(DraftVecUtils.neg(bray)) v2 = c.add(bray) else: # linear linked dimension @@ -1742,31 +1936,33 @@ class _ViewProviderDimension: text = text.replace("dim",dtext) else: text = dtext - self.text.string = self.text3d.string = text - self.textpos.rotation = coin.SbRotation(rot[0],rot[1],rot[2],rot[3]) - self.textpos.translation.setValue([tbase.x,tbase.y,tbase.z]) - if obj.ViewObject.DisplayMode == "2D": - self.coords.point.setValues([[p1.x,p1.y,p1.z], - [p2.x,p2.y,p2.z], - [p3.x,p3.y,p3.z], - [p4.x,p4.y,p4.z]]) - self.line.numVertices.setValues([4]) - else: - ts = (len(text)*obj.ViewObject.FontSize)/4 - rm = ((p3.sub(p2)).Length/2)-ts - p2a = p2.add(fcvec.scaleTo(p3.sub(p2),rm)) - p2b = p3.add(fcvec.scaleTo(p2.sub(p3),rm)) - self.coords.point.setValues([[p1.x,p1.y,p1.z], - [p2.x,p2.y,p2.z], - [p2a.x,p2a.y,p2a.z], - [p2b.x,p2b.y,p2b.z], - [p3.x,p3.y,p3.z], - [p4.x,p4.y,p4.z]]) - self.line.numVertices.setValues([3,3]) - self.coord1.point.setValue((p2.x,p2.y,p2.z)) - self.coord2.point.setValue((p3.x,p3.y,p3.z)) + if hasattr(self,"text"): + self.text.string = self.text3d.string = text + self.textpos.rotation = coin.SbRotation(rot[0],rot[1],rot[2],rot[3]) + self.textpos.translation.setValue([tbase.x,tbase.y,tbase.z]) + if dm == "2D": + self.coords.point.setValues([[p1.x,p1.y,p1.z], + [p2.x,p2.y,p2.z], + [p3.x,p3.y,p3.z], + [p4.x,p4.y,p4.z]]) + self.line.numVertices.setValues([4]) + else: + ts = (len(text)*obj.ViewObject.FontSize)/4 + rm = ((p3.sub(p2)).Length/2)-ts + p2a = p2.add(DraftVecUtils.scaleTo(p3.sub(p2),rm)) + p2b = p3.add(DraftVecUtils.scaleTo(p2.sub(p3),rm)) + self.coords.point.setValues([[p1.x,p1.y,p1.z], + [p2.x,p2.y,p2.z], + [p2a.x,p2a.y,p2a.z], + [p2b.x,p2b.y,p2b.z], + [p3.x,p3.y,p3.z], + [p4.x,p4.y,p4.z]]) + self.line.numVertices.setValues([3,3]) + self.coord1.point.setValue((p2.x,p2.y,p2.z)) + self.coord2.point.setValue((p3.x,p3.y,p3.z)) def onChanged(self, vp, prop): + self.Object = vp.Object if prop == "FontSize": self.font.size = vp.FontSize self.font3d.size = vp.FontSize*100 @@ -1778,15 +1974,20 @@ class _ViewProviderDimension: elif prop == "LineWidth": self.drawstyle.lineWidth = vp.LineWidth else: + self.drawstyle.lineWidth = vp.LineWidth self.updateData(vp.Object, None) def getDisplayModes(self,obj): - modes=[] - modes.extend(["2D","3D"]) - return modes + return ["2D","3D"] def getDefaultDisplayMode(self): - return "2D" + if hasattr(self,"defaultmode"): + return self.defaultmode + else: + return "2D" + + def setDisplayMode(self,mode): + return mode def getIcon(self): if self.Object.Base: @@ -1845,10 +2046,12 @@ class _ViewProviderDimension: """ def __getstate__(self): - return None + return self.Object.ViewObject.DisplayMode def __setstate__(self,state): - return None + if state: + self.defaultmode = state + self.setDisplayMode(state) class _AngularDimension: "The AngularDimension object" @@ -1953,15 +2156,14 @@ class _ViewProviderAngularDimension: self.onChanged(vobj,"FontName") def calcGeom(self,obj): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils rad = (obj.Dimline.sub(obj.Center)).Length cir = Part.makeCircle(rad,obj.Center,Vector(0,0,1),obj.FirstAngle,obj.LastAngle) - cp = fcgeo.findMidpoint(cir.Edges[0]) + cp = DraftGeomUtils.findMidpoint(cir.Edges[0]) rv = cp.sub(obj.Center) - rv = fcvec.scaleTo(rv,rv.Length + obj.ViewObject.FontSize*.2) + rv = DraftVecUtils.scaleTo(rv,rv.Length + obj.ViewObject.FontSize*.2) tbase = obj.Center.add(rv) - trot = fcvec.angle(rv)-math.pi/2 + trot = DraftVecUtils.angle(rv)-math.pi/2 if (trot > math.pi/2) or (trot < -math.pi/2): trot = trot + math.pi s = getParam("dimorientation") @@ -2080,8 +2282,7 @@ class _Rectangle: self.createGeometry(fp) def createGeometry(self,fp): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils plm = fp.Placement p1 = Vector(0,0,0) p2 = Vector(p1.x+fp.Length,p1.y,p1.z) @@ -2090,7 +2291,7 @@ class _Rectangle: shape = Part.makePolygon([p1,p2,p3,p4,p1]) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w shape = Part.Face(shape) @@ -2099,21 +2300,24 @@ class _Rectangle: class _ViewProviderRectangle(_ViewProviderDraft): "A View Provider for the Rectangle object" - def __init__(self, obj): - _ViewProviderDraft.__init__(self,obj) - obj.addProperty("App::PropertyFile","TextureImage", + def __init__(self, vobj): + _ViewProviderDraft.__init__(self,vobj) + vobj.addProperty("App::PropertyFile","TextureImage", "Base","Uses an image as a texture map") - def attach(self,obj): + def attach(self,vobj): self.texture = None + self.Object = vobj.Object def onChanged(self, vp, prop): if prop == "TextureImage": r = vp.RootNode if os.path.exists(vp.TextureImage): - self.texture = coin.SoTexture2() - self.texture.filename = str(vp.TextureImage) - r.insertChild(self.texture,1) + im = loadTexture(vp.TextureImage) + if im: + self.texture = coin.SoTexture2() + self.texture.image = im + r.insertChild(self.texture,1) else: if self.texture: r.removeChild(self.texture) @@ -2200,8 +2404,7 @@ class _Wire: fp.Points = pts def createGeometry(self,fp): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils plm = fp.Placement if fp.Base and (not fp.Tool): if fp.Base.isDerivedFrom("Sketcher::SketchObject"): @@ -2217,8 +2420,8 @@ class _Wire: sh1 = fp.Base.Shape.copy() sh2 = fp.Tool.Shape.copy() shape = sh1.fuse(sh2) - if fcgeo.isCoplanar(shape.Faces): - shape = fcgeo.concatenate(shape) + if DraftGeomUtils.isCoplanar(shape.Faces): + shape = DraftGeomUtils.concatenate(shape) fp.Shape = shape p = [] for v in shape.Vertexes: p.append(v.Point) @@ -2231,7 +2434,7 @@ class _Wire: shape = Part.makePolygon(fp.Points+[fp.Points[0]]) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w shape = Part.Face(shape) @@ -2245,7 +2448,7 @@ class _Wire: shape = Part.Wire(edges) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w fp.Shape = shape @@ -2311,8 +2514,7 @@ class _Polygon: self.createGeometry(fp) def createGeometry(self,fp): - import Part - from draftlibs import fcgeo + import Part, DraftGeomUtils plm = fp.Placement angle = (math.pi*2)/fp.FacesNumber if fp.DrawMode == 'inscribed': @@ -2327,7 +2529,7 @@ class _Polygon: shape = Part.makePolygon(pts) if "FilletRadius" in fp.PropertiesList: if fp.FilletRadius != 0: - w = fcgeo.filletWire(shape,fp.FilletRadius) + w = DraftGeomUtils.filletWire(shape,fp.FilletRadius) if w: shape = w shape = Part.Face(shape) @@ -2336,21 +2538,18 @@ class _Polygon: class _DrawingView: def __init__(self, obj): - obj.addProperty("App::PropertyVector","Direction","Shape view","Projection direction") - obj.addProperty("App::PropertyFloat","LinewidthModifier","Drawing view","Modifies the linewidth of the lines inside this object") - obj.addProperty("App::PropertyFloat","TextModifier","Drawing view","Modifies the size of the texts inside this object") + obj.addProperty("App::PropertyVector","Direction","Shape View","Projection direction") + obj.addProperty("App::PropertyFloat","LineWidth","Drawing View","The width of the lines inside this object") + obj.addProperty("App::PropertyFloat","FontSize","Drawing View","The size of the texts inside this object") obj.addProperty("App::PropertyLink","Source","Base","The linked object") - obj.addProperty("App::PropertyEnumeration","LineStyle","Drawing view","Line Style") - obj.addProperty("App::PropertyEnumeration","FillStyle","Drawing view","Shape Fill Style") - obj.LineStyle = ['continuous','dashed','dashdotted','dotted'] + obj.addProperty("App::PropertyEnumeration","FillStyle","Drawing View","Shape Fill Style") fills = ['shape color'] for f in FreeCAD.svgpatterns.keys(): fills.append(f) obj.FillStyle = fills - obj.Proxy = self - obj.LinewidthModifier = 100 - obj.TextModifier = 100 + obj.LineWidth = 0.35 + obj.FontSize = 12 self.Type = "DrawingView" def execute(self, obj): @@ -2358,12 +2557,12 @@ class _DrawingView: obj.ViewResult = self.updateSVG(obj) def onChanged(self, obj, prop): - if prop in ["X","Y","Scale","LinewidthModifier","TextModifier","LineStyle","FillStyle","Direction"]: + if prop in ["X","Y","Scale","LineWidth","FontSize","FillStyle","Direction"]: obj.ViewResult = self.updateSVG(obj) def updateSVG(self, obj): "encapsulates a svg fragment into a transformation node" - svg = getSVG(obj.Source,obj.LinewidthModifier,obj.TextModifier,obj.LineStyle,obj.FillStyle,obj.Direction) + svg = getSVG(obj.Source,obj.Scale,obj.LineWidth,obj.FontSize,obj.FillStyle,obj.Direction) result = '' result += ', Ken Cline * +#* Yorik van Havre , Ken Cline * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -27,7 +27,7 @@ __url__ = ["http://free-cad.sourceforge.net"] "this file contains generic geometry functions for manipulating Part shapes" -import FreeCAD, Part, fcvec, math, cmath, FreeCADGui +import FreeCAD, Part, DraftVecUtils, math, cmath from FreeCAD import Vector NORM = Vector(0,0,1) # provisory normal direction for all geometry ops. @@ -51,7 +51,7 @@ def vec(edge): def edg(p1,p2): "edg(Vector,Vector) -- returns an edge from 2 vectors" if isinstance(p1,FreeCAD.Vector) and isinstance(p2,FreeCAD.Vector): - if fcvec.equals(p1,p2): return None + if DraftVecUtils.equals(p1,p2): return None else: return Part.Line(p1,p2).toShape() def getVerts(shape): @@ -85,7 +85,7 @@ def isPtOnEdge(pt,edge) : '''isPtOnEdge(Vector,edge) -- Tests if a point is on an edge''' if isinstance(edge.Curve,Part.Line) : orig = edge.Vertexes[0].Point - if fcvec.isNull(pt.sub(orig).cross(vec(edge))) : + if DraftVecUtils.isNull(pt.sub(orig).cross(vec(edge))) : return pt.sub(orig).Length <= vec(edge).Length and pt.sub(orig).dot(vec(edge)) >= 0 else : return False @@ -101,16 +101,16 @@ def isPtOnEdge(pt,edge) : else : begin = edge.Vertexes[0].Point end = edge.Vertexes[-1].Point - if fcvec.isNull(pt.sub(begin)) or fcvec.isNull(pt.sub(end)) : + if DraftVecUtils.isNull(pt.sub(begin)) or DraftVecUtils.isNull(pt.sub(end)) : return True else : # newArc = Part.Arc(begin,pt,end) - # return fcvec.isNull(newArc.Center.sub(center)) \ - # and fcvec.isNull(newArc.Axis-axis) \ + # return DraftVecUtils.isNull(newArc.Center.sub(center)) \ + # and DraftVecUtils.isNull(newArc.Axis-axis) \ # and round(newArc.Radius-radius,precision) == 0 - angle1 = fcvec.angle(begin.sub(center)) - angle2 = fcvec.angle(end.sub(center)) - anglept = fcvec.angle(pt.sub(center)) + angle1 = DraftVecUtils.angle(begin.sub(center)) + angle2 = DraftVecUtils.angle(end.sub(center)) + anglept = DraftVecUtils.angle(pt.sub(center)) if (angle1 < anglept) and (anglept < angle2): return True return False @@ -165,8 +165,8 @@ def findEdge(anEdge,aList): '''findEdge(anEdge,aList): returns True if anEdge is found in aList of edges''' for e in range(len(aList)): if str(anEdge.Curve) == str(aList[e].Curve): - if fcvec.equals(anEdge.Vertexes[0].Point,aList[e].Vertexes[0].Point): - if fcvec.equals(anEdge.Vertexes[-1].Point,aList[e].Vertexes[-1].Point): + if DraftVecUtils.equals(anEdge.Vertexes[0].Point,aList[e].Vertexes[0].Point): + if DraftVecUtils.equals(anEdge.Vertexes[-1].Point,aList[e].Vertexes[-1].Point): return(e) return None @@ -202,13 +202,13 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F return [pt2] #we have 2 straight lines - if fcvec.isNull(pt2.sub(pt1).cross(pt3.sub(pt1)).cross(pt2.sub(pt4).cross(pt3.sub(pt4)))): + if DraftVecUtils.isNull(pt2.sub(pt1).cross(pt3.sub(pt1)).cross(pt2.sub(pt4).cross(pt3.sub(pt4)))): vec1 = pt2.sub(pt1) ; vec2 = pt4.sub(pt3) - if fcvec.isNull(vec1) or fcvec.isNull(vec2): + if DraftVecUtils.isNull(vec1) or DraftVecUtils.isNull(vec2): return [] vec1.normalize() ; vec2.normalize() cross = vec1.cross(vec2) - if not fcvec.isNull(cross) : + if not DraftVecUtils.isNull(cross) : k = ((pt3.z-pt1.z)*(vec2.x-vec2.y)+(pt3.y-pt1.y)*(vec2.z-vec2.x)+ \ (pt3.x-pt1.x)*(vec2.y-vec2.z))/(cross.x+cross.y+cross.z) vec1.scale(k,k,k) @@ -251,7 +251,7 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F elif (pt2 in [pt3,pt4]): return [pt2] - if fcvec.isNull(pt1.sub(center).cross(pt2.sub(center)).cross(arc.Curve.Axis)) : + if DraftVecUtils.isNull(pt1.sub(center).cross(pt2.sub(center)).cross(arc.Curve.Axis)) : # Line and Arc are on same plane dOnLine = center.sub(pt1).dot(dirVec) @@ -303,18 +303,18 @@ def findIntersection(edge1,edge2,infinite1=False,infinite2=False,ex1=False,ex2=F axis1, axis2 = edge1.Curve.Axis , edge2.Curve.Axis c2c = cent2.sub(cent1) - if fcvec.isNull(axis1.cross(axis2)) : + if DraftVecUtils.isNull(axis1.cross(axis2)) : if round(c2c.dot(axis1),precision) == 0 : # circles are on same plane dc2c = c2c.Length ; - if not fcvec.isNull(c2c): c2c.normalize() + if not DraftVecUtils.isNull(c2c): c2c.normalize() if round(rad1+rad2-dc2c,precision) < 0 \ or round(rad1-dc2c-rad2,precision) > 0 or round(rad2-dc2c-rad1,precision) > 0 : return [] else : norm = c2c.cross(axis1) - if not fcvec.isNull(norm): norm.normalize() - if fcvec.isNull(norm): x = 0 + if not DraftVecUtils.isNull(norm): norm.normalize() + if DraftVecUtils.isNull(norm): x = 0 else: x = (dc2c**2 + rad1**2 - rad2**2)/(2*dc2c) y = abs(rad1**2 - x**2)**(0.5) c2c.scale(x,x,x) @@ -364,12 +364,14 @@ def geom(edge): return Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius) else: ref = edge.Placement.multVec(Vector(1,0,0)) + ref = ref.sub(edge.Placement.Base) # we only want the orientation v1 = edge.Vertexes[0].Point v2 = edge.Vertexes[-1].Point c = edge.Curve.Center cu = Part.Circle(edge.Curve.Center,edge.Curve.Axis,edge.Curve.Radius) - a1 = -fcvec.angle(v1.sub(c),ref) - a2 = -fcvec.angle(v2.sub(c),ref) + a1 = -DraftVecUtils.angle(v1.sub(c),ref,edge.Curve.Axis) + a2 = -DraftVecUtils.angle(v2.sub(c),ref,edge.Curve.Axis) + 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: @@ -380,7 +382,7 @@ def mirror (point, edge): normPoint = point.add(findDistance(point, edge, False)) if normPoint: normPoint_point = Vector.sub(point, normPoint) - normPoint_refl = fcvec.neg(normPoint_point) + normPoint_refl = DraftVecUtils.neg(normPoint_point) refl = Vector.add(normPoint, normPoint_refl) return refl else: @@ -433,6 +435,15 @@ def getBoundary(shape): if lut[e.hashCode()] == 1: bound.append(e) return bound +def isLine(bsp): + "returns True if the given BSpline curve is a straight line" + step = bsp.LastParameter/10 + b = bsp.tangent(0) + for i in range(10): + if bsp.tangent(i*step) != b: + return False + return True + def sortEdges(lEdges, aVertex=None): "an alternative, more accurate version of Part.__sortEdges__" @@ -477,6 +488,11 @@ def sortEdges(lEdges, aVertex=None): 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 @@ -489,15 +505,20 @@ def sortEdges(lEdges, aVertex=None): 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 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 @@ -505,12 +526,71 @@ def sortEdges(lEdges, aVertex=None): 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): + '''finds connected wires in the given list of edges''' + + def touches(e1,e2): + if len(e1.Vertexes) < 2: + return False + if len(e2.Vertexes) < 2: + return False + if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[0].Point): + return True + if DraftVecUtils.equals(e1.Vertexes[0].Point,e2.Vertexes[-1].Point): + return True + if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[0].Point): + return True + if DraftVecUtils.equals(e1.Vertexes[-1].Point,e2.Vertexes[-1].Point): + return True + return False + + edges = edgeslist[:] + wires = [] + lost = [] + while edges: + e = edges[0] + if not wires: + # create first group + edges.remove(e) + wires.append([e]) + else: + found = False + for w in wires: + if not found: + for we in w: + if touches(e,we): + edges.remove(e) + w.append(e) + found = True + break + if not found: + if e in lost: + # we already tried this edge, and still nothing + edges.remove(e) + wires.append([e]) + lost = [] + else: + # put to the end of the list + edges.remove(e) + edges.append(e) + lost.append(e) + nwires = [] + for w in wires: + nwires.append(Part.Wire(w)) + return nwires def superWire(edgeslist,closed=False): '''superWire(edges,[closed]): forces a wire between edges that don't necessarily @@ -576,7 +656,7 @@ def findMidpoint(edge): if len(edge.Vertexes) == 1: # Circle dv = first.sub(center) - dv = fcvec.neg(dv) + dv = DraftVecUtils.neg(dv) return center.add(dv) axis = edge.Curve.Axis chord = last.sub(first) @@ -585,12 +665,12 @@ def findMidpoint(edge): ray = first.sub(center) apothem = ray.dot(perp) sagitta = radius - apothem - startpoint = Vector.add(first, fcvec.scale(chord,0.5)) - endpoint = fcvec.scaleTo(perp,sagitta) + startpoint = Vector.add(first, DraftVecUtils.scale(chord,0.5)) + endpoint = DraftVecUtils.scaleTo(perp,sagitta) return Vector.add(startpoint,endpoint) elif isinstance(edge.Curve,Part.Line): - halfedge = fcvec.scale(last.sub(first),.5) + halfedge = DraftVecUtils.scale(last.sub(first),.5) return Vector.add(first,halfedge) else: @@ -679,13 +759,13 @@ def isReallyClosed(wire): if len(wire.Edges) == len(wire.Vertexes): return True v1 = wire.Vertexes[0].Point v2 = wire.Vertexes[-1].Point - if fcvec.equals(v1,v2): return True + if DraftVecUtils.equals(v1,v2): return True return False def getNormal(shape): "finds the normal of a shape, if possible" n = Vector(0,0,1) - if shape.ShapeType == "Face": + if (shape.ShapeType == "Face") and hasattr(shape,"normalAt"): n = shape.normalAt(0.5,0.5) elif shape.ShapeType == "Edge": if isinstance(shape.Curve,Part.Circle): @@ -701,8 +781,10 @@ def getNormal(shape): if 0.1 < abs(e1.getAngle(e2)) < 1.56: n = e1.cross(e2).normalize() break - vdir = FreeCADGui.ActiveDocument.ActiveView.getViewDirection() - if n.getAngle(vdir) < 0.78: n = fcvec.neg(n) + if FreeCAD.GuiUp: + import Draft + vdir = Draft.get3DView().getViewDirection() + if n.getAngle(vdir) < 0.78: n = DraftVecUtils.neg(n) return n def offsetWire(wire,dvec,bind=False,occ=False): @@ -719,7 +801,9 @@ def offsetWire(wire,dvec,bind=False,occ=False): if occ: l=abs(dvec.Length) if not l: return None - if not wire.Wires: + if wire.Wires: + wire = wire.Wires[0] + else: wire = Part.Wire(edges) try: off = wire.makeOffset(l) @@ -731,8 +815,8 @@ def offsetWire(wire,dvec,bind=False,occ=False): curredge = edges[i] delta = dvec if i != 0: - angle = fcvec.angle(vec(edges[0]),vec(curredge),norm) - delta = fcvec.rotate(delta,angle,norm) + angle = DraftVecUtils.angle(vec(edges[0]),vec(curredge),norm) + delta = DraftVecUtils.rotate(delta,angle,norm) nedge = offset(curredge,delta) nedges.append(nedge) nedges = connect(nedges,closed) @@ -806,7 +890,7 @@ def findDistance(point,edge,strict=False): chord = edge.Vertexes[0].Point.sub(point) norm = segment.cross(chord) perp = segment.cross(norm) - dist = fcvec.project(chord,perp) + dist = DraftVecUtils.project(chord,perp) if not dist: return None newpoint = point.add(dist) if (dist.Length == 0): @@ -828,14 +912,14 @@ def findDistance(point,edge,strict=False): center = edge.Curve.Center segment = center.sub(point) ratio = (segment.Length - edge.Curve.Radius) / segment.Length - dist = fcvec.scale(segment,ratio) + dist = DraftVecUtils.scale(segment,ratio) newpoint = Vector.add(point, dist) if (dist.Length == 0): return None if strict and ve2: - ang1 = fcvec.angle(ve1.sub(center)) - ang2 = fcvec.angle(ve2.sub(center)) - angpt = fcvec.angle(newpoint.sub(center)) + ang1 = DraftVecUtils.angle(ve1.sub(center)) + ang2 = DraftVecUtils.angle(ve2.sub(center)) + angpt = DraftVecUtils.angle(newpoint.sub(center)) if ((angpt <= ang2 and angpt >= ang1) or (angpt <= ang1 and angpt >= ang2)): return dist else: @@ -870,15 +954,15 @@ def angleBisection(edge1, edge2): int = findIntersection(edge1, edge2, True, True) if int: line1Dir = p2.sub(p1) - angleDiff = fcvec.angle(line1Dir, p4.sub(p3)) + angleDiff = DraftVecUtils.angle(line1Dir, p4.sub(p3)) ang = angleDiff * 0.5 origin = int[0] line1Dir.normalize() - dir = fcvec.rotate(line1Dir, ang) + dir = DraftVecUtils.rotate(line1Dir, ang) return Part.Line(origin,origin.add(dir)).toShape() else: diff = p3.sub(p1) - origin = p1.add(fcvec.scale(diff, 0.5)) + origin = p1.add(DraftVecUtils.scale(diff, 0.5)) dir = p2.sub(p1); dir.normalize() return Part.Line(origin,origin.add(dir)).toShape() else: @@ -905,7 +989,21 @@ def isCoplanar(faces): return False return True -def findWires(edges): +def isPlanar(shape): + "checks if the given shape is planar" + if len(shape.Vertexes) <= 3: + return True + pts = [v.Point for v in shape.Vertexes[0:3]] + bt = Part.Face(Part.makePolygon(pts+[pts[0]])) + n = bt.normalAt(0,0) + for p in shape.Vertexes[3:]: + pv = p.Point.sub(pts[0]) + rv = DraftVecUtils.project(pv,n) + if not DraftVecUtils.isNull(rv): + return False + return True + +def findWiresOld(edges): '''finds connected edges in the list, and returns a list of lists containing edges that can be connected''' def verts(shape): @@ -1118,9 +1216,9 @@ def getCubicDimensions(shape): vx = vec(base.Edges[0]) vy = vec(base.Edges[1]) # getting rotations - rotZ = fcvec.angle(vx) - rotY = fcvec.angle(vx,FreeCAD.Vector(vx.x,vx.y,0)) - rotX = fcvec.angle(vy,FreeCAD.Vector(vy.x,vy.y,0)) + rotZ = DraftVecUtils.angle(vx) + rotY = DraftVecUtils.angle(vx,FreeCAD.Vector(vx.x,vx.y,0)) + rotX = DraftVecUtils.angle(vy,FreeCAD.Vector(vy.x,vy.y,0)) # getting height vz = None rpi = round(math.pi/2,precision) @@ -1588,23 +1686,23 @@ def circlefrom1Line2Points(edge, p1, p2): v1 = p1.sub(s) v2 = p2.sub(s) projectedDist = math.sqrt(abs(v1.dot(v2))) - edgeDir = vec(edge); edgeDir.normailze() - projectedCen1 = Vector.add(s, fcvec.scale(edgeDir, projectedDist)) - projectedCen2 = Vector.add(s, fcvec.scale(edgeDir, -projectedDist)) + edgeDir = vec(edge); edgeDir.normalize() + projectedCen1 = Vector.add(s, DraftVecUtils.scale(edgeDir, projectedDist)) + projectedCen2 = Vector.add(s, DraftVecUtils.scale(edgeDir, -projectedDist)) perpEdgeDir = edgeDir.cross(Vector(0,0,1)) perpCen1 = Vector.add(projectedCen1, perpEdgeDir) perpCen2 = Vector.add(projectedCen2, perpEdgeDir) mid = findMidpoint(p1_p2) - x = fcvec.crossproduct(vec(p1_p2)); x.normalize() + x = DraftVecUtils.crossproduct(vec(p1_p2)); x.normalize() perp_mid = Vector.add(mid, x) cen1 = findIntersection(edg(projectedCen1, perpCen1), edg(mid, perp_mid), True, True) cen2 = findIntersection(edg(projectedCen2, perpCen2), edg(mid, perp_mid), True, True) circles = [] if cen1: - radius = fcvec.dist(projectedCen1, cen1[0]) + radius = DraftVecUtils.dist(projectedCen1, cen1[0]) circles.append(Part.Circle(cen1[0], NORM, radius)) if cen2: - radius = fcvec.dist(projectedCen2, cen2[0]) + radius = DraftVecUtils.dist(projectedCen2, cen2[0]) circles.append(Part.Circle(cen2[0], NORM, radius)) if circles: return circles @@ -1616,26 +1714,26 @@ def circleFrom2LinesRadius (edge1, edge2, radius): if not int: return None int = int[0] bis12 = angleBisection(edge1,edge2) - bis21 = Part.Line(bis12.Vertexes[0].Point,fcvec.rotate(vec(bis12), math.pi/2.0)) - ang12 = abs(fcvec.angle(vec(edge1),vec(edge2))) + bis21 = Part.Line(bis12.Vertexes[0].Point,DraftVecUtils.rotate(vec(bis12), math.pi/2.0)) + ang12 = abs(DraftVecUtils.angle(vec(edge1),vec(edge2))) ang21 = math.pi - ang12 dist12 = radius / math.sin(ang12 * 0.5) dist21 = radius / math.sin(ang21 * 0.5) circles = [] - cen = Vector.add(int, fcvec.scale(vec(bis12), dist12)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis12), dist12)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, fcvec.scale(vec(bis12), -dist12)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis12), -dist12)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, fcvec.scale(vec(bis21), dist21)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis21), dist21)) circles.append(Part.Circle(cen, NORM, radius)) - cen = Vector.add(int, fcvec.scale(vec(bis21), -dist21)) + cen = Vector.add(int, DraftVecUtils.scale(vec(bis21), -dist21)) circles.append(Part.Circle(cen, NORM, radius)) return circles def circleFrom3LineTangents (edge1, edge2, edge3): "circleFrom3LineTangents(edge,edge,edge)" def rot(ed): - return Part.Line(v1(ed),v1(ed).add(fcvec.rotate(vec(ed),math.pi/2))).toShape() + return Part.Line(v1(ed),v1(ed).add(DraftVecUtils.rotate(vec(ed),math.pi/2))).toShape() bis12 = angleBisection(edge1,edge2) bis23 = angleBisection(edge2,edge3) bis31 = angleBisection(edge3,edge1) @@ -1668,7 +1766,7 @@ def circleFrom3LineTangents (edge1, edge2, edge3): for int in intersections: exists = False for cir in circles: - if fcvec.equals(cir.Center, int.Center): + if DraftVecUtils.equals(cir.Center, int.Center): exists = True break if not exists: @@ -1685,16 +1783,16 @@ def circleFromPointLineRadius (point, edge, radius): center2 = None if dist.Length == 0: segment = vec(edge) - perpVec = fcvec.crossproduct(segment); perpVec.normalize() - normPoint_c1 = fcvec.scale(perpVec, radius) - normPoint_c2 = fcvec.scale(perpVec, -radius) + perpVec = DraftVecUtils.crossproduct(segment); perpVec.normalize() + normPoint_c1 = DraftVecUtils.scale(perpVec, radius) + normPoint_c2 = DraftVecUtils.scale(perpVec, -radius) center1 = point.add(normPoint_c1) center2 = point.add(normPoint_c2) elif dist.Length > 2 * radius: return None elif dist.Length == 2 * radius: normPoint = point.add(findDistance(point, edge, False)) - dummy = fcvec.scale(normPoint.sub(point), 0.5) + dummy = DraftVecUtils.scale(normPoint.sub(point), 0.5) cen = point.add(dummy) circ = Part.Circle(cen, NORM, radius) if circ: @@ -1703,12 +1801,12 @@ def circleFromPointLineRadius (point, edge, radius): return None else: normPoint = point.add(findDistance(point, edge, False)) - normDist = fcvec.dist(normPoint, point) + normDist = DraftVecUtils.dist(normPoint, point) dist = math.sqrt(radius**2 - (radius - normDist)**2) - centerNormVec = fcvec.scaleTo(point.sub(normPoint), radius) + centerNormVec = DraftVecUtils.scaleTo(point.sub(normPoint), radius) edgeDir = edge.Vertexes[0].Point.sub(normPoint); edgeDir.normalize() - center1 = centerNormVec.add(normPoint.add(fcvec.scale(edgeDir, dist))) - center2 = centerNormVec.add(normPoint.add(fcvec.scale(edgeDir, -dist))) + center1 = centerNormVec.add(normPoint.add(DraftVecUtils.scale(edgeDir, dist))) + center2 = centerNormVec.add(normPoint.add(DraftVecUtils.scale(edgeDir, -dist))) circles = [] if center1: circ = Part.Circle(center1, NORM, radius) @@ -1726,10 +1824,10 @@ def circleFromPointLineRadius (point, edge, radius): def circleFrom2PointsRadius(p1, p2, radius): "circleFrom2PointsRadiust(Vector, Vector, radius)" - if fcvec.equals(p1, p2): return None + if DraftVecUtils.equals(p1, p2): return None p1_p2 = Part.Line(p1, p2).toShape() - dist_p1p2 = fcvec.dist(p1, p1) + dist_p1p2 = DraftVecUtils.dist(p1, p1) mid = findMidpoint(p1_p2) if dist_p1p2 == 2*radius: circle = Part.Circle(mid, norm, radius) @@ -1738,8 +1836,8 @@ def circleFrom2PointsRadius(p1, p2, radius): dir = vec(p1_p2); dir.normalize() perpDir = dir.cross(Vector(0,0,1)); perpDir.normailze() dist = math.sqrt(radius**2 - (dist_p1p2 / 2.0)**2) - cen1 = Vector.add(mid, fcvec.scale(perpDir, dist)) - cen2 = Vector.add(mid, fcvec.scale(perpDir, -dist)) + cen1 = Vector.add(mid, DraftVecUtils.scale(perpDir, dist)) + cen2 = Vector.add(mid, DraftVecUtils.scale(perpDir, -dist)) circles = [] if cen1: circles.append(Part.Circle(cen1, norm, radius)) if cen2: circles.append(Part.Circle(cen2, norm, radius)) @@ -1857,7 +1955,7 @@ def innerSoddyCircle(circle1, circle2, circle3): else: print "debug: innerSoddyCircle bad parameters!\n" # FreeCAD.Console.PrintMessage("debug: innerSoddyCircle bad parameters!\n") - return None + return None def circleFrom3CircleTangents(circle1, circle2, circle3): ''' @@ -1971,7 +2069,7 @@ def findHomotheticCenterOfCircles(circle1, circle2): ''' if isinstance(circle1.Curve, Part.Circle) and isinstance(circle2.Curve, Part.Circle): - if fcvec.equals(circle1.Curve.Center, circle2.Curve.Center): + if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None cen1_cen2 = Part.Line(circle1.Curve.Center, circle2.Curve.Center).toShape() @@ -1981,21 +2079,21 @@ def findHomotheticCenterOfCircles(circle1, circle2): perpCenDir = cenDir.cross(Vector(0,0,1)); perpCenDir.normalize() # Get point on first circle - p1 = Vector.add(circle1.Curve.Center, fcvec.scale(perpCenDir, circle1.Curve.Radius)) + p1 = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, circle1.Curve.Radius)) centers = [] # Calculate inner homothetic center # Get point on second circle - p2_inner = Vector.add(circle1.Curve.Center, fcvec.scale(perpCenDir, -circle1.Curve.Radius)) - hCenterInner = fcvec.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) + p2_inner = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, -circle1.Curve.Radius)) + hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_inner, True, True) if hCenterInner: centers.append(hCenterInner) # Calculate outer homothetic center (only exists of the circles have different radii) if circle1.Curve.Radius != circle2.Curve.Radius: # Get point on second circle - p2_outer = Vector.add(circle1.Curve.Center, fcvec.scale(perpCenDir, circle1.Curve.Radius)) - hCenterOuter = fcvec.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) + p2_outer = Vector.add(circle1.Curve.Center, DraftVecUtils.scale(perpCenDir, circle1.Curve.Radius)) + hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center, circle2.Curve.Center, p1, p2_outer, True, True) if hCenterOuter: centers.append(hCenterOuter) @@ -2023,13 +2121,13 @@ def findRadicalAxis(circle1, circle2): ''' if isinstance(circle1.Curve, Part.Circle) and isinstance(circle2.Curve, Part.Circle): - if fcvec.equals(circle1.Curve.Center, circle2.Curve.Center): + if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center): return None r1 = circle1.Curve.Radius r2 = circle1.Curve.Radius cen1 = circle1.Curve.Center # dist .. the distance from cen1 to cen2. - dist = fcvec.dist(cen1, circle2.Curve.Center) + dist = DraftVecUtils.dist(cen1, circle2.Curve.Center) cenDir = cen1.sub(circle2.Curve.Center); cenDir.normalize() # Get the perpedicular vector. @@ -2044,7 +2142,7 @@ def findRadicalAxis(circle1, circle2): k1 = (dist + (r1^2 - r2^2) / dist) / 2.0 #k2 = dist - k1 - K = Vector.add(cen1, fcvec.scale(cenDir, k1)) + K = Vector.add(cen1, DraftVecUtils.scale(cenDir, k1)) # K_ .. A point somewhere between K and J (actually with a distance of 1 unit from K). K_ = Vector,add(K, perpCenDir) @@ -2110,13 +2208,13 @@ def pointInversion(circle, point): cen = circle.Curve.Center rad = circle.Curve.Radius - if fcvec.equals(cen, point): + if DraftVecUtils.equals(cen, point): return None # Inverse the distance of the point # dist(cen -> P) = r^2 / dist(cen -> invP) - dist = fcvec.dist(point, cen) + dist = DraftVecUtils.dist(point, cen) invDist = rad**2 / d invPoint = Vector(0, 0, point.z) @@ -2162,7 +2260,7 @@ def circleInversion(circle, circle2): cen1 = circle.Curve.Center rad1 = circle.Curve.Radius - if fcvec.equals(cen1, point): + if DraftVecUtils.equals(cen1, point): return None invCen2 = Inversion(circle, circle2.Curve.Center) @@ -2170,7 +2268,7 @@ def circleInversion(circle, circle2): pointOnCircle2 = Vector.add(circle2.Curve.Center, Vector(circle2.Curve.Radius, 0, 0)) invPointOnCircle2 = Inversion(circle, pointOnCircle2) - return Part.Circle(invCen2, norm, fcvec.dist(invCen2, invPointOnCircle2)) + return Part.Circle(invCen2, norm, DraftVecUtils.dist(invCen2, invPointOnCircle2)) else: print "debug: circleInversion bad parameters!\n" diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 6b33e6b8ba..d68a981a74 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -78,11 +78,18 @@ class todo: try: name = str(name) FreeCAD.ActiveDocument.openTransaction(name) - func() + if isinstance(func,list): + for l in func: + FreeCADGui.doCommand(l) + else: + func() FreeCAD.ActiveDocument.commitTransaction() except: wrn = "[Draft.todo.commit] Unexpected error:", sys.exc_info()[0], "in ", f, "(", arg, ")" FreeCAD.Console.PrintWarning (wrn) + # restack Draft screen widgets after creation + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.restack() todo.commitlist = [] @staticmethod @@ -150,9 +157,11 @@ class DraftTaskPanel: FreeCADGui.ActiveDocument.resetEdit() return True def reject(self): + FreeCADGui.draftToolBar.isTaskOn = False + FreeCADGui.draftToolBar.escape() FreeCADGui.ActiveDocument.resetEdit() return True - + class DraftToolBar: "main draft Toolbar" def __init__(self): @@ -169,6 +178,7 @@ class DraftToolBar: self.paramconstr = Draft.getParam("constructioncolor")>>8 self.constrMode = False self.continueMode = False + self.relativeMode = True self.state = None self.textbuffer = [] self.crossedViews = [] @@ -307,9 +317,9 @@ class DraftToolBar: self.labelRadius = self._label("labelRadius", self.layout) self.radiusValue = self._lineedit("radiusValue", self.layout, width=60) self.radiusValue.setText("0.00") - self.isRelative = self._checkbox("isRelative",self.layout,checked=True) + self.isRelative = self._checkbox("isRelative",self.layout,checked=self.relativeMode) self.hasFill = self._checkbox("hasFill",self.layout,checked=self.fillmode) - self.continueCmd = self._checkbox("continueCmd",self.layout,checked=False) + self.continueCmd = self._checkbox("continueCmd",self.layout,checked=self.continueMode) self.occOffset = self._checkbox("occOffset",self.layout,checked=False) self.undoButton = self._pushbutton("undoButton", self.layout, icon='Draft_Rotate') self.finishButton = self._pushbutton("finishButton", self.layout, icon='Draft_Finish') @@ -341,7 +351,7 @@ class DraftToolBar: QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("returnPressed()"),self.validatePoint) QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("textChanged(QString)"),self.storeCurrentText) QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("returnPressed()"),self.sendText) - QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("escaped()"),self.finish) + QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("escaped()"),self.escape) QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("down()"),self.sendText) QtCore.QObject.connect(self.textValue,QtCore.SIGNAL("up()"),self.lineUp) QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("returnPressed()"),self.xValue.setFocus) @@ -358,16 +368,17 @@ class DraftToolBar: QtCore.QObject.connect(self.xzButton,QtCore.SIGNAL("clicked()"),self.selectXZ) QtCore.QObject.connect(self.yzButton,QtCore.SIGNAL("clicked()"),self.selectYZ) QtCore.QObject.connect(self.continueCmd,QtCore.SIGNAL("stateChanged(int)"),self.setContinue) + QtCore.QObject.connect(self.isRelative,QtCore.SIGNAL("stateChanged(int)"),self.setRelative) QtCore.QObject.connect(self.hasFill,QtCore.SIGNAL("stateChanged(int)"),self.setFill) QtCore.QObject.connect(self.currentViewButton,QtCore.SIGNAL("clicked()"),self.selectCurrentView) QtCore.QObject.connect(self.resetPlaneButton,QtCore.SIGNAL("clicked()"),self.selectResetPlane) - QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("escaped()"),self.finish) + QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("escaped()"),self.escape) QtCore.QObject.connect(self.xValue,QtCore.SIGNAL("undo()"),self.undoSegment) - QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("escaped()"),self.finish) + QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("escaped()"),self.escape) QtCore.QObject.connect(self.yValue,QtCore.SIGNAL("undo()"),self.undoSegment) - QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("escaped()"),self.finish) + QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("escaped()"),self.escape) QtCore.QObject.connect(self.zValue,QtCore.SIGNAL("undo()"),self.undoSegment) - QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("escaped()"),self.finish) + QtCore.QObject.connect(self.radiusValue,QtCore.SIGNAL("escaped()"),self.escape) QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("resized()"),self.relocate) QtCore.QObject.connect(self.baseWidget,QtCore.SIGNAL("retranslate()"),self.retranslateUi) @@ -484,6 +495,21 @@ class DraftToolBar: self.retranslateUi(self.baseWidget) self.panel = DraftTaskPanel(self.baseWidget,extra) todo.delay(FreeCADGui.Control.showDialog,self.panel) + else: + # create a dummy task to block the UI during the works + class dummy: + "an empty dialog" + def getStandardButtons(self): + return int(QtGui.QDialogButtonBox.Cancel) + def accept(self): + FreeCADGui.ActiveDocument.resetEdit() + return True + def reject(self): + FreeCADGui.draftToolBar.isTaskOn = False + FreeCADGui.draftToolBar.escape() + FreeCADGui.ActiveDocument.resetEdit() + return True + todo.delay(FreeCADGui.Control.showDialog,dummy()) self.setTitle(title) def selectPlaneUi(self): @@ -496,8 +522,22 @@ class DraftToolBar: self.offsetLabel.show() self.offsetValue.show() - def lineUi(self): - self.pointUi(translate("draft", "Line")) + def lineUi(self,title=None): + if title: + self.pointUi(title) + else: + self.pointUi(translate("draft", "Line")) + self.xValue.setEnabled(True) + self.yValue.setEnabled(True) + self.isRelative.show() + self.undoButton.show() + self.continueCmd.show() + + def wireUi(self,title=None): + if title: + self.pointUi(title) + else: + self.pointUi(translate("draft", "DWire")) self.xValue.setEnabled(True) self.yValue.setEnabled(True) self.isRelative.show() @@ -507,7 +547,7 @@ class DraftToolBar: self.wipeButton.show() self.undoButton.show() self.continueCmd.show() - + def circleUi(self): self.pointUi(translate("draft", "Circle")) self.continueCmd.show() @@ -709,7 +749,8 @@ class DraftToolBar: self.radiusValue.setFocus() self.radiusValue.selectAll() - def setRelative(self): + def setRelative(self,val=1): + self.relativeMode = bool(val) if (not self.taskmode) or self.isTaskOn: self.isRelative.show() @@ -833,9 +874,9 @@ class DraftToolBar: pass else: if self.pointcallback: - self.pointcallback(FreeCAD.Vector(numx,numy,numz),(self.isRelative.isVisible() and self.isRelative.isChecked())) + self.pointcallback(FreeCAD.Vector(numx,numy,numz),self.relativeMode) else: - if self.isRelative.isVisible() and self.isRelative.isChecked(): + if self.relativeMode: if self.sourceCmd.node: if self.sourceCmd.featureName == "Rectangle": last = self.sourceCmd.node[0] @@ -860,6 +901,13 @@ class DraftToolBar: self.cancel() self.cancel = None + def escape(self): + "escapes the current command" + self.continueMode = False + if not self.taskmode: + self.continueCmd.setChecked(False) + self.finish() + def closeLine(self): "close button action" self.sourceCmd.finish(True) @@ -895,6 +943,7 @@ class DraftToolBar: spec = False if txt.endsWith(" ") or txt.endsWith("r"): self.isRelative.setChecked(not self.isRelative.isChecked()) + self.relativeMode = self.isRelative.isChecked() spec = True elif txt.endsWith("i"): if self.hasFill.isVisible(): @@ -904,10 +953,16 @@ class DraftToolBar: if self.finishButton.isVisible(): self.finish() spec = True + elif txt.endsWith("t"): + self.continueCmd.setChecked(not self.continueCmd.isChecked()) elif txt.endsWith("w"): self.wipeLine() elif txt.endsWith("s"): self.togglesnap() + elif txt.endsWith("["): + self.toggleradius(1) + elif txt.endsWith("]"): + self.toggleradius(-1) elif txt.endsWith("c"): if self.closeButton.isVisible(): self.closeLine() @@ -964,44 +1019,46 @@ class DraftToolBar: def displayPoint(self, point, last=None, plane=None, mask=None): "this function displays the passed coords in the x, y, and z widgets" - # get coords to display - dp = point - if self.isRelative.isChecked() and (last != None): - if plane: - dp = plane.getLocalCoords(FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z)) + if (not self.taskmode) or self.isTaskOn: + + # get coords to display + dp = point + if self.relativeMode and (last != None): + if plane: + dp = plane.getLocalCoords(FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z)) + else: + dp = FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z) + + # set widgets + self.xValue.setText("%.2f" % dp.x) + self.yValue.setText("%.2f" % dp.y) + self.zValue.setText("%.2f" % dp.z) + + # set masks + if mask == "x": + self.xValue.setEnabled(True) + self.yValue.setEnabled(False) + self.zValue.setEnabled(False) + self.xValue.setFocus() + self.xValue.selectAll() + elif mask == "y": + self.xValue.setEnabled(False) + self.yValue.setEnabled(True) + self.zValue.setEnabled(False) + self.yValue.setFocus() + self.yValue.selectAll() + elif mask == "z": + self.xValue.setEnabled(False) + self.yValue.setEnabled(False) + self.zValue.setEnabled(True) + self.zValue.setFocus() + self.zValue.selectAll() else: - dp = FreeCAD.Vector(point.x-last.x, point.y-last.y, point.z-last.z) - - # set widgets - self.xValue.setText("%.2f" % dp.x) - self.yValue.setText("%.2f" % dp.y) - self.zValue.setText("%.2f" % dp.z) - - # set masks - if mask == "x": - self.xValue.setEnabled(True) - self.yValue.setEnabled(False) - self.zValue.setEnabled(False) - self.xValue.setFocus() - self.xValue.selectAll() - elif mask == "y": - self.xValue.setEnabled(False) - self.yValue.setEnabled(True) - self.zValue.setEnabled(False) - self.yValue.setFocus() - self.yValue.selectAll() - elif mask == "z": - self.xValue.setEnabled(False) - self.yValue.setEnabled(False) - self.zValue.setEnabled(True) - self.zValue.setFocus() - self.zValue.selectAll() - else: - self.xValue.setEnabled(True) - self.yValue.setEnabled(True) - self.zValue.setEnabled(True) - self.xValue.setFocus() - self.xValue.selectAll() + self.xValue.setEnabled(True) + self.yValue.setEnabled(True) + self.zValue.setEnabled(True) + self.xValue.setFocus() + self.xValue.selectAll() def getDefaultColor(self,type,rgb=False): @@ -1103,8 +1160,13 @@ class DraftToolBar: def togglesnap(self): if hasattr(FreeCADGui,"Snapper"): - FreeCADGui.Snapper.active = not FreeCADGui.Snapper.active + FreeCADGui.Snapper.toggle() + def toggleradius(self,val): + if hasattr(FreeCADGui,"Snapper"): + par = Draft.getParam("snapRange") + Draft.setParam("snapRange",par+val) + FreeCADGui.Snapper.showradius() #--------------------------------------------------------------------------- # TaskView operations @@ -1165,6 +1227,7 @@ class DraftToolBar: def Deactivated(self): if (FreeCAD.activeDraftCommand != None): + self.continueMode = False FreeCAD.activeDraftCommand.finish() if self.taskmode: FreeCADGui.Control.clearTaskWatcher() diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index e496ea8f68..c4bacf77a0 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -26,9 +26,8 @@ __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -import FreeCAD, FreeCADGui, math, Draft, DraftGui, DraftTrackers -from DraftGui import todo -from draftlibs import fcvec +import FreeCAD, FreeCADGui, math, Draft, DraftGui, DraftTrackers, DraftVecUtils +from DraftGui import todo,getMainWindow from FreeCAD import Vector from pivy import coin from PyQt4 import QtCore,QtGui @@ -47,6 +46,9 @@ class Snapper: the form [real_point,marker_type,visual_point], and are not meant to be used directly, they are all called when necessary by the general snap() function. + + The Snapper lives inside FreeCADGui once the Draft module has been + loaded. """ @@ -68,8 +70,14 @@ class Snapper: self.grid = None self.constrainLine = None self.trackLine = None + self.radiusTracker = None + self.snapInfo = None self.lastSnappedObject = None self.active = True + self.forceGridOff = False + self.trackers = [[],[],[],[],[]] # view, grid, snap, extline, radius + + self.polarAngles = [90,45] # the snapmarker has "dot","circle" and "square" available styles self.mk = {'passive':'circle', @@ -83,17 +91,17 @@ class Snapper: 'center':'dot', 'ortho':'dot', 'intersection':'dot'} - self.cursors = {'passive':None, - 'extension':':/icons/Constraint_Parallel.svg', - 'parallel':':/icons/Constraint_Parallel.svg', - 'grid':':/icons/Constraint_PointOnPoint.svg', - 'endpoint':':/icons/Constraint_PointOnEnd.svg', - 'midpoint':':/icons/Constraint_PointOnObject.svg', - 'perpendicular':':/icons/Constraint_PointToObject.svg', - 'angle':':/icons/Constraint_ExternalAngle.svg', - 'center':':/icons/Constraint_Concentric.svg', - 'ortho':':/icons/Constraint_Perpendicular.svg', - 'intersection':':/icons/Constraint_Tangent.svg'} + self.cursors = {'passive':':/icons/Snap_Near.svg', + 'extension':':/icons/Snap_Extension.svg', + 'parallel':':/icons/Snap_Parallel.svg', + 'grid':':/icons/Snap_Grid.svg', + 'endpoint':':/icons/Snap_Endpoint.svg', + 'midpoint':':/icons/Snap_Midpoint.svg', + 'perpendicular':':/icons/Snap_Perpendicular.svg', + 'angle':':/icons/Snap_Angle.svg', + 'center':':/icons/Snap_Center.svg', + 'ortho':':/icons/Snap_Ortho.svg', + 'intersection':':/icons/Snap_Intersection.svg'} def snap(self,screenpos,lastpoint=None,active=True,constrain=False): """snap(screenpos,lastpoint=None,active=True,constrain=False): returns a snapped @@ -103,19 +111,32 @@ class Snapper: be True to constrain the point against the closest working plane axis. Screenpos can be a list, a tuple or a coin.SbVec2s object.""" - global Part,fcgeo - import Part, SketcherGui - from draftlibs import fcgeo + global Part, DraftGeomUtils + import Part, DraftGeomUtils + + if not hasattr(self,"toolbar"): + self.makeSnapToolBar() + mw = getMainWindow() + bt = mw.findChild(QtGui.QToolBar,"Draft Snap") + if not bt: + mw.addToolBar(self.toolbar) + else: + if Draft.getParam("showSnapBar"): + bt.show() def cstr(point): "constrains if needed" if constrain: - return self.constrain(point,lastpoint) + fpt = self.constrain(point,lastpoint) else: self.unconstrain() - return point + fpt = point + if self.radiusTracker: + self.radiusTracker.update(fpt) + return fpt snaps = [] + self.snapInfo = None # type conversion if needed if isinstance(screenpos,list): @@ -127,21 +148,14 @@ class Snapper: return None # setup trackers if needed - if not self.tracker: - self.tracker = DraftTrackers.snapTracker() - if not self.extLine: - self.extLine = DraftTrackers.lineTracker(dotted=True) - if (not self.grid) and Draft.getParam("grid"): - self.grid = DraftTrackers.gridTracker() + self.setTrackers() # getting current snap Radius - if not self.radius: - self.radius = self.getScreenDist(Draft.getParam("snapRange"),screenpos) + self.radius = self.getScreenDist(Draft.getParam("snapRange"),screenpos) + if self.radiusTracker: + self.radiusTracker.update(self.radius) + self.radiusTracker.off() - # set the grid - if self.grid and Draft.getParam("grid"): - self.grid.set() - # activate snap oldActive = False if Draft.getParam("alwaysSnap"): @@ -159,7 +173,7 @@ class Snapper: point = self.getApparentPoint(screenpos[0],screenpos[1]) # check if we snapped to something - info = FreeCADGui.ActiveDocument.ActiveView.getObjectInfo((screenpos[0],screenpos[1])) + self.snapInfo = Draft.get3DView().getObjectInfo((screenpos[0],screenpos[1])) # checking if parallel to one of the edges of the last objects or to a polar direction @@ -167,8 +181,8 @@ class Snapper: eline = None point,eline = self.snapToPolar(point,lastpoint) point,eline = self.snapToExtensions(point,lastpoint,constrain,eline) - - if not info: + + if not self.snapInfo: # nothing has been snapped, check fro grid snap if active: @@ -179,7 +193,7 @@ class Snapper: # we have an object to snap to - obj = FreeCAD.ActiveDocument.getObject(info['Object']) + obj = FreeCAD.ActiveDocument.getObject(self.snapInfo['Object']) if not obj: return cstr(point) @@ -192,48 +206,57 @@ class Snapper: if not active: # passive snapping - snaps = [self.snapToVertex(info)] + snaps = [self.snapToVertex(self.snapInfo)] else: + + # first stick to the snapped object + point = self.snapToVertex(self.snapInfo)[0] # active snapping - comp = info['Component'] + comp = self.snapInfo['Component'] if (Draft.getType(obj) == "Wall") and not oldActive: - if obj.Base: - for edge in obj.Base.Shape.Edges: - snaps.extend(self.snapToEndpoints(edge)) - snaps.extend(self.snapToMidpoint(edge)) - snaps.extend(self.snapToPerpendicular(edge,lastpoint)) - snaps.extend(self.snapToIntersection(edge)) - snaps.extend(self.snapToElines(edge,eline)) + edges = [] + for o in [obj]+obj.Additions: + if Draft.getType(o) == "Wall": + if o.Base: + edges.extend(o.Base.Shape.Edges) + for edge in edges: + snaps.extend(self.snapToEndpoints(edge)) + snaps.extend(self.snapToMidpoint(edge)) + snaps.extend(self.snapToPerpendicular(edge,lastpoint)) + snaps.extend(self.snapToIntersection(edge)) + snaps.extend(self.snapToElines(edge,eline)) elif obj.isDerivedFrom("Part::Feature"): if (not self.maxEdges) or (len(obj.Edges) <= self.maxEdges): if "Edge" in comp: # we are snapping to an edge - edge = obj.Shape.Edges[int(comp[4:])-1] - snaps.extend(self.snapToEndpoints(edge)) - snaps.extend(self.snapToMidpoint(edge)) - snaps.extend(self.snapToPerpendicular(edge,lastpoint)) - #snaps.extend(self.snapToOrtho(edge,lastpoint,constrain)) # now part of snapToPolar - snaps.extend(self.snapToIntersection(edge)) - snaps.extend(self.snapToElines(edge,eline)) + en = int(comp[4:])-1 + if len(obj.Shape.Edges) > en: + edge = obj.Shape.Edges[en] + snaps.extend(self.snapToEndpoints(edge)) + snaps.extend(self.snapToMidpoint(edge)) + snaps.extend(self.snapToPerpendicular(edge,lastpoint)) + #snaps.extend(self.snapToOrtho(edge,lastpoint,constrain)) # now part of snapToPolar + snaps.extend(self.snapToIntersection(edge)) + snaps.extend(self.snapToElines(edge,eline)) - if isinstance (edge.Curve,Part.Circle): - # the edge is an arc, we have extra options - snaps.extend(self.snapToAngles(edge)) - snaps.extend(self.snapToCenter(edge)) + if isinstance (edge.Curve,Part.Circle): + # the edge is an arc, we have extra options + snaps.extend(self.snapToAngles(edge)) + snaps.extend(self.snapToCenter(edge)) elif "Vertex" in comp: # directly snapped to a vertex - snaps.append(self.snapToVertex(info,active=True)) + snaps.append(self.snapToVertex(self.snapInfo,active=True)) elif comp == '': # workaround for the new view provider - snaps.append(self.snapToVertex(info,active=True)) + snaps.append(self.snapToVertex(self.snapInfo,active=True)) else: # all other cases (face, etc...) default to passive snap - snapArray = [self.snapToVertex(info)] + snapArray = [self.snapToVertex(self.snapInfo)] elif Draft.getType(obj) == "Dimension": # for dimensions we snap to their 3 points @@ -243,6 +266,9 @@ class Snapper: elif Draft.getType(obj) == "Mesh": # for meshes we only snap to vertices snaps.extend(self.snapToEndpoints(obj.Mesh)) + elif Draft.getType(obj) == "Points": + # for points we only snap to points + snaps.extend(self.snapToEndpoints(obj.Points)) # updating last objects list if not self.lastObj[1]: @@ -256,7 +282,7 @@ class Snapper: # calculating the nearest snap point shortest = 1000000000000000000 - origin = Vector(info['x'],info['y'],info['z']) + origin = Vector(self.snapInfo['x'],self.snapInfo['y'],self.snapInfo['z']) winner = [Vector(0,0,0),None,Vector(0,0,0)] for snap in snaps: # if snap[0] == None: print "debug: Snapper: 'i[0]' is 'None'" @@ -269,8 +295,8 @@ class Snapper: if self.radius: dv = point.sub(winner[2]) if (dv.Length > self.radius): - if not oldActive: - winner = self.snapToVertex(info) + if (not oldActive) and self.isEnabled("passive"): + winner = self.snapToVertex(self.snapInfo) # setting the cursors if self.tracker: @@ -284,25 +310,48 @@ class Snapper: def getApparentPoint(self,x,y): "returns a 3D point, projected on the current working plane" - pt = FreeCADGui.ActiveDocument.ActiveView.getPoint(x,y) - dv = FreeCADGui.ActiveDocument.ActiveView.getViewDirection() - return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv) + view = Draft.get3DView() + pt = view.getPoint(x,y) + if hasattr(FreeCAD,"DraftWorkingPlane"): + if view.getCameraType() == "Perspective": + camera = view.getCameraNode() + p = camera.getField("position").getValue() + dv = pt.sub(Vector(p[0],p[1],p[2])) + else: + dv = view.getViewDirection() + return FreeCAD.DraftWorkingPlane.projectPoint(pt,dv) + else: + return pt def snapToExtensions(self,point,last,constrain,eline): "returns a point snapped to extension or parallel line to last object, if any" - tsnap = self.snapToExtOrtho(last,constrain,eline) - if tsnap: - if (tsnap[0].sub(point)).Length < self.radius: - if self.tracker: - self.tracker.setCoords(tsnap[2]) - self.tracker.setMarker(self.mk[tsnap[1]]) - self.tracker.on() - if self.extLine: - self.extLine.p2(tsnap[2]) - self.extLine.on() - self.setCursor(tsnap[1]) - return tsnap[2],eline + if self.isEnabled("extension"): + tsnap = self.snapToExtOrtho(last,constrain,eline) + if tsnap: + if (tsnap[0].sub(point)).Length < self.radius: + if self.tracker: + self.tracker.setCoords(tsnap[2]) + self.tracker.setMarker(self.mk[tsnap[1]]) + self.tracker.on() + if self.extLine: + self.extLine.p2(tsnap[2]) + self.extLine.on() + self.setCursor(tsnap[1]) + return tsnap[2],eline + else: + tsnap = self.snapToExtPerpendicular(last) + if tsnap: + if (tsnap[0].sub(point)).Length < self.radius: + if self.tracker: + self.tracker.setCoords(tsnap[2]) + self.tracker.setMarker(self.mk[tsnap[1]]) + self.tracker.on() + if self.extLine: + self.extLine.p2(tsnap[2]) + self.extLine.on() + self.setCursor(tsnap[1]) + return tsnap[2],eline for o in [self.lastObj[1],self.lastObj[0]]: if o: @@ -314,222 +363,260 @@ class Snapper: for e in edges: if isinstance(e.Curve,Part.Line): np = self.getPerpendicular(e,point) - if not fcgeo.isPtOnEdge(np,e): + if not DraftGeomUtils.isPtOnEdge(np,e): if (np.sub(point)).Length < self.radius: - if np != e.Vertexes[0].Point: - if self.tracker: - self.tracker.setCoords(np) - self.tracker.setMarker(self.mk['extension']) - self.tracker.on() - if self.extLine: - self.extLine.p1(e.Vertexes[0].Point) - self.extLine.p2(np) - self.extLine.on() - self.setCursor('extension') - return np,Part.Line(e.Vertexes[0].Point,np).toShape() - else: - if last: - de = Part.Line(last,last.add(fcgeo.vec(e))).toShape() - np = self.getPerpendicular(de,point) - if (np.sub(point)).Length < self.radius: + if self.isEnabled('extension'): + if np != e.Vertexes[0].Point: if self.tracker: self.tracker.setCoords(np) - self.tracker.setMarker(self.mk['parallel']) + self.tracker.setMarker(self.mk['extension']) self.tracker.on() + if self.extLine: + self.extLine.p1(e.Vertexes[0].Point) + self.extLine.p2(np) + self.extLine.on() self.setCursor('extension') - return np,de + return np,Part.Line(e.Vertexes[0].Point,np).toShape() + else: + if self.isEnabled('parallel'): + if last: + ve = DraftGeomUtils.vec(e) + if not DraftVecUtils.isNull(ve): + de = Part.Line(last,last.add(ve)).toShape() + np = self.getPerpendicular(de,point) + if (np.sub(point)).Length < self.radius: + if self.tracker: + self.tracker.setCoords(np) + self.tracker.setMarker(self.mk['parallel']) + self.tracker.on() + self.setCursor('parallel') + return np,de return point,eline def snapToPolar(self,point,last): "snaps to polar lines from the given point" - polarAngles = [90,45] - if last: - vecs = [] - ax = [FreeCAD.DraftWorkingPlane.u, - FreeCAD.DraftWorkingPlane.v, - FreeCAD.DraftWorkingPlane.axis] - for a in polarAngles: - if a == 90: - vecs.extend([ax[0],fcvec.neg(ax[0])]) - vecs.extend([ax[1],fcvec.neg(ax[1])]) - else: - v = fcvec.rotate(ax[0],math.radians(a),ax[2]) - vecs.extend([v,fcvec.neg(v)]) - v = fcvec.rotate(ax[1],math.radians(a),ax[2]) - vecs.extend([v,fcvec.neg(v)]) - for v in vecs: - de = Part.Line(last,last.add(v)).toShape() - np = self.getPerpendicular(de,point) - if (np.sub(point)).Length < self.radius: - if self.tracker: - self.tracker.setCoords(np) - self.tracker.setMarker(self.mk['parallel']) - self.tracker.on() - self.setCursor('ortho') - return np,de + if self.isEnabled('ortho'): + if last: + vecs = [] + if hasattr(FreeCAD,"DraftWorkingPlane"): + ax = [FreeCAD.DraftWorkingPlane.u, + FreeCAD.DraftWorkingPlane.v, + FreeCAD.DraftWorkingPlane.axis] + else: + ax = [FreeCAD.Vector(1,0,0), + FreeCAD.Vector(0,1,0), + FreeCAD.Vector(0,0,1)] + for a in self.polarAngles: + if a == 90: + vecs.extend([ax[0],DraftVecUtils.neg(ax[0])]) + vecs.extend([ax[1],DraftVecUtils.neg(ax[1])]) + else: + v = DraftVecUtils.rotate(ax[0],math.radians(a),ax[2]) + vecs.extend([v,DraftVecUtils.neg(v)]) + v = DraftVecUtils.rotate(ax[1],math.radians(a),ax[2]) + vecs.extend([v,DraftVecUtils.neg(v)]) + for v in vecs: + de = Part.Line(last,last.add(v)).toShape() + np = self.getPerpendicular(de,point) + if (np.sub(point)).Length < self.radius: + if self.tracker: + self.tracker.setCoords(np) + self.tracker.setMarker(self.mk['parallel']) + self.tracker.on() + self.setCursor('ortho') + return np,de return point,None def snapToGrid(self,point): "returns a grid snap point if available" if self.grid: - np = self.grid.getClosestNode(point) - if np: - if self.radius != 0: - dv = point.sub(np) - if dv.Length <= self.radius: - if self.tracker: - self.tracker.setCoords(np) - self.tracker.setMarker(self.mk['grid']) - self.tracker.on() - self.setCursor('grid') - return np + if self.grid.Visible: + if self.isEnabled("grid"): + np = self.grid.getClosestNode(point) + if np: + if self.radius != 0: + dv = point.sub(np) + if dv.Length <= self.radius: + if self.tracker: + self.tracker.setCoords(np) + self.tracker.setMarker(self.mk['grid']) + self.tracker.on() + self.setCursor('grid') + return np return point def snapToEndpoints(self,shape): "returns a list of enpoints snap locations" snaps = [] - if hasattr(shape,"Vertexes"): - for v in shape.Vertexes: - snaps.append([v.Point,'endpoint',v.Point]) - elif hasattr(shape,"Point"): - snaps.append([shape.Point,'endpoint',shape.Point]) - elif hasattr(shape,"Points"): - for v in shape.Points: - snaps.append([v.Vector,'endpoint',v.Vector]) + if self.isEnabled("endpoint"): + if hasattr(shape,"Vertexes"): + for v in shape.Vertexes: + snaps.append([v.Point,'endpoint',v.Point]) + elif hasattr(shape,"Point"): + snaps.append([shape.Point,'endpoint',shape.Point]) + elif hasattr(shape,"Points"): + if len(shape.Points) and hasattr(shape.Points[0],"Vector"): + for v in shape.Points: + snaps.append([v.Vector,'endpoint',v.Vector]) + else: + for v in shape.Points: + snaps.append([v,'endpoint',v]) return snaps def snapToMidpoint(self,shape): "returns a list of midpoints snap locations" snaps = [] - if isinstance(shape,Part.Edge): - mp = fcgeo.findMidpoint(shape) - if mp: - snaps.append([mp,'midpoint',mp]) + if self.isEnabled("midpoint"): + if isinstance(shape,Part.Edge): + mp = DraftGeomUtils.findMidpoint(shape) + if mp: + snaps.append([mp,'midpoint',mp]) return snaps def snapToPerpendicular(self,shape,last): "returns a list of perpendicular snap locations" snaps = [] - if last: - if isinstance(shape,Part.Edge): - if isinstance(shape.Curve,Part.Line): - np = self.getPerpendicular(shape,last) - elif isinstance(shape.Curve,Part.Circle): - dv = last.sub(shape.Curve.Center) - dv = fcvec.scaleTo(dv,shape.Curve.Radius) - np = (shape.Curve.Center).add(dv) - elif isinstance(shape.Curve,Part.BSplineCurve): - pr = shape.Curve.parameter(last) - np = shape.Curve.value(pr) - else: - return snaps - snaps.append([np,'perpendicular',np]) + if self.isEnabled("perpendicular"): + if last: + if isinstance(shape,Part.Edge): + if isinstance(shape.Curve,Part.Line): + np = self.getPerpendicular(shape,last) + elif isinstance(shape.Curve,Part.Circle): + dv = last.sub(shape.Curve.Center) + dv = DraftVecUtils.scaleTo(dv,shape.Curve.Radius) + np = (shape.Curve.Center).add(dv) + elif isinstance(shape.Curve,Part.BSplineCurve): + pr = shape.Curve.parameter(last) + np = shape.Curve.value(pr) + else: + return snaps + snaps.append([np,'perpendicular',np]) return snaps def snapToOrtho(self,shape,last,constrain): "returns a list of ortho snap locations" snaps = [] - if constrain: - if isinstance(shape,Part.Edge): - if last: - if isinstance(shape.Curve,Part.Line): - if self.constraintAxis: - tmpEdge = Part.Line(last,last.add(self.constraintAxis)).toShape() - # get the intersection points - pt = fcgeo.findIntersection(tmpEdge,shape,True,True) - if pt: - for p in pt: - snaps.append([p,'ortho',p]) + if self.isEnabled("ortho"): + if constrain: + if isinstance(shape,Part.Edge): + if last: + if isinstance(shape.Curve,Part.Line): + if self.constraintAxis: + tmpEdge = Part.Line(last,last.add(self.constraintAxis)).toShape() + # get the intersection points + pt = DraftGeomUtils.findIntersection(tmpEdge,shape,True,True) + if pt: + for p in pt: + snaps.append([p,'ortho',p]) return snaps def snapToExtOrtho(self,last,constrain,eline): "returns an ortho X extension snap location" - if constrain and last and self.constraintAxis and self.extLine: - tmpEdge1 = Part.Line(last,last.add(self.constraintAxis)).toShape() - tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() - # get the intersection points - pt = fcgeo.findIntersection(tmpEdge1,tmpEdge2,True,True) - if pt: - return [pt[0],'ortho',pt[0]] - if eline: - try: + if self.isEnabled("extension") and self.isEnabled("ortho"): + if constrain and last and self.constraintAxis and self.extLine: + tmpEdge1 = Part.Line(last,last.add(self.constraintAxis)).toShape() tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() # get the intersection points - pt = fcgeo.findIntersection(eline,tmpEdge2,True,True) + pt = DraftGeomUtils.findIntersection(tmpEdge1,tmpEdge2,True,True) if pt: return [pt[0],'ortho',pt[0]] - except: - return None + if eline: + try: + tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() + # get the intersection points + pt = DraftGeomUtils.findIntersection(eline,tmpEdge2,True,True) + if pt: + return [pt[0],'ortho',pt[0]] + except: + return None return None + def snapToExtPerpendicular(self,last): + "returns a perpendicular X extension snap location" + if self.isEnabled("extension") and self.isEnabled("perpendicular"): + if last and self.extLine: + tmpEdge = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() + np = self.getPerpendicular(tmpEdge,last) + return [np,'perpendicular',np] + def snapToElines(self,e1,e2): "returns a snap location at the infinite intersection of the given edges" snaps = [] - if e1 and e2: - # get the intersection points - pts = fcgeo.findIntersection(e1,e2,True,True) - if pts: - for p in pts: - snaps.append([p,'intersection',p]) + if self.isEnabled("intersection") and self.isEnabled("extension"): + if e1 and e2: + # get the intersection points + pts = DraftGeomUtils.findIntersection(e1,e2,True,True) + if pts: + for p in pts: + snaps.append([p,'intersection',p]) return snaps def snapToAngles(self,shape): "returns a list of angle snap locations" snaps = [] - rad = shape.Curve.Radius - pos = shape.Curve.Center - for i in [0,30,45,60,90,120,135,150,180,210,225,240,270,300,315,330]: - ang = math.radians(i) - cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) - snaps.append([cur,'angle',cur]) + if self.isEnabled("angle"): + rad = shape.Curve.Radius + pos = shape.Curve.Center + for i in [0,30,45,60,90,120,135,150,180,210,225,240,270,300,315,330]: + ang = math.radians(i) + cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) + snaps.append([cur,'angle',cur]) return snaps def snapToCenter(self,shape): "returns a list of center snap locations" snaps = [] - rad = shape.Curve.Radius - pos = shape.Curve.Center - for i in [15,37.5,52.5,75,105,127.5,142.5,165,195,217.5,232.5,255,285,307.5,322.5,345]: - ang = math.radians(i) - cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) - snaps.append([cur,'center',pos]) + if self.isEnabled("center"): + rad = shape.Curve.Radius + pos = shape.Curve.Center + for i in [15,37.5,52.5,75,105,127.5,142.5,165,195,217.5,232.5,255,285,307.5,322.5,345]: + ang = math.radians(i) + cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) + snaps.append([cur,'center',pos]) return snaps def snapToIntersection(self,shape): "returns a list of intersection snap locations" snaps = [] - # get the stored objects to calculate intersections - if self.lastObj[0]: - obj = FreeCAD.ActiveDocument.getObject(self.lastObj[0]) - if obj: - if obj.isDerivedFrom("Part::Feature"): - if (not self.maxEdges) or (len(obj.Shape.Edges) <= self.maxEdges): - for e in obj.Shape.Edges: - # get the intersection points - pt = fcgeo.findIntersection(e,shape) - if pt: - for p in pt: - snaps.append([p,'intersection',p]) + if self.isEnabled("intersection"): + # get the stored objects to calculate intersections + if self.lastObj[0]: + obj = FreeCAD.ActiveDocument.getObject(self.lastObj[0]) + if obj: + if obj.isDerivedFrom("Part::Feature"): + if (not self.maxEdges) or (len(obj.Shape.Edges) <= self.maxEdges): + for e in obj.Shape.Edges: + # get the intersection points + pt = DraftGeomUtils.findIntersection(e,shape) + if pt: + for p in pt: + snaps.append([p,'intersection',p]) return snaps def snapToVertex(self,info,active=False): p = Vector(info['x'],info['y'],info['z']) if active: - return [p,'endpoint',p] - else: + if self.isEnabled("endpoint"): + return [p,'endpoint',p] + else: + return [] + elif self.isEnabled("passive"): return [p,'passive',p] + else: + return [] def getScreenDist(self,dist,cursor): "returns a distance in 3D space from a screen pixels distance" - p1 = FreeCADGui.ActiveDocument.ActiveView.getPoint(cursor) - p2 = FreeCADGui.ActiveDocument.ActiveView.getPoint((cursor[0]+dist,cursor[1])) + view = Draft.get3DView() + p1 = view.getPoint(cursor) + p2 = view.getPoint((cursor[0]+dist,cursor[1])) return (p2.sub(p1)).Length def getPerpendicular(self,edge,pt): "returns a point on an edge, perpendicular to the given point" dv = pt.sub(edge.Vertexes[0].Point) - nv = fcvec.project(dv,fcgeo.vec(edge)) + nv = DraftVecUtils.project(dv,DraftGeomUtils.vec(edge)) np = (edge.Vertexes[0].Point).add(nv) return np @@ -560,18 +647,27 @@ class Snapper: for v in self.views: v.setCursor(cur) self.cursorMode = mode - + + def restack(self): + if self.grid: + self.grid.lowerTracker() + def off(self): "finishes snapping" if self.tracker: self.tracker.off() if self.extLine: self.extLine.off() + if self.radiusTracker: + self.radiusTracker.off() if self.grid: - self.grid.off() + if not Draft.getParam("alwaysShowGrid"): + self.grid.off() self.unconstrain() self.radius = 0 self.setCursor() + if Draft.getParam("hideSnapBar"): + self.toolbar.hide() def constrain(self,point,basepoint=None,axis=None): '''constrain(point,basepoint=None,axis=None: Returns a @@ -581,6 +677,10 @@ class Snapper: must be constrained. If no basepoint is given, the current point is used as basepoint.''' + # without the Draft module fully loaded, no axes system!" + if not hasattr(FreeCAD,"DraftWorkingPlane"): + return point + point = Vector(point) # setup trackers if needed @@ -615,7 +715,7 @@ class Snapper: self.constraintAxis = FreeCAD.DraftWorkingPlane.axis # calculating constrained point - cdelta = fcvec.project(delta,self.constraintAxis) + cdelta = DraftVecUtils.project(delta,self.constraintAxis) npoint = self.basepoint.add(cdelta) # setting constrain line @@ -637,7 +737,8 @@ class Snapper: def getPoint(self,last=None,callback=None,movecallback=None,extradlg=None): - """getPoint([last],[callback],[movecallback],[extradlg]) : gets a 3D point + """ + getPoint([last],[callback],[movecallback],[extradlg]) : gets a 3D point from the screen. You can provide an existing point, in that case additional snap options and a tracker are available. You can also pass a function as callback, which will get called @@ -651,16 +752,20 @@ class Snapper: def cb(point): if point: print "got a 3D point: ",point + FreeCADGui.Snapper.getPoint(callback=cb) If the callback function accepts more than one argument, it will also receive - the last snapped object. Finally, a pyqt dialog can be passed as extra taskbox.""" + the last snapped object. Finally, a pyqt dialog can be passed as extra taskbox. + + """ import inspect self.pt = None + self.lastSnappedObject = None self.ui = FreeCADGui.draftToolBar - self.view = FreeCADGui.ActiveDocument.ActiveView + self.view = Draft.get3DView() # setting a track line if we got an existing point if last: @@ -675,7 +780,8 @@ class Snapper: ctrl = event.wasCtrlDown() shift = event.wasShiftDown() self.pt = FreeCADGui.Snapper.snap(mousepos,lastpoint=last,active=ctrl,constrain=shift) - self.ui.displayPoint(self.pt,last,plane=FreeCAD.DraftWorkingPlane,mask=FreeCADGui.Snapper.affinity) + if hasattr(FreeCAD,"DraftWorkingPlane"): + self.ui.displayPoint(self.pt,last,plane=FreeCAD.DraftWorkingPlane,mask=FreeCADGui.Snapper.affinity) if self.trackLine: self.trackLine.p2(self.pt) if movecallback: @@ -683,7 +789,7 @@ class Snapper: def getcoords(point,relative=False): self.pt = point - if relative and last: + if relative and last and hasattr(FreeCAD,"DraftWorkingPlane"): v = FreeCAD.DraftWorkingPlane.getGlobalCoords(point) self.pt = last.add(v) accept() @@ -722,8 +828,126 @@ class Snapper: # adding callback functions self.ui.pointUi(cancel=cancel,getcoords=getcoords,extra=extradlg,rel=bool(last)) self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),click) - self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) + self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) + def makeSnapToolBar(self): + "builds the Snap toolbar" + self.toolbar = QtGui.QToolBar(None) + self.toolbar.setObjectName("Draft Snap") + self.toolbar.setWindowTitle("Draft Snap") + self.toolbarButtons = [] + self.masterbutton = QtGui.QPushButton(None) + self.masterbutton.setIcon(QtGui.QIcon(":/icons/Snap_Lock.svg")) + self.masterbutton.setIconSize(QtCore.QSize(16, 16)) + self.masterbutton.setMaximumSize(QtCore.QSize(26,26)) + self.masterbutton.setToolTip("Snap On/Off") + self.masterbutton.setObjectName("SnapButtonMain") + self.masterbutton.setCheckable(True) + self.masterbutton.setChecked(True) + QtCore.QObject.connect(self.masterbutton,QtCore.SIGNAL("toggled(bool)"),self.toggle) + self.toolbar.addWidget(self.masterbutton) + for c,i in self.cursors.iteritems(): + if i: + b = QtGui.QPushButton(None) + b.setIcon(QtGui.QIcon(i)) + b.setIconSize(QtCore.QSize(16, 16)) + b.setMaximumSize(QtCore.QSize(26,26)) + b.setToolTip(c) + b.setObjectName("SnapButton"+c) + b.setCheckable(True) + b.setChecked(True) + self.toolbar.addWidget(b) + self.toolbarButtons.append(b) + QtCore.QObject.connect(b,QtCore.SIGNAL("toggled(bool)"),self.saveSnapModes) + # restoring states + t = Draft.getParam("snapModes") + if t: + c = 0 + for b in [self.masterbutton]+self.toolbarButtons: + if len(t) > c: + b.setChecked(bool(int(t[c]))) + c += 1 + if not Draft.getParam("showSnapBar"): + self.toolbar.hide() + def saveSnapModes(self): + "saves the snap modes for next sessions" + t = '' + for b in [self.masterbutton]+self.toolbarButtons: + t += str(int(b.isChecked())) + Draft.setParam("snapModes",t) + + def toggle(self,checked=None): + "toggles the snap mode" + if hasattr(self,"toolbarButtons"): + if checked == None: + self.masterbutton.toggle() + elif checked: + if hasattr(self,"savedButtonStates"): + for i in range(len(self.toolbarButtons)): + self.toolbarButtons[i].setEnabled(True) + self.toolbarButtons[i].setChecked(self.savedButtonStates[i]) + else: + self.savedButtonStates = [] + for i in range(len(self.toolbarButtons)): + self.savedButtonStates.append(self.toolbarButtons[i].isChecked()) + self.toolbarButtons[i].setEnabled(False) + self.saveSnapModes() + + def showradius(self): + "shows the snap radius indicator" + self.radius = self.getScreenDist(Draft.getParam("snapRange"),(400,300)) + if self.radiusTracker: + self.radiusTracker.update(self.radius) + self.radiusTracker.on() + + def isEnabled(self,but): + "returns true if the given button is turned on" + for b in self.toolbarButtons: + if str(b.objectName()) == "SnapButton" + but: + return (b.isEnabled() and b.isChecked()) + return False + + def show(self): + "shows the toolbar and the grid" + if not hasattr(self,"toolbar"): + self.makeSnapToolBar() + mw = getMainWindow() + bt = mw.findChild(QtGui.QToolBar,"Draft Snap") + if not bt: + mw.addToolBar(self.toolbar) + self.toolbar.show() + if FreeCADGui.ActiveDocument: + self.setTrackers() + + def setTrackers(self): + v = Draft.get3DView() + if v in self.trackers[0]: + i = self.trackers[0].index(v) + self.grid = self.trackers[1][i] + self.tracker = self.trackers[2][i] + self.extLine = self.trackers[3][i] + self.radiusTracker = self.trackers[4][i] + else: + if Draft.getParam("grid"): + self.grid = DraftTrackers.gridTracker() + else: + self.grid = None + self.tracker = DraftTrackers.snapTracker() + self.extLine = DraftTrackers.lineTracker(dotted=True) + self.radiusTracker = DraftTrackers.radiusTracker() + self.trackers[0].append(v) + self.trackers[1].append(self.grid) + self.trackers[2].append(self.tracker) + self.trackers[3].append(self.extLine) + self.trackers[4].append(self.radiusTracker) + if not self.forceGridOff: + self.grid.set() + if not hasattr(FreeCADGui,"Snapper"): FreeCADGui.Snapper = Snapper() +if not hasattr(FreeCAD,"DraftWorkingPlane"): + import WorkingPlane, Draft_rc + FreeCAD.DraftWorkingPlane = WorkingPlane.plane() + print FreeCAD.DraftWorkingPlane + FreeCADGui.addIconPath(":/icons") diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 3196c96fdc..0407369277 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -29,9 +29,7 @@ __url__ = "http://free-cad.sourceforge.net" # Generic stuff #--------------------------------------------------------------------------- -import os, FreeCAD, FreeCADGui, WorkingPlane, math, re, importSVG, Draft, Draft_rc -from functools import partial -from draftlibs import fcvec +import os, FreeCAD, FreeCADGui, WorkingPlane, math, re, importSVG, Draft, Draft_rc, DraftVecUtils from FreeCAD import Vector from DraftGui import todo,QtCore,QtGui from DraftSnap import * @@ -72,6 +70,20 @@ MODCONSTRAIN = MODS[Draft.getParam("modconstrain")] MODSNAP = MODS[Draft.getParam("modsnap")] MODALT = MODS[Draft.getParam("modalt")] +# sets defaults on first load + +if not FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod").HasGroup("Draft"): + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + p.SetBool("copymode",1) + p.SetBool("alwaysSnap",1) + p.SetBool("showSnapBar",1) + p.SetUnsigned("constructioncolor",746455039) + p.SetFloat("textheight",0.2) + p.SetInt("precision",4) + p.SetInt("gridEvery",10) + p.SetFloat("gridSpacing",1.0) + p.SetInt("UiMode",1) + #--------------------------------------------------------------------------- # General functions #--------------------------------------------------------------------------- @@ -80,7 +92,7 @@ MODALT = MODS[Draft.getParam("modalt")] def translate(context,text): "convenience function for Qt translator" return QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).toUtf8() - + def msg(text=None,mode=None): "prints the given message on the FreeCAD status bar" if not text: FreeCAD.Console.PrintMessage("") @@ -102,7 +114,7 @@ def selectObject(arg): if (arg["Type"] == "SoMouseButtonEvent"): if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): cursor = arg["Position"] - snapped = FreeCADGui.ActiveDocument.ActiveView.getObjectInfo((cursor[0],cursor[1])) + snapped = Draft.get3DView().getObjectInfo((cursor[0],cursor[1])) if snapped: obj = FreeCAD.ActiveDocument.getObject(snapped['Object']) FreeCADGui.Selection.addSelection(obj) @@ -120,7 +132,7 @@ def getPoint(target,args,mobile=False,sym=False,workingplane=True): ''' ui = FreeCADGui.draftToolBar - view = FreeCADGui.ActiveDocument.ActiveView + view = Draft.get3DView() # get point if target.node: @@ -130,23 +142,7 @@ def getPoint(target,args,mobile=False,sym=False,workingplane=True): amod = hasMod(args,MODSNAP) cmod = hasMod(args,MODCONSTRAIN) point = FreeCADGui.Snapper.snap(args["Position"],lastpoint=last,active=amod,constrain=cmod) - - # project onto working plane if needed - if (not plane.weak) and workingplane: - # working plane was explicitely selected - project onto it - viewDirection = view.getViewDirection() - if FreeCADGui.ActiveDocument.ActiveView.getCameraType() == "Perspective": - camera = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() - p = camera.getField("position").getValue() - # view is from camera to point: - viewDirection = point.sub(Vector(p[0],p[1],p[2])) - # if we are not snapping to anything, project along view axis, - # otherwise perpendicularly - if view.getObjectInfo((args["Position"][0],args["Position"][1])): - pass - # point = plane.projectPoint(point) - else: - point = plane.projectPoint(point, viewDirection) + info = FreeCADGui.Snapper.snapInfo ctrlPoint = Vector(point) mask = FreeCADGui.Snapper.affinity if target.node: @@ -155,11 +151,22 @@ def getPoint(target,args,mobile=False,sym=False,workingplane=True): else: ui.displayPoint(point, target.node[-1], plane=plane, mask=mask) else: ui.displayPoint(point, plane=plane, mask=mask) - return point,ctrlPoint + return point,ctrlPoint,info -def getSupport(args): +def getSupport(args=None): "returns the supporting object and sets the working plane" - snapped = FreeCADGui.ActiveDocument.ActiveView.getObjectInfo((args["Position"][0],args["Position"][1])) + if not args: + sel = FreeCADGui.Selection.getSelectionEx() + if len(sel) == 1: + sel = sel[0] + if sel.HasSubObjects: + if len(sel.SubElementNames) == 1: + if "Face" in sel.SubElementNames[0]: + plane.alignToFace(sel.SubObjects[0]) + return sel.Object + return None + + snapped = Draft.get3DView().getObjectInfo((args["Position"][0],args["Position"][1])) if not snapped: return None obj = None plane.save() @@ -192,11 +199,125 @@ def setMod(args,mod,state): elif mod == "alt": args["AltDown"] = state + + + +#--------------------------------------------------------------------------- +# Base Class +#--------------------------------------------------------------------------- + +class DraftTool: + "The base class of all Draft Tools" + + def __init__(self): + self.commitList = [] + + def IsActive(self): + if FreeCADGui.ActiveDocument: + return True + else: + return False + + def Activated(self,name="None"): + if FreeCAD.activeDraftCommand: + FreeCAD.activeDraftCommand.finish() + + global Part, DraftGeomUtils + import Part, DraftGeomUtils + + self.ui = None + self.call = None + self.support = None + self.commitList = [] + self.doc = FreeCAD.ActiveDocument + if not self.doc: + self.finish() + return + + FreeCAD.activeDraftCommand = self + self.view = Draft.get3DView() + self.ui = FreeCADGui.draftToolBar + self.ui.sourceCmd = self + self.ui.setTitle(name) + self.ui.show() + rot = self.view.getCameraNode().getField("orientation").getValue() + upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) + plane.setup(DraftVecUtils.neg(self.view.getViewDirection()), Vector(0,0,0), upv) + self.node = [] + self.pos = [] + self.constrain = None + self.obj = None + self.extendedCopy = False + self.ui.setTitle(name) + self.featureName = name + #self.snap = snapTracker() + #self.extsnap = lineTracker(dotted=True) + self.planetrack = None + if Draft.getParam("showPlaneTracker"): + self.planetrack = PlaneTracker() + + def finish(self): + self.node = [] + #self.snap.finalize() + #self.extsnap.finalize() + FreeCAD.activeDraftCommand = None + if self.ui: + self.ui.offUi() + self.ui.sourceCmd = None + #self.ui.cross(False) + msg("") + if self.planetrack: + self.planetrack.finalize() + if self.support: + plane.restore() + FreeCADGui.Snapper.off() + if self.call: + self.view.removeEventCallback("SoEvent",self.call) + self.call = None + if self.commitList: + todo.delayCommit(self.commitList) + self.commitList = [] + + def commit(self,name,func): + "stores actions to be committed to the FreeCAD document" + # print "committing" + self.commitList.append((name,func)) + + def getStrings(self): + "returns a couple of useful strings fro building python commands" + + # current plane rotation + p = plane.getRotation() + qr = p.Rotation.Q + qr = '('+str(qr[0])+','+str(qr[1])+','+str(qr[2])+','+str(qr[3])+')' + + # support object + if self.support: + sup = 'FreeCAD.ActiveDocument.getObject("' + self.support.Name + '")' + else: + sup = 'None' + + # contents of self.node + points='[' + for n in self.node: + if len(points) > 1: + points += ',' + points += DraftVecUtils.toString(n) + points += ']' + + # fill mode + if self.ui: + fil = str(bool(self.ui.fillmode)) + else: + fil = "True" + + return qr,sup,points,fil + #--------------------------------------------------------------------------- # Helper tools -#--------------------------------------------------------------------------- - -class SelectPlane: +#--------------------------------------------------------------------------- + +class SelectPlane(DraftTool): "The Draft_SelectPlane FreeCAD command definition" def GetResources(self): @@ -204,27 +325,24 @@ class SelectPlane: 'Accel' : "W, P", 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_SelectPlane", "SelectPlane"), 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_SelectPlane", "Select a working plane for geometry creation")} - - def IsActive(self): - if FreeCADGui.ActiveDocument: - return True - else: - return False def Activated(self): - if FreeCAD.activeDraftCommand: - FreeCAD.activeDraftCommand.finish() + DraftTool.Activated(self) self.offset = 0 - self.ui = None - self.call = None - self.doc = FreeCAD.ActiveDocument if self.doc: - FreeCAD.activeDraftCommand = self - self.view = FreeCADGui.ActiveDocument.ActiveView - self.ui = FreeCADGui.draftToolBar + sel = FreeCADGui.Selection.getSelectionEx() + if len(sel) == 1: + sel = sel[0] + if sel.HasSubObjects: + if len(sel.SubElementNames) == 1: + if "Face" in sel.SubElementNames[0]: + self.ui = FreeCADGui.draftToolBar + plane.alignToFace(sel.SubObjects[0], self.offset) + self.display(plane.axis) + self.finish() + return self.ui.selectPlaneUi() msg(translate("draft", "Pick a face to define the drawing plane\n")) - self.ui.sourceCmd = self if plane.alignToSelection(self.offset): FreeCADGui.Selection.clearSelection() self.display(plane.axis) @@ -239,7 +357,7 @@ class SelectPlane: if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): cursor = arg["Position"] doc = FreeCADGui.ActiveDocument - info = doc.ActiveView.getObjectInfo((cursor[0],cursor[1])) + info = Draft.get3DView().getObjectInfo((cursor[0],cursor[1])) if info: try: shape = doc.getObject(info["Object"]).Object.Shape @@ -269,7 +387,7 @@ class SelectPlane: self.display('side') self.finish() elif arg == "currentView": - viewDirection = fcvec.neg(self.view.getViewDirection()) + viewDirection = DraftVecUtils.neg(self.view.getViewDirection()) plane.alignToPointAndAxis(Vector(0,0,0), viewDirection, self.offset) self.display(viewDirection) self.finish() @@ -291,90 +409,27 @@ class SelectPlane: elif type(arg).__name__ == 'Vector': plv = 'd('+str(arg.x)+','+str(arg.y)+','+str(arg.z)+')' self.ui.wplabel.setText(plv+suffix) - - def finish(self): - if self.call: - self.view.removeEventCallback("SoEvent",self.call) - FreeCAD.activeDraftCommand = None - if self.ui: - self.ui.offUi() + FreeCADGui.Snapper.setGrid() #--------------------------------------------------------------------------- # Geometry constructors #--------------------------------------------------------------------------- - -class Creator: + +class Creator(DraftTool): "A generic Draft Creator Tool used by creation tools such as line or arc" def __init__(self): - self.commitList = [] - + DraftTool.__init__(self) + def Activated(self,name="None"): - if FreeCAD.activeDraftCommand: - FreeCAD.activeDraftCommand.finish() - global Part, fcgeo - import Part - from draftlibs import fcgeo - self.ui = None - self.call = None - self.doc = None - self.support = None - self.commitList = [] - self.doc = FreeCAD.ActiveDocument - self.view = FreeCADGui.ActiveDocument.ActiveView - self.featureName = name - if not self.doc: - self.finish() - else: - FreeCAD.activeDraftCommand = self - self.ui = FreeCADGui.draftToolBar - self.ui.sourceCmd = self - self.ui.setTitle(name) - self.ui.show() - rot = self.view.getCameraNode().getField("orientation").getValue() - upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) - plane.setup(fcvec.neg(self.view.getViewDirection()), Vector(0,0,0), upv) - self.node = [] - self.pos = [] - self.constrain = None - self.obj = None - self.snap = snapTracker() - self.extsnap = lineTracker(dotted=True) - self.planetrack = PlaneTracker() - - def IsActive(self): - if FreeCADGui.ActiveDocument: - return True - else: - return False - - def finish(self): - self.snap.finalize() - self.extsnap.finalize() - self.node=[] - self.planetrack.finalize() - if self.support: plane.restore() - FreeCADGui.Snapper.off() - FreeCAD.activeDraftCommand = None - if self.ui: - self.ui.offUi() - self.ui.sourceCmd = None - msg("") - if self.call: - self.view.removeEventCallback("SoEvent",self.call) - self.call = None - if self.commitList: - todo.delayCommit(self.commitList) - self.commitList = [] - - def commit(self,name,func): - "stores partial actions to be committed to the FreeCAD document" - self.commitList.append((name,func)) - + DraftTool.Activated(self) + self.support = getSupport() + class Line(Creator): "The Line FreeCAD command definition" def __init__(self, wiremode=False): + Creator.__init__(self) self.isWire = wiremode def GetResources(self): @@ -387,7 +442,10 @@ class Line(Creator): Creator.Activated(self,name) if self.doc: self.obj = None - self.ui.lineUi() + if self.isWire: + self.ui.wireUi(name) + else: + self.ui.lineUi(name) self.linetrack = lineTracker() self.constraintrack = lineTracker(dotted=True) self.obj=self.doc.addObject("Part::Feature",self.featureName) @@ -399,18 +457,22 @@ class Line(Creator): def finish(self,closed=False,cont=False): "terminates the operation and closes the poly if asked" if self.obj: + # remove temporary object, if any old = self.obj.Name todo.delay(self.doc.removeObject,old) self.obj = None if (len(self.node) > 1): - self.commit(translate("draft","Create Wire"), - partial(Draft.makeWire,self.node,closed, - face=self.ui.fillmode,support=self.support)) + # building command string + rot,sup,pts,fil = self.getStrings() + self.commit(translate("draft","Create DWire"), + ['import Draft', + 'points='+pts, + 'Draft.makeWire(points,closed='+str(closed)+',face='+fil+',support='+sup+')']) if self.ui: self.linetrack.finalize() self.constraintrack.finalize() Creator.finish(self) - if cont and self.ui: + if self.ui: if self.ui.continueMode: self.Activated() @@ -422,7 +484,7 @@ class Line(Creator): self.finish() elif arg["Type"] == "SoLocation2Event": # mouse movement detection - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.ui.cross(True) self.linetrack.p2(point) elif arg["Type"] == "SoMouseButtonEvent": @@ -431,8 +493,9 @@ class Line(Creator): if (arg["Position"] == self.pos): self.finish(False,cont=True) else: - if not self.node: self.support = getSupport(arg) - point,ctrlPoint = getPoint(self,arg) + if (not self.node) and (not self.support): + self.support = getSupport(arg) + point,ctrlPoint,info = getPoint(self,arg) self.pos = arg["Position"] self.node.append(point) self.linetrack.p1(point) @@ -443,7 +506,7 @@ class Line(Creator): if ((point-self.node[0]).Length < Draft.tolerance()): self.undolast() self.finish(True,cont=True) - msg(translate("draft", "Wire has been closed\n")) + msg(translate("draft", "DWire has been closed\n")) def undolast(self): "undoes last line segment" @@ -467,7 +530,8 @@ class Line(Creator): if (len(self.node) == 1): self.linetrack.on() msg(translate("draft", "Pick next point:\n")) - self.planetrack.set(self.node[0]) + if self.planetrack: + self.planetrack.set(self.node[0]) elif (len(self.node) == 2): last = self.node[len(self.node)-2] newseg = Part.Line(last,point).toShape() @@ -490,7 +554,8 @@ class Line(Creator): self.obj.ViewObject.Visibility = False self.node = [self.node[-1]] self.linetrack.p1(self.node[0]) - self.planetrack.set(self.node[0]) + if self.planetrack: + self.planetrack.set(self.node[0]) msg(translate("draft", "Pick next point:\n")) def numericInput(self,numx,numy,numz): @@ -510,8 +575,10 @@ class Wire(Line): def GetResources(self): return {'Pixmap' : 'Draft_Wire', 'Accel' : "W, I", - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "Wire"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "Creates a multiple-point wire. CTRL to snap, SHIFT to constrain")} + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "DWire"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Wire", "Creates a multiple-point DraftWire (DWire). CTRL to snap, SHIFT to constrain")} + def Activated(self): + Line.Activated(self,name=str(translate("draft","DWire"))) class BSpline(Line): @@ -527,7 +594,7 @@ class BSpline(Line): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_BSpline", "Creates a multiple-point b-spline. CTRL to snap, SHIFT to constrain")} def Activated(self): - Line.Activated(self,"BSpline") + Line.Activated(self,name=str(translate("draft","BSpline"))) if self.doc: self.bsplinetrack = bsplineTracker() @@ -537,7 +604,7 @@ class BSpline(Line): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.ui.cross(True) self.bsplinetrack.update(self.node + [point]) # Draw constraint tracker line. @@ -551,8 +618,9 @@ class BSpline(Line): if (arg["Position"] == self.pos): self.finish(False,cont=True) else: - if not self.node: self.support = getSupport(arg) - point,ctrlPoint = getPoint(self,arg) + if (not self.node) and (not self.support): + self.support = getSupport(arg) + point,ctrlPoint,info = getPoint(self,arg) self.pos = arg["Position"] self.node.append(point) self.drawUpdate(point) @@ -581,7 +649,8 @@ class BSpline(Line): def drawUpdate(self,point): if (len(self.node) == 1): self.bsplinetrack.on() - self.planetrack.set(self.node[0]) + if self.planetrack: + self.planetrack.set(self.node[0]) msg(translate("draft", "Pick next point:\n")) else: spline = Part.BSplineCurve() @@ -597,16 +666,19 @@ class BSpline(Line): old = self.obj.Name self.doc.removeObject(old) try: + # building command string + rot,sup,pts,fil = self.getStrings() self.commit(translate("draft","Create BSpline"), - partial(Draft.makeBSpline,self.node,closed, - face=self.ui.fillmode,support=self.support)) + ['import Draft', + 'points='+pts, + 'Draft.makeBSpline(points,closed='+str(closed)+',face='+fil+',support='+sup+')']) except: print "Draft: error delaying commit" if self.ui: self.bsplinetrack.finalize() self.constraintrack.finalize() Creator.finish(self) - if cont and self.ui: + if self.ui: if self.ui.continueMode: self.Activated() @@ -679,10 +751,11 @@ class Rectangle(Creator): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Rectangle", "Creates a 2-point rectangle. CTRL to snap")} def Activated(self): - Creator.Activated(self,"Rectangle") + name = str(translate("draft","Rectangle")) + Creator.Activated(self,name) if self.ui: self.refpoint = None - self.ui.pointUi() + self.ui.pointUi(name) self.ui.extUi() self.call = self.view.addEventCallback("SoEvent",self.action) self.rect = rectangleTracker() @@ -694,7 +767,7 @@ class Rectangle(Creator): if self.ui: self.rect.off() self.rect.finalize() - if cont and self.ui: + if self.ui: if self.ui.continueMode: self.Activated() @@ -703,18 +776,21 @@ class Rectangle(Creator): p1 = self.node[0] p3 = self.node[-1] diagonal = p3.sub(p1) - p2 = p1.add(fcvec.project(diagonal, plane.v)) - p4 = p1.add(fcvec.project(diagonal, plane.u)) + p2 = p1.add(DraftVecUtils.project(diagonal, plane.v)) + p4 = p1.add(DraftVecUtils.project(diagonal, plane.u)) length = p4.sub(p1).Length - if abs(fcvec.angle(p4.sub(p1),plane.u,plane.axis)) > 1: length = -length + if abs(DraftVecUtils.angle(p4.sub(p1),plane.u,plane.axis)) > 1: length = -length height = p2.sub(p1).Length - if abs(fcvec.angle(p2.sub(p1),plane.v,plane.axis)) > 1: height = -height - p = plane.getRotation() - p.move(p1) + if abs(DraftVecUtils.angle(p2.sub(p1),plane.v,plane.axis)) > 1: height = -height try: + # building command string + rot,sup,pts,fil = self.getStrings() self.commit(translate("draft","Create Rectangle"), - partial(Draft.makeRectangle,length,height, - p,self.ui.fillmode,support=self.support)) + ['import Draft', + 'pl=FreeCAD.Placement()', + 'pl.Rotation.Q='+rot, + 'pl.Base='+DraftVecUtils.toString(p1), + 'Draft.makeRectangle(length='+str(length)+',height='+str(height)+',placement=pl,face='+fil+',support='+sup+')']) except: print "Draft: error delaying commit" self.finish(cont=True) @@ -725,7 +801,7 @@ class Rectangle(Creator): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - point,ctrlPoint = getPoint(self,arg,mobile=True) + point,ctrlPoint,info = getPoint(self,arg,mobile=True) self.rect.update(point) self.ui.cross(True) elif arg["Type"] == "SoMouseButtonEvent": @@ -733,8 +809,9 @@ class Rectangle(Creator): if (arg["Position"] == self.pos): self.finish() else: - if not self.node: self.support = getSupport(arg) - point,ctrlPoint = getPoint(self,arg) + if (not self.node) and (not self.support): + self.support = getSupport(arg) + point,ctrlPoint,info = getPoint(self,arg) self.appendPoint(point) def numericInput(self,numx,numy,numz): @@ -752,7 +829,8 @@ class Rectangle(Creator): self.ui.setRelative() self.rect.setorigin(point) self.rect.on() - self.planetrack.set(point) + if self.planetrack: + self.planetrack.set(point) class Arc(Creator): @@ -795,7 +873,7 @@ class Arc(Creator): self.constraintrack.finalize() self.arctrack.finalize() self.doc.recompute() - if cont and self.ui: + if self.ui: if self.ui.continueMode: self.Activated() @@ -826,13 +904,13 @@ class Arc(Creator): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen self.ui.cross(True) - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center if hasMod(arg,MODALT): if not self.altdown: @@ -846,37 +924,36 @@ class Arc(Creator): self.ui.switchUi(False) elif (self.step == 1): # choose radius if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) if hasMod(arg,MODALT): if not self.altdown: self.ui.cross(False) self.altdown = True - snapped = self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) - if snapped: - ob = self.doc.getObject(snapped['Object']) - num = int(snapped['Component'].lstrip('Edge'))-1 + if info: + ob = self.doc.getObject(info['Object']) + num = int(info['Component'].lstrip('Edge'))-1 ed = ob.Shape.Edges[num] if len(self.tangents) == 2: - cir = fcgeo.circleFrom3tan(self.tangents[0], self.tangents[1], ed) - cl = fcgeo.findClosestCircle(point,cir) + cir = DraftGeomUtils.circleFrom3tan(self.tangents[0], self.tangents[1], ed) + cl = DraftGeomUtils.findClosestCircle(point,cir) self.center = cl.Center self.rad = cl.Radius self.arctrack.setCenter(self.center) else: - self.rad = self.center.add(fcgeo.findDistance(self.center,ed).sub(self.center)).Length + self.rad = self.center.add(DraftGeomUtils.findDistance(self.center,ed).sub(self.center)).Length else: - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) else: if self.altdown: self.ui.cross(True) self.altdown = False - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) self.ui.setRadiusValue(self.rad) self.arctrack.setRadius(self.rad) # Draw constraint tracker line. @@ -890,11 +967,11 @@ class Arc(Creator): self.linetrack.p2(point) self.linetrack.on() elif (self.step == 2): # choose first angle - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if currentrad != 0: - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 - self.linetrack.p2(fcvec.scaleTo(point.sub(self.center),self.rad).add(self.center)) + self.linetrack.p2(DraftVecUtils.scaleTo(point.sub(self.center),self.rad).add(self.center)) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): self.constraintrack.p1(point) @@ -905,11 +982,11 @@ class Arc(Creator): self.ui.setRadiusValue(math.degrees(angle)) self.firstangle = angle else: # choose second angle - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if currentrad != 0: - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 - self.linetrack.p2(fcvec.scaleTo(point.sub(self.center),self.rad).add(self.center)) + self.linetrack.p2(DraftVecUtils.scaleTo(point.sub(self.center),self.rad).add(self.center)) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): self.constraintrack.p1(point) @@ -923,14 +1000,15 @@ class Arc(Creator): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center - self.support = getSupport(arg) + if not self.support: + self.support = getSupport(arg) if hasMod(arg,MODALT): snapped=self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) if snapped: @@ -958,7 +1036,8 @@ class Arc(Creator): self.step = 1 self.linetrack.on() msg(translate("draft", "Pick radius:\n")) - self.planetrack.set(point) + if self.planetrack: + self.planetrack.set(point) elif (self.step == 1): # choose radius if self.closedCircle: self.ui.cross(False) @@ -973,7 +1052,7 @@ class Arc(Creator): self.ui.labelRadius.setText("Aperture") self.step = 3 # scale center->point vector for proper display - u = fcvec.scaleTo(point.sub(self.center), self.rad) + u = DraftVecUtils.scaleTo(point.sub(self.center), self.rad) self.arctrack.setStartAngle(self.firstangle) msg(translate("draft", "Pick aperture:\n")) else: # choose second angle @@ -982,23 +1061,30 @@ class Arc(Creator): def drawArc(self): "actually draws the FreeCAD object" - p = plane.getRotation() - p.move(self.center) + rot,sup,pts,fil = self.getStrings() if self.closedCircle: try: - self.commit(translate("draft","Create Circle"), - partial(Draft.makeCircle,self.rad,p, - self.ui.fillmode,support=self.support)) + # building command string + self.commit(translate("draft","Create Circle"), + ['import Draft', + 'pl=FreeCAD.Placement()', + 'pl.Rotation.Q='+rot, + 'pl.Base='+DraftVecUtils.toString(self.center), + 'Draft.makeCircle(radius='+str(self.rad)+',placement=pl,face='+fil+',support='+sup+')']) except: - print "Draft: error delaying commit" + print "Draft: error delaying commit" else: sta = math.degrees(self.firstangle) end = math.degrees(self.firstangle+self.angle) if end < sta: sta,end = end,sta try: - self.commit(translate("draft","Create Arc"), - partial(Draft.makeCircle,self.rad,p,self.ui.fillmode, - sta,end,support=self.support)) + # building command string + self.commit(translate("draft","Create Arc"), + ['import Draft', + 'pl=FreeCAD.Placement()', + 'pl.Rotation.Q='+rot, + 'pl.Base='+DraftVecUtils.toString(self.center), + 'Draft.makeCircle(radius='+str(self.rad)+',placement=pl,face='+fil+',startangle='+str(sta)+',endangle='+str(end)+',support='+sup+')']) except: print "Draft: error delaying commit" self.finish(cont=True) @@ -1019,15 +1105,15 @@ class Arc(Creator): if (self.step == 1): self.rad = rad if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) + cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) + cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center if self.closedCircle: @@ -1044,9 +1130,9 @@ class Arc(Creator): elif (self.step == 2): self.ui.labelRadius.setText(str(translate("draft", "Aperture"))) self.firstangle = math.radians(rad) - if fcvec.equals(plane.axis, Vector(1,0,0)): u = Vector(0,self.rad,0) - else: u = fcvec.scaleTo(Vector(1,0,0).cross(plane.axis), self.rad) - urotated = fcvec.rotate(u, math.radians(rad), plane.axis) + if DraftVecUtils.equals(plane.axis, Vector(1,0,0)): u = Vector(0,self.rad,0) + else: u = DraftVecUtils.scaleTo(Vector(1,0,0).cross(plane.axis), self.rad) + urotated = DraftVecUtils.rotate(u, math.radians(rad), plane.axis) self.arctrack.setStartAngle(self.firstangle) self.step = 3 self.ui.radiusValue.setText("") @@ -1083,14 +1169,15 @@ class Polygon(Creator): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Polygon", "Creates a regular polygon. CTRL to snap, SHIFT to constrain")} def Activated(self): - Creator.Activated(self,"Polygon") + name = str(translate("draft","Polygon")) + Creator.Activated(self,name) if self.ui: self.step = 0 self.center = None self.rad = None self.tangents = [] self.tanpoints = [] - self.ui.pointUi() + self.ui.pointUi(name) self.ui.extUi() self.ui.numFaces.show() self.altdown = False @@ -1109,7 +1196,6 @@ class Polygon(Creator): self.constraintrack.finalize() self.arctrack.finalize() self.doc.recompute() - if cont and self.ui: if self.ui.continueMode: self.Activated() @@ -1119,13 +1205,13 @@ class Polygon(Creator): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen self.ui.cross(True) - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center if hasMod(arg,MODALT): if not self.altdown: @@ -1139,12 +1225,12 @@ class Polygon(Creator): self.ui.switchUi(False) else: # choose radius if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom2tan1pt(self.tangents[0], self.tangents[1], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) - self.center = fcgeo.findClosestCircle(point,cir).Center + cir = DraftGeomUtils.circleFrom1tan2pt(self.tangents[0], self.tanpoints[0], point) + self.center = DraftGeomUtils.findClosestCircle(point,cir).Center self.arctrack.setCenter(self.center) if hasMod(arg,MODALT): if not self.altdown: @@ -1156,20 +1242,20 @@ class Polygon(Creator): num = int(snapped['Component'].lstrip('Edge'))-1 ed = ob.Shape.Edges[num] if len(self.tangents) == 2: - cir = fcgeo.circleFrom3tan(self.tangents[0], self.tangents[1], ed) - cl = fcgeo.findClosestCircle(point,cir) + cir = DraftGeomUtils.circleFrom3tan(self.tangents[0], self.tangents[1], ed) + cl = DraftGeomUtils.findClosestCircle(point,cir) self.center = cl.Center self.rad = cl.Radius self.arctrack.setCenter(self.center) else: - self.rad = self.center.add(fcgeo.findDistance(self.center,ed).sub(self.center)).Length + self.rad = self.center.add(DraftGeomUtils.findDistance(self.center,ed).sub(self.center)).Length else: - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) else: if self.altdown: self.ui.cross(True) self.altdown = False - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) self.ui.setRadiusValue(self.rad) self.arctrack.setRadius(self.rad) # Draw constraint tracker line. @@ -1184,14 +1270,15 @@ class Polygon(Creator): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) # this is to make sure radius is what you see on screen - if self.center and fcvec.dist(point,self.center) > 0: - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center) > 0: + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): # choose center - if not self.node: self.support = getSupport(arg) + if (not self.node) and (not self.support): + self.support = getSupport(arg) if hasMod(arg,MODALT): snapped=self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) if snapped: @@ -1219,18 +1306,22 @@ class Polygon(Creator): self.step = 1 self.linetrack.on() msg(translate("draft", "Pick radius:\n")) - self.planetrack.set(point) + if self.planetrack: + self.planetrack.set(point) elif (self.step == 1): # choose radius self.ui.cross(False) self.drawPolygon() def drawPolygon(self): "actually draws the FreeCAD object" - p = plane.getRotation() - p.move(self.center) + rot,sup,pts,fil = self.getStrings() + # building command string self.commit(translate("draft","Create Polygon"), - partial(Draft.makePolygon,self.ui.numFaces.value(),self.rad, - True,p,face=self.ui.fillmode,support=self.support)) + ['import Draft', + 'pl=FreeCAD.Placement()', + 'pl.Rotation.Q='+rot, + 'pl.Base='+DraftVecUtils.toString(self.center), + 'Draft.makePolygon('+str(self.ui.numFaces.value())+',radius='+str(self.rad)+',inscribed=True,placement=pl,face='+fil+',support='+sup+')']) self.finish(cont=True) def numericInput(self,numx,numy,numz): @@ -1248,15 +1339,15 @@ class Polygon(Creator): "this function gets called by the toolbar when valid radius have been entered there" self.rad = rad if len(self.tangents) == 2: - cir = fcgeo.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) + cir = DraftGeomUtils.circleFrom2tan1rad(self.tangents[0], self.tangents[1], rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center elif self.tangents and self.tanpoints: - cir = fcgeo.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) + cir = DraftGeomUtils.circleFrom1tan1pt1rad(self.tangents[0],self.tanpoints[0],rad) if self.center: - self.center = fcgeo.findClosestCircle(self.center,cir).Center + self.center = DraftGeomUtils.findClosestCircle(self.center,cir).Center else: self.center = cir[-1].Center self.drawPolygon() @@ -1272,12 +1363,13 @@ class Text(Creator): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Text", "Creates an annotation. CTRL to snap")} def Activated(self): - Creator.Activated(self,"Text") + name = str(translate("draft","Text")) + Creator.Activated(self,name) if self.ui: self.dialog = None self.text = '' self.ui.sourceCmd = self - self.ui.pointUi() + self.ui.pointUi(name) self.call = self.view.addEventCallback("SoEvent",self.action) self.ui.xValue.setFocus() self.ui.xValue.selectAll() @@ -1289,14 +1381,21 @@ class Text(Creator): Creator.finish(self) if self.ui: del self.dialog - if cont and self.ui: if self.ui.continueMode: self.Activated() def createObject(self): "creates an object in the current doc" + tx = '[' + for l in self.text: + if len(tx) > 1: + tx += ',' + tx += '"'+str(l)+'"' + tx += ']' self.commit(translate("draft","Create Text"), - partial(Draft.makeText,self.text,self.node[0])) + ['import Draft', + 'Draft.makeText('+tx+',point='+DraftVecUtils.toString(self.node[0])+')']) + self.finish(cont=True) def action(self,arg): @@ -1305,10 +1404,10 @@ class Text(Creator): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,dtrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.node.append(point) self.ui.textUi() self.ui.textValue.setFocus() @@ -1339,19 +1438,20 @@ class Dimension(Creator): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Dimension", "Creates a dimension. CTRL to snap, SHIFT to constrain, ALT to select a segment")} def Activated(self): + name = str(translate("draft","Dimension")) if self.cont: self.finish() elif self.hasMeasures(): - Creator.Activated(self,"Dimension") + Creator.Activated(self,name) self.dimtrack = dimTracker() self.arctrack = arcTracker() self.constraintrack = lineTracker(dotted=True) self.createOnMeasures() self.finish() else: - Creator.Activated(self,"Dimension") + Creator.Activated(self,name) if self.ui: - self.ui.pointUi() + self.ui.pointUi(name) self.ui.continueCmd.show() self.altdown = False self.call = self.view.addEventCallback("SoEvent",self.action) @@ -1397,28 +1497,28 @@ class Dimension(Creator): pt = o.ViewObject.RootNode.getChildren()[1].getChildren()[0].getChildren()[0].getChildren()[3] p3 = Vector(pt.point.getValues()[2].getValue()) self.commit(translate("draft","Create Dimension"), - partial(Draft.makeDimension,p1,p2,p3)) - self.commit(translate("draft","Delete Measurement"), - partial(FreeCAD.ActiveDocument.removeObject,o.Name)) + ['import Draft', + 'Draft.makeDimension('+DraftVecUtils.toString(p1)+','+DraftVecUtils.toString(p2)+','+DraftVecUtils.toString(p3)+')', + 'FreeCAD.ActiveDocument.removeObject("'+o.Name+'")']) def createObject(self): "creates an object in the current doc" if self.angledata: self.commit(translate("draft","Create Dimension"), - partial(Draft.makeAngularDimension,self.center, - self.angledata,self.node[-1])) + ['import Draft', + 'Draft.makeAngularDimension(center='+DraftVecUtils.toString(self.center)+',angles=['+str(self.angledata[0])+','+str(self.angledata[1])+'],p3='+DraftVecUtils.toString(self.node[-1])+')']) elif self.link and (not self.arcmode): self.commit(translate("draft","Create Dimension"), - partial(Draft.makeDimension,self.link[0],self.link[1], - self.link[2],self.node[2])) + ['import Draft', + 'Draft.makeDimension(FreeCAD.ActiveDocument.'+self.link[0].Name+','+str(self.link[1])+','+str(self.link[2])+','+DraftVecUtils.toString(self.node[2])+')']) elif self.arcmode: self.commit(translate("draft","Create Dimension"), - partial(Draft.makeDimension,self.link[0],self.link[1], - self.arcmode,self.node[2])) + ['import Draft', + 'Draft.makeDimension(FreeCAD.ActiveDocument.'+self.link[0].Name+','+str(self.link[1])+',"'+str(self.arcmode)+'",'+DraftVecUtils.toString(self.node[2])+')']) else: self.commit(translate("draft","Create Dimension"), - partial(Draft.makeDimension,self.node[0],self.node[1], - self.node[2])) + ['import Draft', + 'Draft.makeDimension('+DraftVecUtils.toString(self.node[0])+','+DraftVecUtils.toString(self.node[1])+','+DraftVecUtils.toString(self.node[2])+')']) if self.ui.continueMode: self.cont = self.node[2] if not self.dir: @@ -1440,7 +1540,7 @@ class Dimension(Creator): shift = hasMod(arg,MODCONSTRAIN) if self.arcmode or self.point2: setMod(arg,MODCONSTRAIN,False) - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.ui.cross(True) if hasMod(arg,MODALT) and (len(self.node)<3): self.ui.cross(False) @@ -1467,7 +1567,7 @@ class Dimension(Creator): r = point.sub(self.center) self.arctrack.setRadius(r.Length) a = self.arctrack.getAngle(point) - pair = fcgeo.getBoundaryAngles(a,self.pts) + pair = DraftGeomUtils.getBoundaryAngles(a,self.pts) if not (pair[0] < a < pair[1]): self.angledata = [4*math.pi-pair[0],2*math.pi-pair[1]] else: @@ -1478,14 +1578,14 @@ class Dimension(Creator): self.altdown = False self.ui.switchUi(False) if self.dir: - point = self.node[0].add(fcvec.project(point.sub(self.node[0]),self.dir)) + point = self.node[0].add(DraftVecUtils.project(point.sub(self.node[0]),self.dir)) if len(self.node) == 2: if self.arcmode and self.edges: cen = self.edges[0].Curve.Center rad = self.edges[0].Curve.Radius baseray = point.sub(cen) - v2 = fcvec.scaleTo(baseray,rad) - v1 = fcvec.neg(v2) + v2 = DraftVecUtils.scaleTo(baseray,rad) + v1 = DraftVecUtils.neg(v2) if shift: self.node = [cen,cen.add(v2)] self.arcmode = "radius" @@ -1524,14 +1624,15 @@ class Dimension(Creator): self.dimtrack.update(self.node+[point]+[self.cont]) elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,ctrlPoint = getPoint(self,arg) - if not self.node: self.support = getSupport(arg) + point,ctrlPoint,info = getPoint(self,arg) + if (not self.node) and (not self.support): + self.support = getSupport(arg) if hasMod(arg,MODALT) and (len(self.node)<3): - snapped = self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) - if snapped: - ob = self.doc.getObject(snapped['Object']) - if 'Edge' in snapped['Component']: - num = int(snapped['Component'].lstrip('Edge'))-1 + print "snapped: ",info + if info: + ob = self.doc.getObject(info['Object']) + if 'Edge' in info['Component']: + num = int(info['Component'].lstrip('Edge'))-1 ed = ob.Shape.Edges[num] v1 = ed.Vertexes[0].Point v2 = ed.Vertexes[-1].Point @@ -1556,7 +1657,7 @@ class Dimension(Creator): # there is already a snapped edge, so we start angular dimension self.edges.append(ed) self.node.extend([v1,v2]) # self.node now has the 4 endpoints - c = fcgeo.findIntersection(self.node[0], + c = DraftGeomUtils.findIntersection(self.node[0], self.node[1], self.node[2], self.node[3], @@ -1575,14 +1676,16 @@ class Dimension(Creator): self.dimtrack.on() else: if self.dir: - point = self.node[0].add(fcvec.project(point.sub(self.node[0]),self.dir)) + point = self.node[0].add(DraftVecUtils.project(point.sub(self.node[0]),self.dir)) self.node.append(point) + #print "node",self.node self.dimtrack.update(self.node) if (len(self.node) == 2): self.point2 = self.node[1] if (len(self.node) == 1): self.dimtrack.on() - self.planetrack.set(self.node[0]) + if self.planetrack: + self.planetrack.set(self.node[0]) elif (len(self.node) == 2) and self.cont: self.node.append(self.cont) self.createObject() @@ -1591,7 +1694,7 @@ class Dimension(Creator): # for unlinked arc mode: # if self.arcmode: # v = self.node[1].sub(self.node[0]) - # v = fcvec.scale(v,0.5) + # v = DraftVecUtils.scale(v,0.5) # cen = self.node[0].add(v) # self.node = [self.node[0],self.node[1],cen] self.createObject() @@ -1617,73 +1720,17 @@ class Dimension(Creator): # Modifier functions #--------------------------------------------------------------------------- -class Modifier: +class Modifier(DraftTool): "A generic Modifier Tool, used by modification tools such as move" - - def __init__(self): - self.commitList = [] + def __init__(self): + DraftTool.__init__(self) + def IsActive(self): if Draft.getSelection(): return True else: return False - - def Activated(self,name="None"): - if FreeCAD.activeDraftCommand: - FreeCAD.activeDraftCommand.finish() - global Part, fcgeo - import Part - from draftlibs import fcgeo - self.ui = None - self.call = None - self.commitList = [] - self.doc = FreeCAD.ActiveDocument - if not self.doc: - self.finish() - else: - FreeCAD.activeDraftCommand = self - self.view = FreeCADGui.ActiveDocument.ActiveView - self.ui = FreeCADGui.draftToolBar - FreeCADGui.draftToolBar.show() - rot = self.view.getCameraNode().getField("orientation").getValue() - upv = Vector(rot.multVec(coin.SbVec3f(0,1,0)).getValue()) - plane.setup(fcvec.neg(self.view.getViewDirection()), Vector(0,0,0), upv) - self.node = [] - self.ui.sourceCmd = self - self.constrain = None - self.obj = None - self.extendedCopy = False - self.ui.setTitle(name) - self.featureName = name - #self.snap = snapTracker() - #self.extsnap = lineTracker(dotted=True) - self.planetrack = PlaneTracker() - - def finish(self): - self.node = [] - #self.snap.finalize() - #self.extsnap.finalize() - FreeCAD.activeDraftCommand = None - if self.ui: - self.ui.offUi() - self.ui.sourceCmd=None - self.ui.cross(False) - msg("") - self.planetrack.finalize() - FreeCADGui.Snapper.off() - if self.call: - self.view.removeEventCallback("SoEvent",self.call) - self.call = None - if self.commitList: - todo.delayCommit(self.commitList) - self.commitList = [] - - def commit(self,name,func): - "stores partial actions to be committed to the FreeCAD document" - # print "committing" - self.commitList.append((name,func)) - class Move(Modifier): "The Draft_Move FreeCAD command definition" @@ -1695,7 +1742,8 @@ class Move(Modifier): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Move", "Moves the selected objects between 2 points. CTRL to snap, SHIFT to constrain, ALT to copy")} def Activated(self): - Modifier.Activated(self,"Move") + self.name = str(translate("draft","Move")) + Modifier.Activated(self,self.name) if self.ui: if not Draft.getSelection(): self.ghost = None @@ -1711,7 +1759,7 @@ class Move(Modifier): if self.call: self.view.removeEventCallback("SoEvent",self.call) self.sel = Draft.getSelection() self.sel = Draft.getGroupContents(self.sel) - self.ui.pointUi() + self.ui.pointUi(self.name) self.ui.modUi() self.ui.xValue.setFocus() self.ui.xValue.selectAll() @@ -1735,10 +1783,20 @@ class Move(Modifier): def move(self,delta,copy=False): "moving the real shapes" + sel = '[' + for o in self.sel: + if len(sel) > 1: + sel += ',' + sel += 'FreeCAD.ActiveDocument.'+o.Name + sel += ']' if copy: - self.commit(translate("draft","Copy"),partial(Draft.move,self.sel,delta,copy)) + self.commit(translate("draft","Copy"), + ['import Draft', + 'Draft.move('+sel+','+DraftVecUtils.toString(delta)+',copy='+str(copy)+')']) else: - self.commit(translate("draft","Move"),partial(Draft.move,self.sel,delta,copy)) + self.commit(translate("draft","Move"), + ['import Draft', + 'Draft.move('+sel+','+DraftVecUtils.toString(delta)+',copy='+str(copy)+')']) self.doc.recompute() def action(self,arg): @@ -1747,7 +1805,7 @@ class Move(Modifier): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.linetrack.p2(point) self.ui.cross(True) # Draw constraint tracker line. @@ -1764,7 +1822,7 @@ class Move(Modifier): if not hasMod(arg,MODALT): self.finish() elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) if (self.node == []): self.node.append(point) self.ui.isRelative.show() @@ -1772,7 +1830,8 @@ class Move(Modifier): self.ghost.on() self.linetrack.p1(point) msg(translate("draft", "Pick end point:\n")) - self.planetrack.set(point) + if self.planetrack: + self.planetrack.set(point) else: last = self.node[0] if self.ui.isCopy.isChecked() or hasMod(arg,MODALT): @@ -1823,19 +1882,21 @@ class ApplyStyle(Modifier): if self.ui: self.sel = Draft.getSelection() if (len(self.sel)>0): + c = ['import Draft'] for ob in self.sel: if (ob.Type == "App::DocumentObjectGroup"): - self.formatGroup(ob) + c.extend(self.formatGroup(ob)) else: - self.commit(translate("draft","Change Style"),partial(Draft.formatObject,ob)) + c.append('Draft.formatObject(FreeCAD.ActiveDocument.'+ob.Name+')') + self.commit(translate("draft","Change Style"),c) def formatGroup(self,grpob): + c=[] for ob in grpob.Group: if (ob.Type == "App::DocumentObjectGroup"): - self.formatGroup(ob) + c.extend(self.formatGroup(ob)) else: - self.commit(translate("draft","Change Style"),partial(Draft.formatObject,ob)) - + c.append('Draft.formatObject(FreeCAD.ActiveDocument.'+ob.Name+')') class Rotate(Modifier): "The Draft_Rotate FreeCAD command definition" @@ -1893,14 +1954,20 @@ class Rotate(Modifier): def rot (self,angle,copy=False): "rotating the real shapes" + sel = '[' + for o in self.sel: + if len(sel) > 1: + sel += ',' + sel += 'FreeCAD.ActiveDocument.'+o.Name + sel += ']' if copy: self.commit(translate("draft","Copy"), - partial(Draft.rotate,self.sel, - math.degrees(angle),self.center,plane.axis,copy)) + ['import Draft', + 'Draft.rotate('+sel+','+str(math.degrees(angle))+','+DraftVecUtils.toString(self.center)+',axis='+DraftVecUtils.toString(plane.axis)+',copy='+str(copy)+')']) else: self.commit(translate("draft","Rotate"), - partial(Draft.rotate,self.sel, - math.degrees(angle),self.center,plane.axis,copy)) + ['import Draft', + 'Draft.rotate('+sel+','+str(math.degrees(angle))+','+DraftVecUtils.toString(self.center)+',axis='+DraftVecUtils.toString(plane.axis)+',copy='+str(copy)+')']) def action(self,arg): "scene event handler" @@ -1908,13 +1975,13 @@ class Rotate(Modifier): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.ui.cross(True) # this is to make sure radius is what you see on screen - if self.center and fcvec.dist(point,self.center): - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): - point = point.add(fcvec.neg(viewdelta)) + if self.center and DraftVecUtils.dist(point,self.center): + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): + point = point.add(DraftVecUtils.neg(viewdelta)) if self.extendedCopy: if not hasMod(arg,MODALT): self.step = 3 @@ -1922,9 +1989,9 @@ class Rotate(Modifier): if (self.step == 0): pass elif (self.step == 1): - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if (currentrad != 0): - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 self.linetrack.p2(point) # Draw constraint tracker line. @@ -1939,16 +2006,16 @@ class Rotate(Modifier): self.ui.radiusValue.setFocus() self.ui.radiusValue.selectAll() elif (self.step == 2): - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) if (currentrad != 0): - angle = fcvec.angle(plane.u, point.sub(self.center), plane.axis) + angle = DraftVecUtils.angle(plane.u, point.sub(self.center), plane.axis) else: angle = 0 if (angle < self.firstangle): sweep = (2*math.pi-self.firstangle)+angle else: sweep = angle - self.firstangle self.arctrack.setApertureAngle(sweep) - self.ghost.trans.rotation.setValue(coin.SbVec3f(fcvec.tup(plane.axis)),sweep) + self.ghost.trans.rotation.setValue(coin.SbVec3f(DraftVecUtils.tup(plane.axis)),sweep) self.linetrack.p2(point) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): @@ -1963,10 +2030,10 @@ class Rotate(Modifier): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,ctrlPoint = getPoint(self,arg) - if self.center and fcvec.dist(point,self.center): - viewdelta = fcvec.project(point.sub(self.center), plane.axis) - if not fcvec.isNull(viewdelta): point = point.add(fcvec.neg(viewdelta)) + point,ctrlPoint,info = getPoint(self,arg) + if self.center and DraftVecUtils.dist(point,self.center): + viewdelta = DraftVecUtils.project(point.sub(self.center), plane.axis) + if not DraftVecUtils.isNull(viewdelta): point = point.add(DraftVecUtils.neg(viewdelta)) if (self.step == 0): self.center = point self.node = [point] @@ -1979,19 +2046,20 @@ class Rotate(Modifier): self.linetrack.on() self.step = 1 msg(translate("draft", "Pick base angle:\n")) - self.planetrack.set(point) + if self.planetrack: + self.planetrack.set(point) elif (self.step == 1): self.ui.labelRadius.setText("Rotation") - self.rad = fcvec.dist(point,self.center) + self.rad = DraftVecUtils.dist(point,self.center) self.arctrack.on() self.arctrack.setStartPoint(point) self.ghost.on() self.step = 2 msg(translate("draft", "Pick rotation angle:\n")) else: - currentrad = fcvec.dist(point,self.center) + currentrad = DraftVecUtils.dist(point,self.center) angle = point.sub(self.center).getAngle(plane.u) - if fcvec.project(point.sub(self.center), plane.v).getAngle(plane.v) > 1: + if DraftVecUtils.project(point.sub(self.center), plane.v).getAngle(plane.v) > 1: angle = -angle if (angle < self.firstangle): sweep = (2*math.pi-self.firstangle)+angle @@ -2095,7 +2163,8 @@ class Offset(Modifier): self.call = self.view.addEventCallback("SoEvent",self.action) msg(translate("draft", "Pick distance:\n")) self.ui.cross(True) - self.planetrack.set(self.shape.Vertexes[0].Point) + if self.planetrack: + self.planetrack.set(self.shape.Vertexes[0].Point) self.running = True def action(self,arg): @@ -2105,35 +2174,35 @@ class Offset(Modifier): self.finish() elif arg["Type"] == "SoLocation2Event": self.ui.cross(True) - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) if hasMod(arg,MODCONSTRAIN) and self.constrainSeg: - dist = fcgeo.findPerpendicular(point,self.shape,self.constrainSeg[1]) + dist = DraftGeomUtils.findPerpendicular(point,self.shape,self.constrainSeg[1]) e = self.shape.Edges[self.constrainSeg[1]] self.constraintrack.p1(e.Vertexes[0].Point) self.constraintrack.p2(point.add(dist[0])) self.constraintrack.on() else: - dist = fcgeo.findPerpendicular(point,self.shape.Edges) + dist = DraftGeomUtils.findPerpendicular(point,self.shape.Edges) self.constraintrack.off() if dist: self.ghost.on() if self.mode == "Wire": - d = fcvec.neg(dist[0]) - v1 = fcgeo.getTangent(self.shape.Edges[0],point) - v2 = fcgeo.getTangent(self.shape.Edges[dist[1]],point) - a = -fcvec.angle(v1,v2) - self.dvec = fcvec.rotate(d,a,plane.axis) + d = DraftVecUtils.neg(dist[0]) + v1 = DraftGeomUtils.getTangent(self.shape.Edges[0],point) + v2 = DraftGeomUtils.getTangent(self.shape.Edges[dist[1]],point) + a = -DraftVecUtils.angle(v1,v2) + self.dvec = DraftVecUtils.rotate(d,a,plane.axis) occmode = self.ui.occOffset.isChecked() - self.ghost.update(fcgeo.offsetWire(self.shape,self.dvec,occ=occmode),forceclosed=occmode) + self.ghost.update(DraftGeomUtils.offsetWire(self.shape,self.dvec,occ=occmode),forceclosed=occmode) elif self.mode == "BSpline": - d = fcvec.neg(dist[0]) + d = DraftVecUtils.neg(dist[0]) e = self.shape.Edges[0] - basetan = fcgeo.getTangent(e,point) + basetan = DraftGeomUtils.getTangent(e,point) self.npts = [] for p in self.sel.Points: - currtan = fcgeo.getTangent(e,p) - a = -fcvec.angle(currtan,basetan) - self.dvec = fcvec.rotate(d,a,plane.axis) + currtan = DraftGeomUtils.getTangent(e,p) + a = -DraftVecUtils.angle(currtan,basetan) + self.dvec = DraftVecUtils.rotate(d,a,plane.axis) self.npts.append(p.add(self.dvec)) self.ghost.update(self.npts) elif self.mode == "Circle": @@ -2161,13 +2230,18 @@ class Offset(Modifier): occmode = self.ui.occOffset.isChecked() if hasMod(arg,MODALT) or self.ui.isCopy.isChecked(): copymode = True if self.npts: + print "offset:npts=",self.npts self.commit(translate("draft","Offset"), - partial(Draft.offset,self.sel, - self.npts,copymode,occ=False)) + ['import Draft', + 'Draft.offset(FreeCAD.ActiveDocument.'+self.sel.Name+','+DraftVecUtils.toString(self.ntps)+',copy='+str(copymode)+')']) elif self.dvec: + if isinstance(self.dvec,float): + d = str(self.dvec) + else: + d = DraftVecUtils.toString(self.dvec) self.commit(translate("draft","Offset"), - partial(Draft.offset,self.sel, - self.dvec,copymode,occ=occmode)) + ['import Draft', + 'Draft.offset(FreeCAD.ActiveDocument.'+self.sel.Name+','+d+',copy='+str(copymode)+',occ='+str(occmode)+')']) if hasMod(arg,MODALT): self.extendedCopy = True else: @@ -2189,9 +2263,13 @@ class Offset(Modifier): copymode = False occmode = self.ui.occOffset.isChecked() if self.ui.isCopy.isChecked(): copymode = True + if isinstance(self.dvec,float): + d = str(self.dvec) + else: + d = DraftVecUtils.toString(self.dvec) self.commit(translate("draft","Offset"), - partial(Draft.offset,self.sel, - self.dvec,copymode,occ=occmode)) + ['import Draft', + 'Draft.offset(FreeCAD.ActiveDocument.'+self.sel.Name+','+d+',copy='+str(copymode)+',occ='+str(occmode)+')']) self.finish() @@ -2297,7 +2375,7 @@ class Upgrade(Modifier): newob = Draft.fuse(self.sel[0],self.sel[1]) self.nodelete = True - elif (len(self.sel) > 2) and (len(faces) > 10): + elif (len(self.sel) > 2) and (len(faces) > 6): # we have many separate faces: we try to make a shell sh = Part.makeShell(faces) newob = self.doc.addObject("Part::Feature","Shell") @@ -2309,13 +2387,14 @@ class Upgrade(Modifier): u = faces.pop(0) for f in faces: u = u.fuse(f) - if fcgeo.isCoplanar(faces): + if DraftGeomUtils.isCoplanar(faces): if self.sel[0].ViewObject.DisplayMode == "Wireframe": f = False else: f = True - u = fcgeo.concatenate(u) + u = DraftGeomUtils.concatenate(u) if not curves: + # several coplanar and non-curved faces: they can becoem a Draft wire msg(translate("draft", "Found several objects or faces: making a parametric face\n")) newob = Draft.makeWire(u.Wires[0],closed=True,face=f) Draft.formatObject(newob,lastob) @@ -2340,6 +2419,14 @@ class Upgrade(Modifier): if (not curves) and (Draft.getType(self.sel[0]) == "Part"): msg(translate("draft", "Found 1 non-parametric objects: draftifying it\n")) Draft.draftify(self.sel[0]) + else: + msg(translate("draft", "No upgrade available for this object\n")) + self.doc.abortTransaction() + return + else: + msg(translate("draft", "Couldn't upgrade these objects\n")) + self.doc.abortTransaction() + return elif wires and (not faces) and (not openwires): # we have only wires, no faces @@ -2355,51 +2442,63 @@ class Upgrade(Modifier): else: # only closed wires for w in wires: - f = Part.Face(w) - faces.append(f) - for f in faces: - if not curves: - newob = Draft.makeWire(f.Wire,closed=True) + if DraftGeomUtils.isPlanar(w): + f = Part.Face(w) + faces.append(f) else: - # if there are curved segments, we do a non-parametric face - msg(translate("draft", "Found closed wires: making faces\n")) - newob = self.doc.addObject("Part::Feature","Face") - newob.Shape = f - Draft.formatObject(newob,lastob) + msg(translate("draft", "One wire is not planar, upgrade not done\n")) + self.nodelete = True + for f in faces: + # if there are curved segments, we do a non-parametric face + msg(translate("draft", "Found a closed wire: making a face\n")) + newob = self.doc.addObject("Part::Feature","Face") + newob.Shape = f + Draft.formatObject(newob,lastob) + newob.ViewObject.DisplayMode = "Flat Lines" elif (len(openwires) == 1) and (not faces) and (not wires): - # special case, we have only one open wire. We close it!" + # special case, we have only one open wire. We close it, unless it has only 1 edge!" p0 = openwires[0].Vertexes[0].Point p1 = openwires[0].Vertexes[-1].Point edges = openwires[0].Edges - edges.append(Part.Line(p1,p0).toShape()) - w = Part.Wire(fcgeo.sortEdges(edges)) - msg(translate("draft", "Found 1 open wire: closing it\n")) - if not curves: - newob = Draft.makeWire(w,closed=True) + if len(edges) > 1: + edges.append(Part.Line(p1,p0).toShape()) + w = Part.Wire(DraftGeomUtils.sortEdges(edges)) + if len(edges) == 1: + if len(w.Vertexes) == 2: + msg(translate("draft", "Found 1 open edge: making a line\n")) + newob = Draft.makeWire(w,closed=False) + elif len(w.Vertexes) == 1: + msg(translate("draft", "Found 1 circular edge: making a circle\n")) + c = w.Edges[0].Curve.Center + r = w.Edges[0].Curve.Radius + p = FreeCAD.Placement() + p.move(c) + newob = Draft.makeCircle(r,p) else: - # if not possible, we do a non-parametric union - newob = self.doc.addObject("Part::Feature","Wire") - newob.Shape = w - Draft.formatObject(newob,lastob) - + msg(translate("draft", "Found 1 open wire: closing it\n")) + if not curves: + newob = Draft.makeWire(w,closed=True) + else: + # if not possible, we do a non-parametric union + newob = self.doc.addObject("Part::Feature","Wire") + newob.Shape = w + Draft.formatObject(newob,lastob) + elif openwires and (not wires) and (not faces): # only open wires and edges: we try to join their edges for ob in self.sel: for e in ob.Shape.Edges: edges.append(e) newob = None - nedges = fcgeo.sortEdges(edges[:]) + nedges = DraftGeomUtils.sortEdges(edges[:]) # for e in nedges: print "debug: ",e.Curve,e.Vertexes[0].Point,e.Vertexes[-1].Point w = Part.Wire(nedges) if len(w.Edges) == len(edges): msg(translate("draft", "Found several edges: wiring them\n")) - if not curves: - newob = Draft.makeWire(w) - else: - newob = self.doc.addObject("Part::Feature","Wire") - newob.Shape = w - Draft.formatObject(newob,lastob) + newob = self.doc.addObject("Part::Feature","Wire") + newob.Shape = w + Draft.formatObject(newob,lastob) if not newob: print "no new object found" msg(translate("draft", "Found several non-connected edges: making compound\n")) @@ -2467,7 +2566,7 @@ class Downgrade(Modifier): self.doc.openTransaction("Downgrade") if (len(self.sel) == 1) and (Draft.getType(self.sel[0]) == "Block"): - # a block, we explode it + # we have a block, we explode it pl = self.sel[0].Placement newob = [] for ob in self.sel[0].Components: @@ -2521,6 +2620,14 @@ class Downgrade(Modifier): else: # no faces: split wire into single edges + onlyedges = True + for ob in self.sel: + if ob.Shape.ShapeType != "Edge": + onlyedges = False + if onlyedges: + msg(translate("draft", "No more downgrade possible\n")) + self.doc.abortTransaction() + return msg(translate("draft", "Found only wires: extracting their edges\n")) for ob in self.sel: for e in edges: @@ -2594,7 +2701,7 @@ class Trimex(Modifier): self.extrudeMode = False if self.obj.Shape.Wires: self.edges = self.obj.Shape.Wires[0].Edges - self.edges = fcgeo.sortEdges(self.edges) + self.edges = DraftGeomUtils.sortEdges(self.edges) else: self.edges = self.obj.Shape.Edges self.ghost = [] @@ -2627,8 +2734,10 @@ class Trimex(Modifier): self.ui.cross(True) self.shift = hasMod(arg,MODCONSTRAIN) self.alt = hasMod(arg,MODALT) + if self.extrudeMode: + arg["ShiftDown"] = False wp = not(self.extrudeMode and self.shift) - self.point = getPoint(self,arg,workingplane=wp)[0] + self.point,cp,info = getPoint(self,arg,workingplane=wp) if hasMod(arg,MODSNAP): self.snapped = None else: self.snapped = self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) if self.extrudeMode: @@ -2656,7 +2765,7 @@ class Trimex(Modifier): "redraws the ghost in extrude mode" self.newpoint = self.obj.Shape.Faces[0].CenterOfMass dvec = self.point.sub(self.newpoint) - if shift: delta = fcvec.project(dvec,self.normal) + if not shift: delta = DraftVecUtils.project(dvec,self.normal) else: delta = dvec if self.force: ratio = self.force/delta.Length @@ -2682,7 +2791,7 @@ class Trimex(Modifier): for e in self.edges: vlist.append(e.Vertexes[0].Point) vlist.append(self.edges[-1].Vertexes[-1].Point) if shift: npoint = self.activePoint - else: npoint = fcgeo.findClosest(point,vlist) + else: npoint = DraftGeomUtils.findClosest(point,vlist) if npoint > len(self.edges)/2: reverse = True if alt: reverse = not reverse self.activePoint = npoint @@ -2707,16 +2816,16 @@ class Trimex(Modifier): snapped = self.doc.getObject(snapped['Object']) pts = [] for e in snapped.Shape.Edges: - int = fcgeo.findIntersection(edge,e,True,True) + int = DraftGeomUtils.findIntersection(edge,e,True,True) if int: pts.extend(int) if pts: - point = pts[fcgeo.findClosest(point,pts)] + point = pts[DraftGeomUtils.findClosest(point,pts)] # modifying active edge if isinstance(edge.Curve,Part.Line): - perp = fcgeo.vec(edge).cross(Vector(0,0,1)) + perp = DraftGeomUtils.vec(edge).cross(Vector(0,0,1)) chord = v1.sub(point) - proj = fcvec.project(chord,perp) + proj = DraftVecUtils.project(chord,perp) self.newpoint = Vector.add(point,proj) dist = v1.sub(self.newpoint).Length ghost.p1(self.newpoint) @@ -2725,15 +2834,15 @@ class Trimex(Modifier): if real: if self.force: ray = self.newpoint.sub(v1) - ray = fcvec.scale(ray,self.force/ray.Length) + ray = DraftVecUtils.scale(ray,self.force/ray.Length) self.newpoint = Vector.add(v1,ray) newedges.append(Part.Line(self.newpoint,v2).toShape()) else: center = edge.Curve.Center rad = edge.Curve.Radius - ang1 = fcvec.angle(v2.sub(center)) - ang2 = fcvec.angle(point.sub(center)) - self.newpoint=Vector.add(center,fcvec.rotate(Vector(rad,0,0),-ang2)) + ang1 = DraftVecUtils.angle(v2.sub(center)) + ang2 = DraftVecUtils.angle(point.sub(center)) + self.newpoint=Vector.add(center,DraftVecUtils.rotate(Vector(rad,0,0),-ang2)) self.ui.labelRadius.setText("Angle") dist = math.degrees(-ang2) # if ang1 > ang2: ang1,ang2 = ang2,ang1 @@ -2745,11 +2854,11 @@ class Trimex(Modifier): if real: if self.force: angle = math.radians(self.force) - newray = fcvec.rotate(Vector(rad,0,0),-angle) + newray = DraftVecUtils.rotate(Vector(rad,0,0),-angle) self.newpoint = Vector.add(center,newray) chord = self.newpoint.sub(v2) perp = chord.cross(Vector(0,0,1)) - scaledperp = fcvec.scaleTo(perp,rad) + scaledperp = DraftVecUtils.scaleTo(perp,rad) midpoint = Vector.add(center,scaledperp) newedges.append(Part.Arc(self.newpoint,midpoint,v2).toShape()) ghost.on() @@ -2764,8 +2873,8 @@ class Trimex(Modifier): ghost.p1(edge.Vertexes[0].Point) ghost.p2(edge.Vertexes[-1].Point) else: - ang1 = fcvec.angle(edge.Vertexes[0].Point.sub(center)) - ang2 = fcvec.angle(edge.Vertexes[-1].Point.sub(center)) + ang1 = DraftVecUtils.angle(edge.Vertexes[0].Point.sub(center)) + ang2 = DraftVecUtils.angle(edge.Vertexes[-1].Point.sub(center)) # if ang1 > ang2: ang1,ang2 = ang2,ang1 ghost.setEndAngle(-ang2) ghost.setStartAngle(-ang1) @@ -2841,7 +2950,8 @@ class Scale(Modifier): 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Draft_Scale", "Scales the selected objects from a base point. CTRL to snap, SHIFT to constrain, ALT to copy")} def Activated(self): - Modifier.Activated(self,"Scale") + self.name = str(translate("draft","Scale")) + Modifier.Activated(self,self.name) if self.ui: if not Draft.getSelection(): self.ghost = None @@ -2857,7 +2967,7 @@ class Scale(Modifier): if self.call: self.view.removeEventCallback("SoEvent",self.call) self.sel = Draft.getSelection() self.sel = Draft.getGroupContents(self.sel) - self.ui.pointUi() + self.ui.pointUi(self.name) self.ui.modUi() self.ui.xValue.setFocus() self.ui.xValue.selectAll() @@ -2881,12 +2991,20 @@ class Scale(Modifier): def scale(self,delta,copy=False): "moving the real shapes" + sel = '[' + for o in self.sel: + if len(sel) > 1: + sel += ',' + sel += 'FreeCAD.ActiveDocument.'+o.Name + sel += ']' if copy: self.commit(translate("draft","Copy"), - partial(Draft.scale,self.sel,delta,self.node[0],copy)) + ['import Draft', + 'Draft.scale('+sel+',delta='+DraftVecUtils.toString(delta)+',center='+DraftVecUtils.toString(self.node[0])+',copy='+str(copy)+')']) else: self.commit(translate("draft","Scale"), - partial(Draft.scale,self.sel,delta,self.node[0],copy)) + ['import Draft', + 'Draft.scale('+sel+',delta='+DraftVecUtils.toString(delta)+',center='+DraftVecUtils.toString(self.node[0])+',copy='+str(copy)+')']) def action(self,arg): "scene event handler" @@ -2894,7 +3012,7 @@ class Scale(Modifier): if arg["Key"] == "ESCAPE": self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection - point,ctrlPoint = getPoint(self,arg,sym=True) + point,ctrlPoint,info = getPoint(self,arg,sym=True) self.linetrack.p2(point) self.ui.cross(True) # Draw constraint tracker line. @@ -2909,13 +3027,13 @@ class Scale(Modifier): self.ghost.trans.scaleFactor.setValue([delta.x,delta.y,delta.z]) corr = Vector(self.node[0].x,self.node[0].y,self.node[0].z) corr.scale(delta.x,delta.y,delta.z) - corr = fcvec.neg(corr.sub(self.node[0])) + corr = DraftVecUtils.neg(corr.sub(self.node[0])) self.ghost.trans.translation.setValue([corr.x,corr.y,corr.z]) if self.extendedCopy: if not hasMod(arg,MODALT): self.finish() elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): - point,ctrlPoint = getPoint(self,arg,sym=True) + point,ctrlPoint,info = getPoint(self,arg,sym=True) if (self.node == []): self.node.append(point) self.ui.isRelative.show() @@ -3091,10 +3209,10 @@ class Edit(Modifier): if hasattr(self.obj.ViewObject,"Selectable"): self.selectstate = self.obj.ViewObject.Selectable self.obj.ViewObject.Selectable = False - if not Draft.getType(self.obj) in ["Wire","BSpline"]: - self.ui.setEditButtons(False) - else: + if Draft.getType(self.obj) in ["Wire","BSpline"]: self.ui.setEditButtons(True) + else: + self.ui.setEditButtons(False) self.editing = None self.editpoints = [] self.pl = None @@ -3114,9 +3232,9 @@ class Edit(Modifier): self.editpoints.append(self.obj.Shape.Vertexes[2].Point) v = self.obj.Shape.Vertexes self.bx = v[1].Point.sub(v[0].Point) - if self.obj.Length < 0: self.bx = fcvec.neg(self.bx) + if self.obj.Length < 0: self.bx = DraftVecUtils.neg(self.bx) self.by = v[2].Point.sub(v[1].Point) - if self.obj.Height < 0: self.by = fcvec.neg(self.by) + if self.obj.Height < 0: self.by = DraftVecUtils.neg(self.by) elif Draft.getType(self.obj) == "Polygon": self.editpoints.append(self.obj.Placement.Base) self.editpoints.append(self.obj.Shape.Vertexes[0].Point) @@ -3132,12 +3250,13 @@ class Edit(Modifier): for ep in range(len(self.editpoints)): self.trackers.append(editTracker(self.editpoints[ep],self.obj.Name, ep,self.obj.ViewObject.LineColor)) - self.constraintrack = lineTracker(dotted=True) - self.call = self.view.addEventCallback("SoEvent",self.action) - self.running = True - plane.save() - if "Shape" in self.obj.PropertiesList: - plane.alignToFace(self.obj.Shape) + self.constraintrack = lineTracker(dotted=True) + self.call = self.view.addEventCallback("SoEvent",self.action) + self.running = True + plane.save() + if "Shape" in self.obj.PropertiesList: + plane.alignToFace(self.obj.Shape) + if self.planetrack: self.planetrack.set(self.editpoints[0]) else: msg(translate("draft", "This object type is not editable\n"),'warning') @@ -3170,7 +3289,7 @@ class Edit(Modifier): self.finish() elif arg["Type"] == "SoLocation2Event": #mouse movement detection if self.editing != None: - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) # Draw constraint tracker line. if hasMod(arg,MODCONSTRAIN): self.constraintrack.p1(point) @@ -3183,27 +3302,27 @@ class Edit(Modifier): elif arg["Type"] == "SoMouseButtonEvent": if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"): if self.editing == None: - snapped = self.view.getObjectInfo((arg["Position"][0],arg["Position"][1])) - if snapped: - if snapped['Object'] == self.obj.Name: + sel = FreeCADGui.Selection.getSelectionEx() + if sel: + sel = sel[0] + if sel.ObjectName == self.obj.Name: if self.ui.addButton.isChecked(): - point,ctrlPoint = getPoint(self,arg) + point,ctrlPoint,info = getPoint(self,arg) self.pos = arg["Position"] self.addPoint(point) elif self.ui.delButton.isChecked(): - if 'EditNode' in snapped['Component']: - self.delPoint(int(snapped['Component'][8:])) - elif 'EditNode' in snapped['Component']: + if 'EditNode' in sel.SubElementNames[0]: + self.delPoint(int(sel.SubElementNames[0][8:])) + elif 'EditNode' in sel.SubElementNames[0]: self.ui.pointUi() self.ui.isRelative.show() - self.editing = int(snapped['Component'][8:]) + self.editing = int(sel.SubElementNames[0][8:]) self.trackers[self.editing].off() if hasattr(self.obj.ViewObject,"Selectable"): self.obj.ViewObject.Selectable = False if "Points" in self.obj.PropertiesList: self.node.append(self.obj.Points[self.editing]) else: - print "finishing edit" self.trackers[self.editing].on() if hasattr(self.obj.ViewObject,"Selectable"): self.obj.ViewObject.Selectable = True @@ -3240,8 +3359,8 @@ class Edit(Modifier): self.obj.Placement = p elif self.editing == 1: diag = v.sub(self.obj.Placement.Base) - nx = fcvec.project(diag,self.bx) - ny = fcvec.project(diag,self.by) + nx = DraftVecUtils.project(diag,self.bx) + ny = DraftVecUtils.project(diag,self.by) ax = nx.Length ay = ny.Length if ax and ay: @@ -3612,7 +3731,7 @@ class Point: return False def Activated(self): - self.view = FreeCADGui.ActiveDocument.ActiveView + self.view = Draft.get3DView() self.stack = [] self.point = None # adding 2 callback functions @@ -3642,14 +3761,71 @@ class ToggleSnap(): "The ToggleSnap FreeCAD command definition" def GetResources(self): - return {'Pixmap' : 'Draft_Snap', + return {'Pixmap' : 'Snap_Lock', + 'Accel' : "Shift+S", 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_ToggleSnap", "Toggle snap"), 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_ToggleSnap", "Toggles Draft snap on or off")} def Activated(self): if hasattr(FreeCADGui,"Snapper"): - FreeCADGui.Snapper.active = not FreeCADGui.Snapper.active - + FreeCADGui.Snapper.toggle() + +class ShowSnapBar(): + "The ShowSnapBar FreeCAD command definition" + + def GetResources(self): + return {'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_ShowSnapBar", "Show Snap Bar"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_ShowSnapBar", "Shows Draft snap toolbar")} + + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.show() + + +class Draft_Clone(): + "The Draft Clone command definition" + + def GetResources(self): + return {'Pixmap' : 'Draft_Clone', + 'Accel' : "C,L", + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_Clone", "Clone"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_Clone", "Clones the selected object(s)")} + + def Activated(self): + if FreeCADGui.Selection.getSelection(): + FreeCAD.ActiveDocument.openTransaction("Clone") + for obj in FreeCADGui.Selection.getSelection(): + Draft.clone(obj) + FreeCAD.ActiveDocument.commitTransaction() + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False + + +class ToggleGrid(): + "The Draft ToggleGrid command definition" + + def GetResources(self): + return {'Pixmap' : 'Snap_Grid', + 'Accel' : "G,R", + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Draft_ToggleGrid", "Toggle Grid"), + 'ToolTip' : QtCore.QT_TRANSLATE_NOOP("Draft_ToggleGrid", "Toggles the Draft gid on/off")} + + def Activated(self): + if hasattr(FreeCADGui,"Snapper"): + if FreeCADGui.Snapper.grid: + if FreeCADGui.Snapper.grid.Visible: + FreeCADGui.Snapper.grid.off() + FreeCADGui.Snapper.forceGridOff=True + else: + FreeCADGui.Snapper.grid.on() + FreeCADGui.Snapper.forceGridOff=False + else: + FreeCADGui.Snapper.show() + #--------------------------------------------------------------------------- # Adds the icons & commands to the FreeCAD command manager, and sets defaults #--------------------------------------------------------------------------- @@ -3682,6 +3858,7 @@ FreeCADGui.addCommand('Draft_DelPoint',DelPoint()) FreeCADGui.addCommand('Draft_WireToBSpline',WireToBSpline()) FreeCADGui.addCommand('Draft_Draft2Sketch',Draft2Sketch()) FreeCADGui.addCommand('Draft_Array',Array()) +FreeCADGui.addCommand('Draft_Clone',Draft_Clone()) # context commands FreeCADGui.addCommand('Draft_FinishLine',FinishLine()) @@ -3695,6 +3872,8 @@ FreeCADGui.addCommand('Draft_AddToGroup',AddToGroup()) FreeCADGui.addCommand('Draft_SelectGroup',SelectGroup()) FreeCADGui.addCommand('Draft_Shape2DView',Shape2DView()) FreeCADGui.addCommand('Draft_ToggleSnap',ToggleSnap()) +FreeCADGui.addCommand('Draft_ShowSnapBar',ShowSnapBar()) +FreeCADGui.addCommand('Draft_ToggleGrid',ToggleGrid()) # a global place to look for active draft Command FreeCAD.activeDraftCommand = None diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 1f954f2f70..c36d031522 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -25,18 +25,16 @@ __title__="FreeCAD Draft Trackers" __author__ = "Yorik van Havre" __url__ = "http://free-cad.sourceforge.net" -import FreeCAD,FreeCADGui,math,Draft +import FreeCAD,FreeCADGui,math,Draft, DraftVecUtils from FreeCAD import Vector -from draftlibs import fcvec from pivy import coin from DraftGui import todo class Tracker: "A generic Draft Tracker, to be used by other specific trackers" def __init__(self,dotted=False,scolor=None,swidth=None,children=[],ontop=False): - global Part, fcgeo - import Part - from draftlibs import fcgeo + global Part, DraftGeomUtils + import Part, DraftGeomUtils self.ontop = ontop color = coin.SoBaseColor() color.rgb = scolor or FreeCADGui.draftToolBar.getDefaultColor("ui") @@ -63,7 +61,7 @@ class Tracker: def _insertSwitch(self, switch): '''insert self.switch into the scene graph. Must not be called from an event handler (or other scene graph traversal).''' - sg=FreeCADGui.ActiveDocument.ActiveView.getSceneGraph() + sg=Draft.get3DView().getSceneGraph() if self.ontop: sg.insertChild(switch,0) else: @@ -72,7 +70,7 @@ class Tracker: def _removeSwitch(self, switch): '''remove self.switch from the scene graph. As with _insertSwitch, must not be called during scene graph traversal).''' - sg=FreeCADGui.ActiveDocument.ActiveView.getSceneGraph() + sg=Draft.get3DView().getSceneGraph() sg.removeChild(switch) def on(self): @@ -82,7 +80,23 @@ class Tracker: def off(self): self.switch.whichChild = -1 self.Visible = False - + + def lowerTracker(self): + '''lowers the tracker to the bottom of the scenegraph, so + it doesn't obscure the other objects''' + if self.switch: + sg=Draft.get3DView().getSceneGraph() + sg.removeChild(self.switch) + sg.addChild(self.switch) + + def raiseTracker(self): + '''raises the tracker to the top of the scenegraph, so + it obscures the other objects''' + if self.switch: + sg=Draft.get3DView().getSceneGraph() + sg.removeChild(self.switch) + sg.insertChild(self.switch,0) + class snapTracker(Tracker): "A Snap Mark tracker, used by tools that support snapping" def __init__(self): @@ -161,8 +175,8 @@ class rectangleTracker(Tracker): def update(self,point): "sets the opposite (diagonal) point of the rectangle" diagonal = point.sub(self.origin) - inpoint1 = self.origin.add(fcvec.project(diagonal,self.v)) - inpoint2 = self.origin.add(fcvec.project(diagonal,self.u)) + inpoint1 = self.origin.add(DraftVecUtils.project(diagonal,self.v)) + inpoint2 = self.origin.add(DraftVecUtils.project(diagonal,self.u)) self.coords.point.set1Value(1,inpoint1.x,inpoint1.y,inpoint1.z) self.coords.point.set1Value(2,point.x,point.y,point.z) self.coords.point.set1Value(3,inpoint2.x,inpoint2.y,inpoint2.z) @@ -204,7 +218,7 @@ class rectangleTracker(Tracker): p1 = Vector(self.coords.point.getValues()[0].getValue()) p2 = Vector(self.coords.point.getValues()[2].getValue()) diag = p2.sub(p1) - return ((fcvec.project(diag,self.u)).Length,(fcvec.project(diag,self.v)).Length) + return ((DraftVecUtils.project(diag,self.u)).Length,(DraftVecUtils.project(diag,self.v)).Length) def getNormal(self): "returns the normal of the rectangle" @@ -233,23 +247,23 @@ class dimTracker(Tracker): def calc(self): import Part if (self.p1 != None) and (self.p2 != None): - points = [fcvec.tup(self.p1,True),fcvec.tup(self.p2,True),\ - fcvec.tup(self.p1,True),fcvec.tup(self.p2,True)] + points = [DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True),\ + DraftVecUtils.tup(self.p1,True),DraftVecUtils.tup(self.p2,True)] if self.p3 != None: p1 = self.p1 p4 = self.p2 - if fcvec.equals(p1,p4): + if DraftVecUtils.equals(p1,p4): proj = None else: base = Part.Line(p1,p4).toShape() - proj = fcgeo.findDistance(self.p3,base) + proj = DraftGeomUtils.findDistance(self.p3,base) if not proj: p2 = p1 p3 = p4 else: - p2 = p1.add(fcvec.neg(proj)) - p3 = p4.add(fcvec.neg(proj)) - points = [fcvec.tup(p1),fcvec.tup(p2),fcvec.tup(p3),fcvec.tup(p4)] + p2 = p1.add(DraftVecUtils.neg(proj)) + p3 = p4.add(DraftVecUtils.neg(proj)) + points = [DraftVecUtils.tup(p1),DraftVecUtils.tup(p2),DraftVecUtils.tup(p3),DraftVecUtils.tup(p4)] self.coords.point.setValues(0,4,points) class bsplineTracker(Tracker): @@ -340,7 +354,7 @@ class arcTracker(Tracker): center = Vector(c[0],c[1],c[2]) base = FreeCAD.DraftWorkingPlane.u rad = pt.sub(center) - return(fcvec.angle(rad,base,FreeCAD.DraftWorkingPlane.axis)) + return(DraftVecUtils.angle(rad,base,FreeCAD.DraftWorkingPlane.axis)) def getAngles(self): "returns the start and end angles" @@ -451,8 +465,8 @@ class PlaneTracker(Tracker): "A working plane tracker" def __init__(self): # getting screen distance - p1 = FreeCADGui.ActiveDocument.ActiveView.getPoint((100,100)) - p2 = FreeCADGui.ActiveDocument.ActiveView.getPoint((110,100)) + p1 = Draft.get3DView().getPoint((100,100)) + p2 = Draft.get3DView().getPoint((110,100)) bl = (p2.sub(p1)).Length * (Draft.getParam("snapRange")/2) self.trans = coin.SoTransform() self.trans.translation.setValue([0,0,0]) @@ -496,7 +510,7 @@ class wireTracker(Tracker): "A wire tracker" def __init__(self,wire): self.line = coin.SoLineSet() - self.closed = fcgeo.isReallyClosed(wire) + self.closed = DraftGeomUtils.isReallyClosed(wire) if self.closed: self.line.numVertices.setValue(len(wire.Vertexes)+1) else: @@ -535,22 +549,30 @@ class gridTracker(Tracker): bound = (self.numlines/2)*self.space pts = [] mpts = [] + apts = [] for i in range(self.numlines+1): curr = -bound + i*self.space z = 0 if i/float(self.mainlines) == i/self.mainlines: - mpts.extend([[-bound,curr,z],[bound,curr,z]]) - mpts.extend([[curr,-bound,z],[curr,bound,z]]) + if round(curr,4) == 0: + apts.extend([[-bound,curr,z],[bound,curr,z]]) + apts.extend([[curr,-bound,z],[curr,bound,z]]) + else: + mpts.extend([[-bound,curr,z],[bound,curr,z]]) + mpts.extend([[curr,-bound,z],[curr,bound,z]]) else: pts.extend([[-bound,curr,z],[bound,curr,z]]) pts.extend([[curr,-bound,z],[curr,bound,z]]) idx = [] midx = [] + aidx = [] for p in range(0,len(pts),2): idx.append(2) for mp in range(0,len(mpts),2): midx.append(2) - + for ap in range(0,len(apts),2): + aidx.append(2) + mat1 = coin.SoMaterial() mat1.transparency.setValue(0.7) mat1.diffuseColor.setValue(col) @@ -565,6 +587,13 @@ class gridTracker(Tracker): self.coords2.point.setValues(mpts) lines2 = coin.SoLineSet() lines2.numVertices.setValues(midx) + mat3 = coin.SoMaterial() + mat3.transparency.setValue(0) + mat3.diffuseColor.setValue(col) + self.coords3 = coin.SoCoordinate3() + self.coords3.point.setValues(apts) + lines3 = coin.SoLineSet() + lines3.numVertices.setValues(aidx) s = coin.SoSeparator() s.addChild(self.trans) s.addChild(mat1) @@ -573,6 +602,9 @@ class gridTracker(Tracker): s.addChild(mat2) s.addChild(self.coords2) s.addChild(lines2) + s.addChild(mat3) + s.addChild(self.coords3) + s.addChild(lines3) Tracker.__init__(self,children=[s]) self.update() @@ -601,29 +633,21 @@ class gridTracker(Tracker): def set(self): Q = FreeCAD.DraftWorkingPlane.getRotation().Rotation.Q + P = FreeCAD.DraftWorkingPlane.position self.trans.rotation.setValue([Q[0],Q[1],Q[2],Q[3]]) + self.trans.translation.setValue([P.x,P.y,P.z]) self.on() def getClosestNode(self,point): "returns the closest node from the given point" # get the 2D coords. - point = FreeCAD.DraftWorkingPlane.projectPoint(point) - u = fcvec.project(point,FreeCAD.DraftWorkingPlane.u) - lu = u.Length - if u.getAngle(FreeCAD.DraftWorkingPlane.u) > 1.5: - lu = -lu - v = fcvec.project(point,FreeCAD.DraftWorkingPlane.v) - lv = v.Length - if v.getAngle(FreeCAD.DraftWorkingPlane.v) > 1.5: - lv = -lv - # print "u = ",u," v = ",v - # find nearest grid node - pu = (round(lu/self.space,0))*self.space - pv = (round(lv/self.space,0))*self.space - rot = FreeCAD.Rotation() - rot.Q = self.trans.rotation.getValue().getValue() - return rot.multVec(Vector(pu,pv,0)) - + # point = FreeCAD.DraftWorkingPlane.projectPoint(point) + pt = FreeCAD.DraftWorkingPlane.getLocalCoords(point) + pu = (round(pt.x/self.space,0))*self.space + pv = (round(pt.y/self.space,0))*self.space + pt = FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(pu,pv,0)) + return pt + class boxTracker(Tracker): "A box tracker, can be based on a line object" def __init__(self,line=None,width=0.1,height=1): @@ -641,8 +665,7 @@ class boxTracker(Tracker): Tracker.__init__(self,children=[self.trans,m,self.cube]) def update(self,line=None,normal=None): - import WorkingPlane - from draftlibs import fcgeo + import WorkingPlane, DraftGeomUtils if not normal: normal = FreeCAD.DraftWorkingPlane.axis if line: @@ -650,10 +673,10 @@ class boxTracker(Tracker): bp = line[0] lvec = line[1].sub(line[0]) else: - lvec = fcgeo.vec(line.Shape.Edges[0]) + lvec = DraftGeomUtils.vec(line.Shape.Edges[0]) bp = line.Shape.Edges[0].Vertexes[0].Point elif self.baseline: - lvec = fcgeo.vec(self.baseline.Shape.Edges[0]) + lvec = DraftGeomUtils.vec(self.baseline.Shape.Edges[0]) bp = self.baseline.Shape.Edges[0].Vertexes[0].Point else: return @@ -661,12 +684,12 @@ class boxTracker(Tracker): self.cube.width.setValue(lvec.Length) p = WorkingPlane.getPlacementFromPoints([bp,bp.add(lvec),bp.add(right)]) self.trans.rotation.setValue(p.Rotation.Q) - bp = bp.add(fcvec.scale(lvec,0.5)) - bp = bp.add(fcvec.scaleTo(normal,self.cube.depth.getValue()/2)) + bp = bp.add(DraftVecUtils.scale(lvec,0.5)) + bp = bp.add(DraftVecUtils.scaleTo(normal,self.cube.depth.getValue()/2)) self.pos(bp) def pos(self,p): - self.trans.translation.setValue(fcvec.tup(p)) + self.trans.translation.setValue(DraftVecUtils.tup(p)) def width(self,w=None): if w: @@ -686,3 +709,27 @@ class boxTracker(Tracker): self.update() else: return self.cube.depth.getValue() + +class radiusTracker(Tracker): + "A tracker that displays a transparent sphere to inicate a radius" + def __init__(self,position=FreeCAD.Vector(0,0,0),radius=1): + self.trans = coin.SoTransform() + self.trans.translation.setValue([position.x,position.y,position.z]) + m = coin.SoMaterial() + m.transparency.setValue(0.9) + m.diffuseColor.setValue([0,1,0]) + self.sphere = coin.SoSphere() + self.sphere.radius.setValue(radius) + self.baseline = None + Tracker.__init__(self,children=[self.trans,m,self.sphere]) + + def update(self,arg1,arg2=None): + if isinstance(arg1,FreeCAD.Vector): + self.trans.translation.setValue([arg1.x,arg1.y,arg1.z]) + else: + self.sphere.radius.setValue(arg1) + if arg2 != None: + if isinstance(arg2,FreeCAD.Vector): + self.trans.translation.setValue([arg2.x,arg2.y,arg2.z]) + else: + self.sphere.radius.setValue(arg2) diff --git a/src/Mod/Draft/draftlibs/fcvec.py b/src/Mod/Draft/DraftVecUtils.py similarity index 96% rename from src/Mod/Draft/draftlibs/fcvec.py rename to src/Mod/Draft/DraftVecUtils.py index 0f3358cfc7..678965e85a 100644 --- a/src/Mod/Draft/draftlibs/fcvec.py +++ b/src/Mod/Draft/DraftVecUtils.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * #* Copyright (c) 2009, 2010 * -#* Yorik van Havre , Ken Cline * +#* Yorik van Havre , Ken Cline * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -40,6 +40,10 @@ def typecheck (args_and_types, name="?"): FreeCAD.Console.PrintWarning("typecheck[" + str(name) + "]: " + str(v) + " is not " + str(t) + "\n") raise TypeError("fcvec." + str(name)) +def toString(u): + "returns a string containing a python command to recreate this vector" + return "FreeCAD.Vector("+str(u.x)+","+str(u.y)+","+str(u.z)+")" + def tup(u,array=False): "returns a tuple (x,y,z) with the vector coords, or an array if array=true" typecheck ([(u,Vector)], "tup"); diff --git a/src/Mod/Draft/Draft_rc.py b/src/Mod/Draft/Draft_rc.py index 43477b4e37..4028d367e7 100644 --- a/src/Mod/Draft/Draft_rc.py +++ b/src/Mod/Draft/Draft_rc.py @@ -2,8 +2,8 @@ # Resource object code # -# Created: Sun Feb 26 13:28:36 2012 -# by: The Resource Compiler for PyQt (Qt v4.7.4) +# Created: Wed Jun 6 16:21:23 2012 +# by: The Resource Compiler for PyQt (Qt v4.8.1) # # WARNING! All changes made in this file will be lost! @@ -117,79 +117,150 @@ qt_resource_data = "\ \x0a\x20\x20\x20\x20\x3c\x2f\x70\x61\x74\x74\x65\x72\x6e\x3e\x0a\ \x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ \ -\x00\x00\x04\x69\ -\x00\ -\x00\x15\x07\x78\x9c\xbd\x58\xdb\x6e\x1b\x37\x10\x7d\xef\x57\x2c\ -\x36\x2f\x2d\xb0\xa1\x78\xbf\xb8\x52\x7e\xa1\x0f\x45\x3e\x40\xb0\ -\xd7\xb2\x10\x47\x0e\x24\xb5\x49\xfa\xf5\x1d\xde\x96\xb4\xe1\x59\ -\xcf\x4b\x2c\x01\xc2\x90\x7b\x20\x9e\x1d\xce\x99\x19\x72\x7b\xf9\ -\xf7\xf0\xe9\xb7\x61\xd8\xde\xcd\xf7\x97\x68\x80\xf9\x6d\x7f\xbd\ -\xce\xe7\x53\x1a\xc0\xe7\x78\xb7\x1b\x6f\x9f\x4e\xb7\xe7\xf9\x3a\ -\x8f\x75\xb2\x60\x3e\x9f\x8e\xd7\xcb\x6e\xfc\xe7\x32\x9f\xff\xfe\ -\xb6\xbf\x9d\xff\x3a\x7d\xbe\x34\xd0\x8f\xdd\xc8\x97\xc1\xcf\x7e\ -\xf0\xfd\x78\x77\x7d\xd8\x8d\xcc\x2c\x33\x0f\xf3\xf1\xf0\x70\x4d\ -\x53\x9f\xca\xdc\xf6\x50\x1f\x0e\xc3\xe5\xfa\xf3\x71\xde\x8d\xf7\ -\xc7\xc7\xc7\x9b\xd3\xd3\x69\xfe\x13\x66\xce\x4f\x5f\xe6\x9b\x0f\ -\x3c\x7d\xea\xf8\x63\xfa\xe7\x9b\xee\x8f\x87\xe1\x7a\xde\x9f\x2e\ -\xf7\x4f\xe7\xaf\xbb\xf1\x72\xbb\x7f\x9c\x7f\x67\x5c\xfc\xd1\x3d\ -\x8f\x2f\x78\x50\x9a\x8b\x65\xe5\xec\x84\x87\x06\x19\x06\xc0\x7c\ -\x1d\x0c\x53\xc6\x09\x2d\xfd\xa4\x98\x91\xd2\x07\x6d\x87\xfd\x20\ -\x98\x52\x41\x7a\xe3\xa6\xc5\x1a\xf8\x20\xe0\xfb\x51\x32\xeb\x60\ -\x28\xcc\xc4\x57\x60\x3d\xea\xbf\xb1\x5f\x35\x52\x8b\x4c\xa4\xd7\ -\x7c\x1c\x36\x6f\xf1\x13\x9a\x09\x0e\x04\xd5\x64\x99\x97\x56\x5b\ -\x2b\x80\x9f\x62\x32\x72\x36\x76\x5a\xac\xca\xcf\xb2\x38\x74\x42\ -\xc0\xca\x38\xac\x47\xa1\xfc\x24\x8d\x9f\x97\xd9\x7f\x9c\x05\xa5\ -\x2c\x0f\xc0\x8f\xb3\xe4\x53\xe3\xd4\xd4\xcc\xca\x50\x94\xb5\x61\ -\xe9\x35\x5c\x07\x43\x19\x6a\x02\x43\xe9\x59\xd9\x61\x61\x99\xe4\ -\x02\x5c\x08\x0c\x25\x93\x2a\xf2\x0e\xd3\x62\x55\x7e\x9a\x69\x0b\ -\x70\x0b\x0b\xe3\xa8\x0e\x84\xb2\xb3\x04\x76\x40\xc9\xc4\x68\x97\ -\x93\xe4\x8c\x7b\xa3\x82\x4e\xfe\xd3\xa1\x6c\x7b\x33\x2b\x3f\xf0\ -\xb3\xcf\xa4\xf8\x2a\xb0\xc7\xa1\x1c\x3d\x81\xa3\xd2\xcc\xc5\x97\ -\xd7\x93\x74\x20\x12\xe7\xa4\x49\x1c\x65\x8e\xf1\xb4\xb4\x8a\x6a\ -\x0b\xae\x71\x34\x49\x57\x89\x22\x8e\xeb\x60\x18\x43\x43\x51\x89\ -\xe6\x4c\xc4\x35\xe4\x14\x98\x82\xa8\xe6\x5e\x24\x86\xa2\xea\x13\ -\x48\xe4\xfd\xf3\x8d\x61\xa6\x95\x18\xe2\xb8\x0e\x86\x32\xa4\xe8\ -\x44\x97\xdd\xd0\x93\xf2\xcc\x69\x2b\x8a\x4e\xea\x72\xaf\x32\xd4\ -\x29\xc6\xb2\x0f\x51\x5c\x07\x43\x19\x52\x74\xa2\x04\x13\x96\xc7\ -\x94\x05\x5c\x8d\xb3\x59\x27\x8a\x25\xc7\xc0\xec\x62\x55\x7e\x8e\ -\xc5\x61\x8c\xbc\x15\x54\x07\x42\xd9\x51\x74\x22\x8b\x00\x55\xf4\ -\x9f\x34\x86\x2b\x93\xf2\x74\x64\x9c\xb4\x5d\xad\xca\xae\x64\x3c\ -\x9b\xd2\x34\x86\xea\x40\x28\x3b\x8a\x42\xb4\x60\x21\xee\x01\x14\ -\x02\x58\x42\x3b\x1f\xb2\x42\x7c\x76\x46\x8c\xfc\x6a\xb6\x2c\x98\ -\x44\x91\x15\x82\xe3\x3a\x18\xc6\xd0\x52\x14\xa2\x2c\xcb\x69\x42\ -\x1a\xe6\xa2\xfb\x5c\x22\x58\x8a\x5f\x0c\xfc\x6a\xb6\xf0\x73\xd5\ -\x37\x6b\xb8\x0e\x86\x12\xa4\x08\x24\x26\xc2\x49\x4b\x50\x89\x13\ -\x2e\x6b\xc3\xc2\x4c\xfa\x6d\x3e\x8b\x33\xaf\x3c\x29\x0f\x50\x02\ -\x94\xf8\x17\x8e\x15\x89\x89\xc0\x82\x29\x75\x82\xd0\x09\x90\x1a\ -\x81\x35\x76\x94\xf8\x17\x25\xc2\xec\x24\x3c\xe8\xd4\x38\x23\x73\ -\x9d\x48\xda\x4f\x99\xab\x9a\x6d\x03\x7d\x49\x6a\xab\xb8\x0e\x86\ -\x32\xa4\x68\x00\xaa\xab\xcd\x21\x06\x9a\x0f\x20\x01\x9d\x77\x31\ -\x67\x78\x19\x57\xae\x66\xdb\xcf\xa4\xc6\x5c\xc8\x70\x5c\x07\xc3\ -\x18\x3a\x92\x06\x96\x72\x23\x14\xb3\x42\x8a\x52\x25\xde\x66\xe8\ -\x69\x0c\xd7\x72\xb0\xa3\x88\x00\x2a\x6d\x52\xbf\x8d\x4a\x70\x22\ -\x28\x29\x89\xdd\x94\xa4\x75\x53\x72\x8d\x21\x45\x25\x7a\xf1\x61\ -\xec\xab\x52\xc3\x9c\x54\x62\x4a\xfd\x5d\xac\x96\x87\xb9\x5a\xda\ -\x65\x0c\xd5\x81\x50\x76\x14\x95\xa8\x90\xbb\x51\x37\x41\xbd\xe0\ -\xbc\xa4\xb9\x9a\x43\xd5\xb4\x58\x8d\x9d\xa9\x1b\x87\xa3\x3a\x10\ -\xca\x8e\xa2\x10\x59\x8a\xe1\x73\xdf\x41\xca\xcb\x82\x9c\x16\xab\ -\xb2\x33\x4d\x9a\x38\xca\xbc\xad\x5f\x4f\x51\x47\xd7\x89\x7a\xc8\ -\x35\x10\x7b\x79\x67\x75\xa9\xec\x8b\xd5\xf2\x5f\x7a\x9b\xa4\x4b\ -\x1c\xd6\xa3\x50\x7e\x24\x6d\xe4\x18\x89\x1d\x80\x62\xf0\x4a\x5c\ -\xe5\xfc\xe2\x79\x69\x21\xab\xd5\x94\x61\x3b\xf1\x62\xb0\x1e\x85\ -\xf2\x23\x29\x23\x9f\x33\x54\x4c\xd0\x9d\xfb\x7e\x79\x83\xe2\x49\ -\xc2\x50\x85\x1c\xb4\x01\x29\xf0\xb2\xef\xf2\x01\x21\x95\xf5\x6a\ -\x36\xef\x85\x7a\xc0\x59\xc3\x75\x30\x94\x20\x49\x1b\xa6\x64\xac\ -\x98\x1b\x8c\xaf\xc7\xc8\x77\x29\x6f\x81\x22\x0f\xb9\x64\x01\xcd\ -\x78\x23\xf8\x2e\x1e\x0c\x14\x7d\x80\x6a\x4b\x12\x85\xfe\xc5\xf0\ -\xf7\x6d\xf1\x02\xe9\x84\x01\x39\x59\x7b\x13\xe0\x94\x60\xfa\xbb\ -\x02\xe3\x9c\x07\xc1\xbc\x42\x10\x8e\x24\x06\x6a\x58\x29\xbf\x18\ -\xac\x43\xa1\xfc\x28\x22\xd1\x70\xba\x9d\xb4\x01\x92\x3c\xb7\x57\ -\xa9\xad\x8c\x3f\x2d\xe5\xe5\x3a\xf6\x7c\x3a\xcf\xa2\x4b\x93\x0e\ -\x10\xe5\x1a\x25\xc0\x01\xca\x05\x58\x5e\xbc\xdf\x35\x4a\xe0\x94\ -\xf8\x8f\xa7\xd6\x00\x1f\x68\x4d\x80\x62\xbd\x46\x79\x76\xb8\xaf\ -\xe6\xcb\x4b\x00\xf5\xf2\x16\xe0\x05\xb0\xc7\xa1\x1c\x7b\x09\x6c\ -\x37\x87\x72\xb1\xb9\x29\xb7\x96\xe9\xc2\x73\x93\x6f\x3c\xb7\x9b\ -\x78\x03\xfa\x3f\xe0\xde\x25\x35\ +\x00\x00\x08\xd6\ +\x3c\ +\x73\x76\x67\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x3e\x0a\x20\x20\ +\x20\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x63\x6f\x6e\x63\x72\x65\x74\x65\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x70\x61\x74\x74\x65\x72\x6e\x55\x6e\ +\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\ +\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x30\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x2e\x35\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\ +\x2e\x35\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\ +\x6c\x6c\x3a\x6e\x6f\x6e\x65\x3b\x20\x73\x74\x72\x6f\x6b\x65\x3a\ +\x23\x30\x30\x30\x30\x30\x30\x3b\x20\x73\x74\x72\x6f\x6b\x65\x2d\ +\x77\x69\x64\x74\x68\x3a\x2e\x35\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x73\x63\ +\x61\x6c\x65\x28\x2e\x30\x31\x29\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x67\x33\x34\x30\x31\x22\x3e\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\ +\x6d\x20\x35\x2e\x33\x35\x37\x31\x34\x32\x38\x2c\x33\x2e\x35\x32\ +\x32\x38\x39\x34\x36\x20\x61\x20\x31\x2e\x33\x33\x39\x32\x38\x35\ +\x37\x2c\x31\x2e\x33\x33\x39\x32\x38\x35\x37\x20\x30\x20\x31\x20\ +\x31\x20\x2d\x32\x2e\x36\x37\x38\x35\x37\x31\x35\x2c\x30\x20\x31\ +\x2e\x33\x33\x39\x32\x38\x35\x37\x2c\x31\x2e\x33\x33\x39\x32\x38\ +\x35\x37\x20\x30\x20\x31\x20\x31\x20\x32\x2e\x36\x37\x38\x35\x37\ +\x31\x35\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x31\x34\x2e\ +\x31\x30\x37\x31\x34\x33\x2c\x36\x2e\x38\x32\x36\x34\x36\x36\x31\ +\x20\x61\x20\x33\x2e\x32\x31\x34\x32\x38\x35\x36\x2c\x33\x2e\x32\ +\x31\x34\x32\x38\x35\x36\x20\x30\x20\x31\x20\x31\x20\x2d\x36\x2e\ +\x34\x32\x38\x35\x37\x31\x31\x2c\x30\x20\x33\x2e\x32\x31\x34\x32\ +\x38\x35\x36\x2c\x33\x2e\x32\x31\x34\x32\x38\x35\x36\x20\x30\x20\ +\x31\x20\x31\x20\x36\x2e\x34\x32\x38\x35\x37\x31\x31\x2c\x30\x20\ +\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\ +\x74\x68\x20\x64\x3d\x22\x6d\x20\x31\x34\x2e\x38\x32\x31\x34\x32\ +\x38\x2c\x33\x30\x2e\x39\x33\x33\x36\x30\x39\x20\x61\x20\x30\x2e\ +\x37\x31\x34\x32\x38\x35\x37\x33\x2c\x30\x2e\x37\x31\x34\x32\x38\ +\x35\x37\x33\x20\x30\x20\x31\x20\x31\x20\x2d\x31\x2e\x34\x32\x38\ +\x35\x37\x31\x2c\x30\x20\x30\x2e\x37\x31\x34\x32\x38\x35\x37\x33\ +\x2c\x30\x2e\x37\x31\x34\x32\x38\x35\x37\x33\x20\x30\x20\x31\x20\ +\x31\x20\x31\x2e\x34\x32\x38\x35\x37\x31\x2c\x30\x20\x7a\x22\x2f\ +\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\ +\x64\x3d\x22\x6d\x20\x32\x38\x2e\x35\x37\x31\x34\x32\x38\x2c\x31\ +\x36\x2e\x32\x30\x31\x34\x36\x36\x20\x61\x20\x32\x2e\x32\x33\x32\ +\x31\x34\x32\x39\x2c\x32\x2e\x32\x33\x32\x31\x34\x32\x39\x20\x30\ +\x20\x31\x20\x31\x20\x2d\x34\x2e\x34\x36\x34\x32\x38\x36\x2c\x30\ +\x20\x32\x2e\x32\x33\x32\x31\x34\x32\x39\x2c\x32\x2e\x32\x33\x32\ +\x31\x34\x32\x39\x20\x30\x20\x31\x20\x31\x20\x34\x2e\x34\x36\x34\ +\x32\x38\x36\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x36\x2e\ +\x32\x35\x30\x30\x30\x30\x32\x2c\x32\x30\x2e\x30\x38\x35\x33\x39\ +\x34\x20\x61\x20\x30\x2e\x34\x39\x31\x30\x37\x31\x34\x33\x2c\x30\ +\x2e\x34\x39\x31\x30\x37\x31\x34\x33\x20\x30\x20\x31\x20\x31\x20\ +\x2d\x30\x2e\x39\x38\x32\x31\x34\x32\x39\x2c\x30\x20\x30\x2e\x34\ +\x39\x31\x30\x37\x31\x34\x33\x2c\x30\x2e\x34\x39\x31\x30\x37\x31\ +\x34\x33\x20\x30\x20\x31\x20\x31\x20\x30\x2e\x39\x38\x32\x31\x34\ +\x32\x39\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x33\x34\x2e\ +\x37\x33\x32\x31\x34\x34\x2c\x32\x37\x2e\x35\x32\x37\x37\x32\x35\ +\x20\x61\x20\x30\x2e\x32\x36\x37\x38\x35\x37\x31\x33\x2c\x30\x2e\ +\x34\x33\x33\x34\x30\x31\x39\x37\x20\x30\x20\x31\x20\x31\x20\x2d\ +\x30\x2e\x35\x33\x35\x37\x31\x34\x2c\x30\x20\x30\x2e\x32\x36\x37\ +\x38\x35\x37\x31\x33\x2c\x30\x2e\x34\x33\x33\x34\x30\x31\x39\x37\ +\x20\x30\x20\x31\x20\x31\x20\x30\x2e\x35\x33\x35\x37\x31\x34\x2c\ +\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\ +\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x34\x30\x2e\x31\x37\x38\ +\x35\x37\x32\x2c\x39\x2e\x33\x37\x31\x31\x30\x38\x31\x20\x61\x20\ +\x30\x2e\x31\x33\x33\x39\x32\x38\x35\x37\x2c\x30\x2e\x32\x32\x33\ +\x32\x31\x34\x32\x38\x20\x30\x20\x31\x20\x31\x20\x2d\x30\x2e\x32\ +\x36\x37\x38\x35\x37\x2c\x30\x20\x30\x2e\x31\x33\x33\x39\x32\x38\ +\x35\x37\x2c\x30\x2e\x32\x32\x33\x32\x31\x34\x32\x38\x20\x30\x20\ +\x31\x20\x31\x20\x30\x2e\x32\x36\x37\x38\x35\x37\x2c\x30\x20\x7a\ +\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\ +\x68\x20\x64\x3d\x22\x6d\x20\x34\x30\x2e\x39\x38\x32\x31\x34\x34\ +\x2c\x33\x38\x2e\x37\x34\x36\x31\x30\x39\x20\x61\x20\x30\x2e\x32\ +\x32\x33\x32\x31\x34\x32\x38\x2c\x30\x2e\x32\x32\x33\x32\x31\x34\ +\x32\x38\x20\x30\x20\x31\x20\x31\x20\x2d\x30\x2e\x34\x34\x36\x34\ +\x32\x38\x2c\x30\x20\x30\x2e\x32\x32\x33\x32\x31\x34\x32\x38\x2c\ +\x30\x2e\x32\x32\x33\x32\x31\x34\x32\x38\x20\x30\x20\x31\x20\x31\ +\x20\x30\x2e\x34\x34\x36\x34\x32\x38\x2c\x30\x20\x7a\x22\x2f\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\ +\x3d\x22\x6d\x20\x33\x31\x2e\x31\x36\x30\x37\x31\x35\x2c\x34\x30\ +\x2e\x35\x37\x36\x34\x36\x36\x20\x61\x20\x33\x2e\x39\x32\x38\x35\ +\x37\x31\x35\x2c\x33\x2e\x39\x32\x38\x35\x37\x31\x35\x20\x30\x20\ +\x31\x20\x31\x20\x2d\x37\x2e\x38\x35\x37\x31\x34\x33\x2c\x30\x20\ +\x33\x2e\x39\x32\x38\x35\x37\x31\x35\x2c\x33\x2e\x39\x32\x38\x35\ +\x37\x31\x35\x20\x30\x20\x31\x20\x31\x20\x37\x2e\x38\x35\x37\x31\ +\x34\x33\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x32\x32\x2e\ +\x32\x33\x32\x31\x34\x33\x2c\x33\x38\x2e\x32\x35\x35\x30\x33\x35\ +\x20\x61\x20\x31\x2e\x36\x30\x37\x31\x34\x32\x38\x2c\x31\x2e\x36\ +\x30\x37\x31\x34\x32\x38\x20\x30\x20\x31\x20\x31\x20\x2d\x33\x2e\ +\x32\x31\x34\x32\x38\x36\x2c\x30\x20\x31\x2e\x36\x30\x37\x31\x34\ +\x32\x38\x2c\x31\x2e\x36\x30\x37\x31\x34\x32\x38\x20\x30\x20\x31\ +\x20\x31\x20\x33\x2e\x32\x31\x34\x32\x38\x36\x2c\x30\x20\x7a\x22\ +\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\ +\x20\x64\x3d\x22\x6d\x20\x34\x31\x2e\x39\x36\x34\x32\x38\x37\x2c\ +\x31\x31\x2e\x36\x34\x37\x38\x39\x35\x20\x61\x20\x30\x2e\x38\x39\ +\x32\x38\x35\x37\x31\x33\x2c\x30\x2e\x38\x39\x32\x38\x35\x37\x31\ +\x33\x20\x30\x20\x31\x20\x31\x20\x2d\x31\x2e\x37\x38\x35\x37\x31\ +\x34\x2c\x30\x20\x30\x2e\x38\x39\x32\x38\x35\x37\x31\x33\x2c\x30\ +\x2e\x38\x39\x32\x38\x35\x37\x31\x33\x20\x30\x20\x31\x20\x31\x20\ +\x31\x2e\x37\x38\x35\x37\x31\x34\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\ +\x22\x6d\x20\x33\x36\x2e\x30\x37\x31\x34\x33\x2c\x32\x35\x2e\x37\ +\x35\x35\x30\x33\x37\x20\x61\x20\x30\x2e\x33\x35\x37\x31\x34\x32\ +\x38\x37\x2c\x30\x2e\x33\x35\x37\x31\x34\x32\x38\x37\x20\x30\x20\ +\x31\x20\x31\x20\x2d\x30\x2e\x37\x31\x34\x32\x38\x36\x2c\x30\x20\ +\x30\x2e\x33\x35\x37\x31\x34\x32\x38\x37\x2c\x30\x2e\x33\x35\x37\ +\x31\x34\x32\x38\x37\x20\x30\x20\x31\x20\x31\x20\x30\x2e\x37\x31\ +\x34\x32\x38\x36\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x36\ +\x2e\x32\x35\x2c\x34\x32\x2e\x39\x38\x37\x31\x37\x39\x20\x61\x20\ +\x30\x2e\x36\x32\x35\x2c\x30\x2e\x36\x32\x35\x20\x30\x20\x31\x20\ +\x31\x20\x2d\x31\x2e\x32\x35\x2c\x30\x20\x30\x2e\x36\x32\x35\x2c\ +\x30\x2e\x36\x32\x35\x20\x30\x20\x31\x20\x31\x20\x31\x2e\x32\x35\ +\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x20\x31\x37\x2e\x33\x32\ +\x31\x34\x32\x38\x2c\x31\x39\x2e\x39\x35\x31\x34\x36\x36\x20\x61\ +\x20\x31\x2e\x33\x33\x39\x32\x38\x35\x37\x2c\x31\x2e\x33\x33\x39\ +\x32\x38\x35\x37\x20\x30\x20\x31\x20\x31\x20\x2d\x32\x2e\x36\x37\ +\x38\x35\x37\x31\x2c\x30\x20\x31\x2e\x33\x33\x39\x32\x38\x35\x37\ +\x2c\x31\x2e\x33\x33\x39\x32\x38\x35\x37\x20\x30\x20\x31\x20\x31\ +\x20\x32\x2e\x36\x37\x38\x35\x37\x31\x2c\x30\x20\x7a\x22\x2f\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\ +\x3d\x22\x6d\x20\x31\x31\x2e\x39\x36\x34\x32\x38\x36\x2c\x31\x38\ +\x2e\x31\x36\x35\x37\x35\x32\x20\x61\x20\x30\x2e\x34\x34\x36\x34\ +\x32\x38\x35\x37\x2c\x30\x2e\x34\x34\x36\x34\x32\x38\x35\x37\x20\ +\x30\x20\x31\x20\x31\x20\x2d\x30\x2e\x38\x39\x32\x38\x35\x37\x2c\ +\x30\x20\x30\x2e\x34\x34\x36\x34\x32\x38\x35\x37\x2c\x30\x2e\x34\ +\x34\x36\x34\x32\x38\x35\x37\x20\x30\x20\x31\x20\x31\x20\x30\x2e\ +\x38\x39\x32\x38\x35\x37\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\ +\x20\x31\x36\x2e\x36\x30\x37\x31\x34\x33\x2c\x37\x2e\x38\x39\x37\ +\x38\x39\x34\x39\x20\x61\x20\x30\x2e\x35\x33\x35\x37\x31\x34\x32\ +\x37\x2c\x30\x2e\x35\x33\x35\x37\x31\x34\x32\x37\x20\x30\x20\x31\ +\x20\x31\x20\x2d\x31\x2e\x30\x37\x31\x34\x32\x39\x2c\x30\x20\x30\ +\x2e\x35\x33\x35\x37\x31\x34\x32\x37\x2c\x30\x2e\x35\x33\x35\x37\ +\x31\x34\x32\x37\x20\x30\x20\x31\x20\x31\x20\x31\x2e\x30\x37\x31\ +\x34\x32\x39\x2c\x30\x20\x7a\x22\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x70\x61\x74\x74\ +\x65\x72\x6e\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x3c\ +\x2f\x73\x76\x67\x3e\ \x00\x00\x74\xe7\ \x3c\ \xb8\x64\x18\xca\xef\x9c\x95\xcd\x21\x1c\xbf\x60\xa1\xbd\xdd\x42\ @@ -9137,6 +9208,2747 @@ qt_resource_data = "\ \x2b\x9d\x15\x94\xf3\x78\x6e\x77\xc4\xe7\x94\x75\x1c\x4c\x20\xaa\ \xd1\x65\x7a\xbb\xb0\x2c\x87\x9a\x83\xcd\x40\x04\xb2\xc8\xf0\x66\ \x5d\x8d\x1b\xfe\x7f\x15\x11\x41\xe5\ +\x00\x00\xab\x29\ +\x3c\ +\xb8\x64\x18\xca\xef\x9c\x95\xcd\x21\x1c\xbf\x60\xa1\xbd\xdd\x42\ +\x00\x00\x09\x98\x00\x00\x00\x58\x00\x00\x9e\xbc\x00\x00\x00\x59\ +\x00\x00\x9f\x8b\x00\x00\x00\x5a\x00\x00\xa0\x3a\x00\x00\x05\xd9\ +\x00\x00\x9f\x4b\x00\x00\x05\xda\x00\x00\x9f\x6b\x00\x00\x05\xea\ +\x00\x00\xa0\x1a\x00\x00\x07\x78\x00\x00\x6b\x30\x00\x00\x48\x83\ +\x00\x00\x03\x39\x00\x00\x48\x83\x00\x00\x71\xc2\x00\x00\x68\x34\ +\x00\x00\x65\xc3\x00\x04\xa6\x79\x00\x00\x75\x03\x00\x04\xbb\x04\ +\x00\x00\x0b\x56\x00\x04\xbb\x04\x00\x00\x79\x78\x00\x05\x30\x45\ +\x00\x00\x0d\x81\x00\x05\x30\x45\x00\x00\x8b\x6f\x00\x05\x46\xc5\ +\x00\x00\x0d\xae\x00\x05\x46\xc5\x00\x00\x8c\x13\x00\x05\x56\x45\ +\x00\x00\x44\x35\x00\x05\x56\x45\x00\x00\x8c\x3f\x00\x05\xac\xf4\ +\x00\x00\x18\x90\x00\x05\xb8\xfd\x00\x00\x9c\x58\x00\x05\xcf\xc7\ +\x00\x00\x9c\xfc\x00\x05\xe0\x85\x00\x00\x22\x0d\x00\x06\xab\x8c\ +\x00\x00\x67\x1b\x00\x10\x84\x49\x00\x00\x4f\x3f\x00\x12\x05\xba\ +\x00\x00\x98\xb8\x00\x16\xc6\xda\x00\x00\x80\x04\x00\x2a\xa6\x79\ +\x00\x00\x6e\x06\x00\x2b\xc4\xaf\x00\x00\x6e\xe4\x00\x2b\xe0\x65\ +\x00\x00\x6f\x0f\x00\x39\xdf\x33\x00\x00\x33\x76\x00\x3d\xa1\x19\ +\x00\x00\x72\xd4\x00\x3e\x93\x83\x00\x00\x34\xa2\x00\x48\x8f\x7c\ +\x00\x00\x24\xbf\x00\x4b\x66\x35\x00\x00\x30\xb0\x00\x4b\x66\x37\ +\x00\x00\x30\xf1\x00\x4b\x66\x39\x00\x00\x31\x32\x00\x4b\x87\xd4\ +\x00\x00\x78\xa9\x00\x57\x60\x54\x00\x00\x94\xb9\x00\x58\xfd\xf4\ +\x00\x00\x47\x7e\x00\x59\x98\x25\x00\x00\x13\x70\x00\x59\x98\x25\ +\x00\x00\x95\xfd\x00\x6a\x58\x9a\x00\x00\x8e\x83\x00\x79\xef\xd4\ +\x00\x00\x6b\x68\x00\x7e\x7f\x0e\x00\x00\x62\x2e\x00\x8a\x23\x95\ +\x00\x00\x28\x07\x00\x8a\x23\x97\x00\x00\x28\x4f\x00\x8a\x23\x99\ +\x00\x00\x28\x99\x00\x91\xbc\xe9\x00\x00\x0d\xdf\x00\xa6\x37\x3f\ +\x00\x00\x26\xdc\x00\xaa\x80\x25\x00\x00\x77\xe1\x00\xc6\xe3\x6e\ +\x00\x00\x23\x77\x00\xcb\xa8\x14\x00\x00\x6a\x44\x00\xfc\x00\xca\ +\x00\x00\x86\xfa\x01\x21\xd6\x39\x00\x00\x4e\x4e\x01\x22\xb4\xf9\ +\x00\x00\x13\x9f\x01\x2f\x8e\x7e\x00\x00\x58\xf0\x01\x48\xfe\xa3\ +\x00\x00\x35\x1a\x01\x53\xf3\xaa\x00\x00\x7c\xee\x01\x56\x16\x4a\ +\x00\x00\x86\x85\x01\x67\x0d\x8a\x00\x00\x81\xdb\x01\x69\x11\x7a\ +\x00\x00\x92\x9e\x01\x82\x39\x0a\x00\x00\x8f\x23\x01\x8b\x68\x75\ +\x00\x00\x9b\xf3\x01\xa1\x7f\x63\x00\x00\x1b\x09\x01\xc1\xd9\xde\ +\x00\x00\x51\x64\x01\xd2\x8f\xd3\x00\x00\x48\x25\x01\xdf\x11\x43\ +\x00\x00\x05\x5a\x01\xe2\xf4\x5a\x00\x00\x98\x4b\x01\xfc\xae\xd3\ +\x00\x00\x6b\xa9\x02\x05\xbe\x25\x00\x00\x76\x80\x02\x46\x58\x0a\ +\x00\x00\x91\xe0\x02\x65\xad\x62\x00\x00\xa1\x16\x02\x6e\x07\xe2\ +\x00\x00\x4a\x55\x02\x76\x24\x13\x00\x00\x38\xf9\x02\x7d\xe0\x55\ +\x00\x00\x4b\x03\x02\x94\x46\x1a\x00\x00\x8e\xca\x02\xa7\x2c\x15\ +\x00\x00\x04\x04\x02\xaa\x36\x95\x00\x00\x6d\x91\x02\xb1\xf0\xba\ +\x00\x00\x83\xbe\x02\xbf\xaa\x8e\x00\x00\x37\x82\x02\xc0\x66\xf2\ +\x00\x00\x55\x16\x02\xc8\x3f\xf5\x00\x00\x5f\xff\x02\xd9\xa4\xb9\ +\x00\x00\x65\x72\x02\xdb\x1a\x94\x00\x00\x06\xdd\x03\x01\x84\xc4\ +\x00\x00\x87\xc1\x03\x12\x97\x6a\x00\x00\x85\xb2\x03\x1a\x14\x14\ +\x00\x00\x2e\x5c\x03\x1a\x16\x59\x00\x00\x4b\xa3\x03\x2f\x1a\x6a\ +\x00\x00\x6f\xa2\x03\x7e\xca\xb5\x00\x00\x3f\xd4\x03\x88\x1f\xd4\ +\x00\x00\x40\xa7\x03\x9e\x58\xa5\x00\x00\x00\x42\x03\xb3\x9e\xfa\ +\x00\x00\x8f\xd3\x03\xb5\xc8\x9a\x00\x00\x91\x33\x03\xbd\xd4\xe4\ +\x00\x00\x70\x5b\x03\xc4\x3c\xf5\x00\x00\x72\x96\x03\xc5\xd5\x5e\ +\x00\x00\x08\xe5\x03\xcb\x0d\xe5\x00\x00\x96\x26\x03\xdc\x0c\xd4\ +\x00\x00\x6e\x62\x03\xf2\x70\x35\x00\x00\x2b\x17\x03\xf2\xbd\x60\ +\x00\x00\x14\xef\x03\xfb\x0f\x04\x00\x00\x2d\xe4\x04\x21\x23\x23\ +\x00\x00\x1f\x9d\x04\x56\x06\x93\x00\x00\x2c\x0f\x04\x60\x7c\x15\ +\x00\x00\x95\x10\x04\x79\xef\x9a\x00\x00\x83\x27\x04\x82\x77\xf4\ +\x00\x00\x4a\xb7\x04\x87\xf9\x9e\x00\x00\x88\xc8\x04\x8c\xd6\xae\ +\x00\x00\x5e\x5c\x04\xa0\x8a\x25\x00\x00\x05\x29\x04\xa0\x8a\x25\ +\x00\x00\x73\xff\x04\xa4\x31\x5a\x00\x00\x8a\xff\x04\xa8\xeb\x85\ +\x00\x00\x31\x73\x04\xe1\x6e\xe3\x00\x00\x09\x87\x04\xe4\x0f\x75\ +\x00\x00\x02\xd7\x04\xeb\x41\xc3\x00\x00\x2b\x8e\x04\xef\xd9\xa8\ +\x00\x00\x46\xec\x05\x03\x83\x95\x00\x00\x67\x59\x05\x05\xcb\x13\ +\x00\x00\x3e\xa4\x05\x0f\xf2\x74\x00\x00\x8d\x8c\x05\x1b\x10\x59\ +\x00\x00\x42\x40\x05\x2a\xe5\x97\x00\x00\x48\xeb\x05\x44\x3b\x5f\ +\x00\x00\x69\x44\x05\x5c\xd9\xc4\x00\x00\x0f\x0c\x05\x5c\xd9\xc4\ +\x00\x00\x8c\xa8\x05\x63\xf6\x93\x00\x00\x47\xbf\x05\x65\xee\x65\ +\x00\x00\x7b\x60\x05\x87\xb0\xc3\x00\x00\x94\xe2\x05\x96\xa8\xa5\ +\x00\x00\x12\x38\x05\x96\xa8\xa5\x00\x00\x95\xd3\x05\xad\x4b\xc3\ +\x00\x00\x40\x2a\x05\xb9\x03\xc8\x00\x00\x1c\x94\x05\xbd\x0c\xba\ +\x00\x00\x7d\x99\x05\xbd\x8e\xde\x00\x00\x5c\xb0\x05\xbe\x56\x93\ +\x00\x00\x46\x86\x05\xc5\x50\x04\x00\x00\x0b\x85\x05\xe5\x8e\x2e\ +\x00\x00\x10\x38\x05\xfb\xdc\x83\x00\x00\x3f\x00\x06\x1e\xe6\xb5\ +\x00\x00\x9b\x31\x06\x29\xee\xa9\x00\x00\x74\x29\x06\x32\xe3\xe3\ +\x00\x00\x78\xd2\x06\x57\x19\xf4\x00\x00\x00\x00\x06\x5a\xef\x15\ +\x00\x00\x6d\xbf\x06\x5b\xd2\xb5\x00\x00\x3b\x8f\x06\x6c\x88\x8e\ +\x00\x00\x3c\xc7\x06\x74\x1d\x55\x00\x00\x50\xcc\x06\x8b\x96\x44\ +\x00\x00\x0c\x37\x06\x97\x58\xc9\x00\x00\x4c\x2c\x06\xbc\x80\xa5\ +\x00\x00\x1c\x21\x06\xc9\xb8\x05\x00\x00\x70\xd7\x06\xe8\x05\x4e\ +\x00\x00\x06\x74\x06\xee\xaa\x57\x00\x00\x9a\x2c\x06\xf0\xcb\x25\ +\x00\x00\x19\xef\x06\xfa\xff\xc3\x00\x00\x3f\x6e\x06\xfc\x1a\x14\ +\x00\x00\x32\x7b\x06\xfc\xa0\x8a\x00\x00\x8d\xcd\x07\x08\x90\xe5\ +\x00\x00\x29\x72\x07\x0d\xb7\xf7\x00\x00\x36\xcf\x07\x0e\x86\x3e\ +\x00\x00\x1a\x58\x07\x35\x68\x6e\x00\x00\x16\x0c\x07\x35\xe8\x9a\ +\x00\x00\x92\xe5\x07\x44\x41\x2a\x00\x00\x7c\x5d\x07\x4a\x1f\x63\ +\x00\x00\x01\xf6\x07\x4d\x73\x22\x00\x00\x8b\x97\x07\x4e\xa6\xf2\ +\x00\x00\x79\xd9\x07\x58\xcb\xe8\x00\x00\x8b\xd1\x07\x63\xfe\x0e\ +\x00\x00\x11\x09\x07\x80\xc6\xb3\x00\x00\x9e\x84\x07\x88\x72\x5a\ +\x00\x00\x71\xe5\x07\xa3\xe4\x0e\x00\x00\x21\x3b\x07\xc1\xfc\x13\ +\x00\x00\x2c\xd0\x08\x27\xb4\xba\x00\x00\x90\xce\x08\x32\xc4\xaa\ +\x00\x00\x93\x96\x08\x36\x74\x14\x00\x00\x23\x30\x08\x44\xb9\x83\ +\x00\x00\x32\xf8\x08\x49\xc9\x30\x00\x00\x15\x41\x08\x61\x7c\xb3\ +\x00\x00\x1c\xe1\x08\xa2\xca\x67\x00\x00\x4b\x53\x08\xa3\xe0\x33\ +\x00\x00\x75\x2d\x08\xb1\x15\x28\x00\x00\x2d\x71\x08\xb4\x04\x04\ +\x00\x00\x95\x56\x08\xd0\x32\xf4\x00\x00\x79\xa2\x08\xd4\xcd\x69\ +\x00\x00\x7a\x1f\x08\xe1\x9b\xbe\x00\x00\x19\x35\x08\xe1\xc1\xfa\ +\x00\x00\x7b\xa3\x08\xeb\x8d\x7a\x00\x00\x9e\x31\x09\x20\xda\x24\ +\x00\x00\x9f\xa8\x09\x20\xda\xb4\x00\x00\xa0\x57\x09\x20\xda\xd4\ +\x00\x00\x9e\xd9\x09\x4d\x96\xd9\x00\x00\x24\x06\x09\x65\xda\x8a\ +\x00\x00\x7f\x7f\x09\x68\x0d\x29\x00\x00\x89\xc6\x09\x71\x8d\x25\ +\x00\x00\x06\x2c\x09\x75\x23\x14\x00\x00\x6f\x3a\x09\x76\xed\x34\ +\x00\x00\x61\x46\x09\x86\xa6\x05\x00\x00\x22\x56\x09\x8b\x23\xba\ +\x00\x00\x94\x01\x09\x9e\xfd\x7e\x00\x00\x61\x90\x09\xb6\x2a\x63\ +\x00\x00\x31\xcd\x09\xcd\x1c\x55\x00\x00\x96\x72\x09\xd2\x21\xea\ +\x00\x00\x59\xd5\x09\xe5\x23\x0e\x00\x00\x54\x03\x09\xec\x2b\x45\ +\x00\x00\x0b\xe5\x09\xef\x33\xa3\x00\x00\x17\x19\x09\xf0\x1f\x6e\ +\x00\x00\x03\x60\x09\xfd\x45\x1a\x00\x00\x8f\x78\x0a\x09\xc1\x7a\ +\x00\x00\x92\x39\x0a\x28\x9a\x65\x00\x00\x49\x80\x0a\x28\x9a\x67\ +\x00\x00\x49\xc7\x0a\x28\x9a\x69\x00\x00\x4a\x0e\x0a\x2d\xbe\xe4\ +\x00\x00\x2e\xcf\x0a\x35\xa9\xfa\x00\x00\x84\x46\x0a\x3f\x27\x74\ +\x00\x00\x76\xca\x0a\x3f\x6b\x05\x00\x00\x77\x07\x0a\x49\xa5\x4a\ +\x00\x00\x9b\x72\x0a\x60\xe0\x15\x00\x00\x25\x00\x0a\x60\xe0\x17\ +\x00\x00\x25\x53\x0a\x60\xe0\x19\x00\x00\x25\xa6\x0a\x65\x9b\xea\ +\x00\x00\x8c\xd4\x0a\x78\x05\x80\x00\x00\x01\x3f\x0a\x7f\x8f\x65\ +\x00\x00\x3a\x1e\x0a\x98\x86\x18\x00\x00\x28\xe3\x0a\x99\x5c\xaa\ +\x00\x00\x94\x5b\x0a\xa8\x16\x95\x00\x00\x11\xf9\x0a\xa9\x89\xec\ +\x00\x00\x41\x02\x0a\xc8\x5c\x59\x00\x00\x0f\x3f\x0a\xd0\x50\xb8\ +\x00\x00\x6e\x31\x0a\xd0\xe6\xf5\x00\x00\x16\xc2\x0a\xd6\xf1\xfa\ +\x00\x00\x79\x0d\x0a\xeb\x91\x88\x00\x00\x60\xa3\x0b\x07\x78\x8a\ +\x00\x00\x7e\xde\x0b\x1b\xe0\x73\x00\x00\x4c\x9a\x0b\x24\x9d\xb4\ +\x00\x00\x4d\x65\x0b\x24\xc5\xc9\x00\x00\x12\x69\x0b\x26\x7e\x0e\ +\x00\x00\x75\xea\x0b\x2b\x50\xfa\x00\x00\x82\x80\x0b\x2d\xb3\xf9\ +\x00\x00\x64\xd6\x0b\x37\x73\x69\x00\x00\x9d\x24\x0b\x40\x40\x3e\ +\x00\x00\x42\xa2\x0b\x43\xcd\x19\x00\x00\x41\x7c\x0b\x66\x28\xd2\ +\x00\x00\x60\x4e\x0b\x88\xe0\x07\x00\x00\x0a\x70\x0b\x94\x44\xc5\ +\x00\x00\x2f\x44\x0b\xc2\x99\x6a\x00\x00\x7e\x21\x0b\xd3\x27\xae\ +\x00\x00\x04\x3e\x0b\xd4\x7e\x9e\x00\x00\x0a\xa7\x0b\xf5\xee\x53\ +\x00\x00\x8c\x67\x0c\x06\x50\x2e\x00\x00\x0c\xbc\x0c\x08\x46\x23\ +\x00\x00\x77\x9a\x0c\x19\xfa\x99\x00\x00\x7a\xa7\x0c\x28\x9b\x45\ +\x00\x00\x6e\xaf\x0c\x31\x7e\x4a\x00\x00\x90\x1e\x0c\x38\x4d\xe5\ +\x00\x00\x07\x20\x0c\x3a\x16\xd0\x00\x00\x18\x0a\x0c\x5a\xc0\xc8\ +\x00\x00\x72\x64\x0c\x6e\x87\xf5\x00\x00\x20\xfe\x0c\x91\xa0\x7a\ +\x00\x00\x9a\xdc\x0c\x96\x90\x59\x00\x00\x41\xd5\x0c\xca\xdd\xfa\ +\x00\x00\x99\x26\x0c\xd6\xef\x12\x00\x00\x2c\x75\x0c\xde\x99\x49\ +\x00\x00\x65\x22\x0c\xf0\xde\xaa\x00\x00\x81\x1f\x0d\x1c\xf6\xee\ +\x00\x00\x2a\x5d\x0d\x3a\x6c\xba\x00\x00\x90\x74\x0d\x45\xe2\x6a\ +\x00\x00\x97\xe4\x0d\x59\xa1\x45\x00\x00\x78\x15\x0d\x5a\xad\x33\ +\x00\x00\x71\x53\x0d\x5e\xe7\x6e\x00\x00\x25\xf9\x0d\x64\xa5\xd9\ +\x00\x00\x58\x1a\x0d\x6d\xf8\xf4\x00\x00\x07\xd1\x0d\x76\xb5\x92\ +\x00\x00\x2a\xb1\x0d\x9b\xec\xc9\x00\x00\x50\x5b\x0d\xa5\xd9\x94\ +\x00\x00\x2a\x04\x0d\xa6\xda\xa4\x00\x00\x43\xc7\x0d\xc6\xc6\x2a\ +\x00\x00\x93\x3a\x0d\xf2\x39\xba\x00\x00\x84\xf9\x0e\x2b\x04\x15\ +\x00\x00\x75\xab\x0e\x2c\xe4\x2a\x00\x00\x97\x71\x0e\x4e\xcc\xc5\ +\x00\x00\x09\x1e\x0e\x6f\x9a\x1a\x00\x00\x99\xb6\x0e\x7b\x7a\x2c\ +\x00\x00\x30\x36\x0e\x8f\x6a\x37\x00\x00\x34\x4c\x0e\x91\x65\xf5\ +\x00\x00\x18\xbd\x0e\xca\xd7\x34\x00\x00\x1e\x9d\x0e\xcd\x1c\x55\ +\x00\x00\x96\xc7\x0e\xcd\x1c\x65\x00\x00\x97\x1c\x0e\xea\xe5\x03\ +\x00\x00\x6c\x40\x0e\xed\xe1\xf9\x00\x00\x44\x75\x0f\x07\x8d\xe3\ +\x00\x00\x6c\xe2\x0f\x17\x82\x4e\x00\x00\x00\xe9\x0f\x1f\x8d\xa5\ +\x00\x00\x75\x65\x0f\x4f\x75\x3a\x00\x00\xa0\xc9\x0f\x5f\xca\xd5\ +\x00\x00\x2f\xc3\x0f\x75\xb0\x54\x00\x00\x77\x4a\x0f\x77\xc3\xb4\ +\x00\x00\x65\xfe\x0f\x89\x0b\xbe\x00\x00\x44\xd7\x0f\x8f\xa8\xa7\ +\x00\x00\x17\xbd\x0f\x98\x0a\x39\x00\x00\x9c\x86\x0f\x9e\xec\xa0\ +\x00\x00\x11\x42\x0f\xbf\x87\xa3\x00\x00\x8a\xb5\x0f\xcd\xce\x95\ +\x00\x00\x33\xda\x0f\xdf\x21\x05\x00\x00\x22\xd7\x0f\xf6\x06\x1e\ +\x00\x00\x1e\xfd\x0f\xf6\x29\x0a\x00\x00\x71\x09\x0f\xf7\x77\xaa\ +\x00\x00\x80\x82\x0f\xfb\x5f\xae\x00\x00\x76\x3a\x69\x00\x00\xa1\ +\x77\x03\x00\x00\x00\x16\x00\x44\x00\x6f\x00\x64\x00\x61\x00\x6a\ +\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x09\x41\x64\x64\x20\x50\x6f\x69\x6e\x74\x07\ +\x00\x00\x00\x0e\x44\x72\x61\x66\x74\x5f\x41\x64\x64\x50\x6f\x69\ +\x6e\x74\x01\x03\x00\x00\x00\x5c\x00\x57\x00\x73\x00\x74\x00\x61\ +\x00\x77\x00\x69\x00\x61\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\ +\x00\x74\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x62\x00\x69\x00\x65\ +\x01\x7c\x01\x05\x00\x63\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x73\ +\x00\x7a\x00\x6b\x00\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x75\ +\x00\x2f\x00\x42\x00\x2d\x00\x53\x00\x70\x00\x6c\x00\x61\x00\x6a\ +\x00\x6e\x00\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x28\x41\x64\ +\x64\x73\x20\x61\x20\x70\x6f\x69\x6e\x74\x20\x74\x6f\x20\x61\x6e\ +\x20\x65\x78\x69\x73\x74\x69\x6e\x67\x20\x77\x69\x72\x65\x2f\x62\ +\x73\x70\x6c\x69\x6e\x65\x07\x00\x00\x00\x0e\x44\x72\x61\x66\x74\ +\x5f\x41\x64\x64\x50\x6f\x69\x6e\x74\x01\x03\x00\x00\x00\x22\x00\ +\x44\x00\x6f\x00\x64\x00\x61\x00\x6a\x00\x20\x00\x64\x00\x6f\x00\ +\x20\x00\x67\x00\x72\x00\x75\x00\x70\x00\x79\x00\x2e\x00\x2e\x00\ +\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0f\x41\x64\x64\x20\x74\ +\x6f\x20\x67\x72\x6f\x75\x70\x2e\x2e\x2e\x07\x00\x00\x00\x10\x44\ +\x72\x61\x66\x74\x5f\x41\x64\x64\x54\x6f\x47\x72\x6f\x75\x70\x01\ +\x03\x00\x00\x00\x62\x00\x44\x00\x6f\x00\x64\x00\x61\x00\x77\x00\ +\x61\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\ +\x6e\x00\x61\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x79\x00\x63\x00\ +\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\xf3\x00\x77\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x62\x00\x69\x00\ +\x65\x01\x7c\x01\x05\x00\x63\x00\x65\x00\x6a\x00\x20\x00\x67\x00\ +\x72\x00\x75\x00\x70\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x30\x41\x64\x64\x73\x20\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\ +\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x28\x73\x29\x20\x74\x6f\x20\ +\x61\x6e\x20\x65\x78\x69\x73\x74\x69\x6e\x67\x20\x67\x72\x6f\x75\ +\x70\x07\x00\x00\x00\x10\x44\x72\x61\x66\x74\x5f\x41\x64\x64\x54\ +\x6f\x47\x72\x6f\x75\x70\x01\x03\x00\x00\x00\x84\x00\x53\x00\x74\ +\x00\x6f\x00\x73\x00\x75\x00\x6a\x00\x65\x00\x20\x00\x62\x00\x69\ +\x00\x65\x01\x7c\x01\x05\x00\x63\x01\x05\x00\x20\x00\x73\x00\x7a\ +\x00\x65\x00\x72\x00\x6f\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\ +\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x00\x20\x00\x69\x00\x20\ +\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\xf3\x00\x77\x00\x20\ +\x00\x64\x00\x6f\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\x61\ +\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x79\x00\x63\x00\x68\x00\x20\ +\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\xf3\x00\x77\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x38\x41\x70\x70\x6c\x69\x65\ +\x73\x20\x63\x75\x72\x72\x65\x6e\x74\x20\x6c\x69\x6e\x65\x20\x77\ +\x69\x64\x74\x68\x20\x61\x6e\x64\x20\x63\x6f\x6c\x6f\x72\x20\x74\ +\x6f\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\ +\x74\x73\x07\x00\x00\x00\x10\x44\x72\x61\x66\x74\x5f\x41\x70\x70\ +\x6c\x79\x53\x74\x79\x6c\x65\x01\x03\x00\x00\x00\x2a\x00\x5a\x00\ +\x61\x00\x73\x00\x74\x00\x6f\x00\x73\x00\x75\x00\x6a\x00\x20\x00\ +\x42\x00\x69\x00\x65\x01\x7c\x01\x05\x00\x63\x00\x79\x00\x20\x00\ +\x73\x00\x74\x00\x79\x00\x6c\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x13\x41\x70\x70\x6c\x79\x20\x43\x75\x72\x72\x65\x6e\x74\x20\x53\ +\x74\x79\x6c\x65\x07\x00\x00\x00\x10\x44\x72\x61\x66\x74\x5f\x41\ +\x70\x70\x6c\x79\x53\x74\x79\x6c\x65\x01\x03\x00\x00\x00\x06\x01\ +\x41\x00\x75\x00\x6b\x08\x00\x00\x00\x00\x06\x00\x00\x00\x03\x41\ +\x72\x63\x07\x00\x00\x00\x09\x44\x72\x61\x66\x74\x5f\x41\x72\x63\ +\x01\x03\x00\x00\x00\x56\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\ +\x00\x79\x00\x20\x01\x42\x00\x75\x00\x6b\x00\x2e\x00\x20\x00\x43\ +\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\x00\x7a\x00\x79\ +\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6a\x00\x2c\x00\x20\ +\x00\x53\x00\x48\x00\x49\x00\x46\x00\x54\x00\x20\x00\x6f\x00\x67\ +\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x30\x43\x72\x65\x61\x74\x65\x73\x20\x61\x6e\ +\x20\x61\x72\x63\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\x6e\ +\x61\x70\x2c\x20\x53\x48\x49\x46\x54\x20\x74\x6f\x20\x63\x6f\x6e\ +\x73\x74\x72\x61\x69\x6e\x07\x00\x00\x00\x09\x44\x72\x61\x66\x74\ +\x5f\x41\x72\x63\x01\x03\x00\x00\x00\x10\x00\x42\x00\x2d\x00\x53\ +\x00\x70\x00\x6c\x00\x61\x00\x6a\x00\x6e\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x08\x42\x2d\x53\x70\x6c\x69\x6e\x65\x07\x00\x00\x00\ +\x0d\x44\x72\x61\x66\x74\x5f\x42\x53\x70\x6c\x69\x6e\x65\x01\x03\ +\x00\x00\x00\x86\x00\x43\x00\x72\x00\x65\x00\x61\x00\x74\x00\x65\ +\x00\x73\x00\x20\x00\x61\x00\x20\x00\x6d\x00\x75\x00\x6c\x00\x74\ +\x00\x69\x00\x70\x00\x6c\x00\x65\x00\x2d\x00\x70\x00\x6f\x00\x69\ +\x00\x6e\x00\x74\x00\x20\x00\x62\x00\x2d\x00\x73\x00\x70\x00\x6c\ +\x00\x69\x00\x6e\x00\x65\x00\x2e\x00\x20\x00\x43\x00\x54\x00\x52\ +\x00\x4c\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x73\x00\x6e\x00\x61\ +\x00\x70\x00\x2c\x00\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\x54\ +\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x63\x00\x6f\x00\x6e\x00\x73\ +\x00\x74\x00\x72\x00\x61\x00\x69\x00\x6e\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x43\x43\x72\x65\x61\x74\x65\x73\x20\x61\x20\x6d\x75\ +\x6c\x74\x69\x70\x6c\x65\x2d\x70\x6f\x69\x6e\x74\x20\x62\x2d\x73\ +\x70\x6c\x69\x6e\x65\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\ +\x6e\x61\x70\x2c\x20\x53\x48\x49\x46\x54\x20\x74\x6f\x20\x63\x6f\ +\x6e\x73\x74\x72\x61\x69\x6e\x07\x00\x00\x00\x0d\x44\x72\x61\x66\ +\x74\x5f\x42\x53\x70\x6c\x69\x6e\x65\x01\x03\x00\x00\x00\x0a\x00\ +\x4f\x00\x6b\x00\x72\x01\x05\x00\x67\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x06\x43\x69\x72\x63\x6c\x65\x07\x00\x00\x00\x0c\x44\x72\ +\x61\x66\x74\x5f\x43\x69\x72\x63\x6c\x65\x01\x03\x00\x00\x00\x74\ +\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\x6f\ +\x00\x6b\x00\x72\x01\x05\x00\x67\x00\x2e\x00\x20\x00\x43\x00\x54\ +\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\x00\x7a\x00\x79\x00\x63\ +\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6a\x00\x2c\x00\x20\x00\x41\ +\x00\x4c\x00\x54\x00\x20\x00\x77\x00\x79\x00\x62\x00\x69\x00\x65\ +\x00\x72\x00\x7a\x00\x20\x00\x73\x00\x74\x00\x79\x00\x63\x00\x7a\ +\x00\x6e\x01\x05\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\ +\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x3d\x43\x72\ +\x65\x61\x74\x65\x73\x20\x61\x20\x63\x69\x72\x63\x6c\x65\x2e\x20\ +\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\x6e\x61\x70\x2c\x20\x41\x4c\ +\x54\x20\x74\x6f\x20\x73\x65\x6c\x65\x63\x74\x20\x74\x61\x6e\x67\ +\x65\x6e\x74\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\x00\x00\x0c\ +\x44\x72\x61\x66\x74\x5f\x43\x69\x72\x63\x6c\x65\x01\x03\x00\x00\ +\x00\x1a\x00\x5a\x00\x61\x00\x6d\x00\x6b\x00\x6e\x00\x69\x00\x6a\ +\x00\x20\x00\x4c\x00\x69\x00\x6e\x00\x69\x01\x19\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x0a\x43\x6c\x6f\x73\x65\x20\x4c\x69\x6e\x65\ +\x07\x00\x00\x00\x0f\x44\x72\x61\x66\x74\x5f\x43\x6c\x6f\x73\x65\ +\x4c\x69\x6e\x65\x01\x03\x00\x00\x00\x2a\x00\x5a\x00\x61\x00\x6d\ +\x00\x79\x00\x6b\x00\x61\x00\x20\x00\x72\x00\x79\x00\x73\x00\x6f\ +\x00\x77\x00\x61\x00\x6e\x01\x05\x00\x20\x00\x6c\x00\x69\x00\x6e\ +\x00\x69\x01\x19\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1b\x43\x6c\ +\x6f\x73\x65\x73\x20\x74\x68\x65\x20\x6c\x69\x6e\x65\x20\x62\x65\ +\x69\x6e\x67\x20\x64\x72\x61\x77\x6e\x07\x00\x00\x00\x0f\x44\x72\ +\x61\x66\x74\x5f\x43\x6c\x6f\x73\x65\x4c\x69\x6e\x65\x01\x03\x00\ +\x00\x00\x14\x00\x55\x00\x73\x00\x75\x01\x44\x00\x20\x00\x70\x00\ +\x75\x00\x6e\x00\x6b\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x0c\x52\x65\x6d\x6f\x76\x65\x20\x50\x6f\x69\x6e\x74\x07\x00\x00\ +\x00\x0e\x44\x72\x61\x66\x74\x5f\x44\x65\x6c\x50\x6f\x69\x6e\x74\ +\x01\x03\x00\x00\x00\x5e\x00\x55\x00\x73\x00\x75\x00\x77\x00\x61\ +\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x20\x00\x7a\ +\x00\x20\x00\x62\x00\x69\x00\x65\x01\x7c\x01\x05\x00\x63\x00\x65\ +\x00\x67\x00\x6f\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\x69\x00\x65\ +\x00\x6c\x00\x65\x00\x74\x00\x75\x00\x20\x00\x6c\x00\x75\x00\x62\ +\x00\x20\x00\x42\x00\x2d\x00\x53\x00\x70\x00\x6c\x00\x61\x00\x6a\ +\x00\x6e\x00\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x30\x52\x65\ +\x6d\x6f\x76\x65\x73\x20\x61\x20\x70\x6f\x69\x6e\x74\x20\x66\x72\ +\x6f\x6d\x20\x61\x6e\x20\x65\x78\x69\x73\x74\x69\x6e\x67\x20\x77\ +\x69\x72\x65\x20\x6f\x72\x20\x62\x73\x70\x6c\x69\x6e\x65\x07\x00\ +\x00\x00\x0e\x44\x72\x61\x66\x74\x5f\x44\x65\x6c\x50\x6f\x69\x6e\ +\x74\x01\x03\x00\x00\x00\xa2\x00\x54\x00\x77\x00\x6f\x00\x72\x00\ +\x7a\x00\x79\x00\x20\x00\x77\x00\x79\x00\x6d\x00\x69\x00\x61\x00\ +\x72\x00\x2e\x00\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\ +\x70\x00\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\ +\x61\x00\x6a\x00\x2c\x00\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\ +\x54\x00\x2c\x00\x20\x00\x61\x00\x62\x00\x79\x00\x20\x00\x6f\x00\ +\x67\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\x00\x79\x01\ +\x07\x00\x2c\x00\x20\x00\x41\x00\x4c\x00\x54\x00\x2c\x00\x20\x00\ +\x61\x00\x62\x00\x79\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\ +\x61\x00\x63\x00\x7a\x00\x79\x01\x07\x00\x20\x00\x73\x00\x65\x00\ +\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x4e\x43\x72\x65\x61\x74\x65\x73\x20\x61\x20\x64\x69\x6d\ +\x65\x6e\x73\x69\x6f\x6e\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\ +\x73\x6e\x61\x70\x2c\x20\x53\x48\x49\x46\x54\x20\x74\x6f\x20\x63\ +\x6f\x6e\x73\x74\x72\x61\x69\x6e\x2c\x20\x41\x4c\x54\x20\x74\x6f\ +\x20\x73\x65\x6c\x65\x63\x74\x20\x61\x20\x73\x65\x67\x6d\x65\x6e\ +\x74\x07\x00\x00\x00\x0f\x44\x72\x61\x66\x74\x5f\x44\x69\x6d\x65\ +\x6e\x73\x69\x6f\x6e\x01\x03\x00\x00\x00\x0c\x00\x57\x00\x79\x00\ +\x6d\x00\x69\x00\x61\x00\x72\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x09\x44\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x07\x00\x00\x00\x0f\x44\ +\x72\x61\x66\x74\x5f\x44\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x01\x03\ +\x00\x00\x00\x3c\x00\x5a\x00\x61\x00\x69\x00\x6e\x00\x73\x00\x74\ +\x00\x61\x00\x6c\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x65\ +\x00\x20\x00\x73\x00\x74\x00\x61\x00\x72\x00\x73\x00\x7a\x00\x65\ +\x00\x6a\x00\x20\x00\x77\x00\x65\x00\x72\x00\x73\x00\x6a\x00\x69\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09\x44\x6f\x77\x6e\x67\x72\ +\x61\x64\x65\x07\x00\x00\x00\x0f\x44\x72\x61\x66\x74\x5f\x44\x6f\ +\x77\x6e\x67\x72\x61\x64\x65\x01\x03\x00\x00\x00\x80\x00\x52\x00\ +\x6f\x00\x7a\x00\x77\x00\x69\x00\x6a\x00\x61\x00\x20\x00\x7a\x00\ +\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\ +\x65\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\x79\x00\x20\x00\x6e\x00\x61\x00\x20\x00\x70\x00\x72\x00\x6f\x00\ +\x73\x00\x74\x00\x73\x00\x7a\x00\x65\x00\x20\x00\x6c\x00\x75\x00\ +\x62\x00\x20\x00\x6f\x00\x64\x00\x65\x00\x6a\x00\x6d\x00\x75\x00\ +\x6a\x00\x65\x00\x20\x00\x70\x00\x6f\x00\x77\x00\x69\x00\x65\x00\ +\x72\x00\x7a\x00\x63\x00\x68\x00\x6e\x00\x69\x00\x65\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x45\x45\x78\x70\x6c\x6f\x64\x65\x73\x20\ +\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\ +\x65\x63\x74\x73\x20\x69\x6e\x74\x6f\x20\x73\x69\x6d\x70\x6c\x65\ +\x72\x20\x6f\x62\x6a\x65\x63\x74\x73\x2c\x20\x6f\x72\x20\x73\x75\ +\x62\x74\x72\x61\x63\x74\x20\x66\x61\x63\x65\x73\x07\x00\x00\x00\ +\x0f\x44\x72\x61\x66\x74\x5f\x44\x6f\x77\x6e\x67\x72\x61\x64\x65\ +\x01\x03\x00\x00\x00\x0e\x00\x52\x00\x79\x00\x73\x00\x75\x00\x6e\ +\x00\x65\x00\x6b\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07\x44\x72\ +\x61\x77\x69\x6e\x67\x07\x00\x00\x00\x0d\x44\x72\x61\x66\x74\x5f\ +\x44\x72\x61\x77\x69\x6e\x67\x01\x03\x00\x00\x00\x60\x00\x55\x00\ +\x6d\x00\x69\x00\x65\x00\x73\x00\x7a\x00\x63\x00\x7a\x00\x61\x00\ +\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\ +\x6f\x00\x6e\x00\x65\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x79\x00\x20\x00\x6e\x00\x61\x00\x20\x00\x61\x00\ +\x72\x00\x6b\x00\x75\x00\x73\x00\x7a\x00\x75\x00\x20\x00\x72\x00\ +\x79\x00\x73\x00\x75\x00\x6e\x00\x6b\x00\x75\x00\x2e\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x2d\x50\x75\x74\x73\x20\x74\x68\x65\x20\ +\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\ +\x20\x6f\x6e\x20\x61\x20\x44\x72\x61\x77\x69\x6e\x67\x20\x73\x68\ +\x65\x65\x74\x2e\x07\x00\x00\x00\x0d\x44\x72\x61\x66\x74\x5f\x44\ +\x72\x61\x77\x69\x6e\x67\x01\x03\x00\x00\x00\x0c\x00\x45\x00\x64\ +\x00\x79\x00\x74\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x04\x45\x64\x69\x74\x07\x00\x00\x00\x0a\x44\x72\x61\x66\x74\ +\x5f\x45\x64\x69\x74\x01\x03\x00\x00\x00\x2a\x00\x45\x00\x64\x00\ +\x79\x00\x74\x00\x75\x00\x6a\x00\x20\x00\x61\x00\x6b\x00\x74\x00\ +\x79\x00\x77\x00\x6e\x00\x79\x00\x20\x00\x6f\x00\x62\x00\x69\x00\ +\x65\x00\x6b\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17\x45\ +\x64\x69\x74\x73\x20\x74\x68\x65\x20\x61\x63\x74\x69\x76\x65\x20\ +\x6f\x62\x6a\x65\x63\x74\x07\x00\x00\x00\x0a\x44\x72\x61\x66\x74\ +\x5f\x45\x64\x69\x74\x01\x03\x00\x00\x00\x22\x00\x5a\x00\x61\x00\ +\x6b\x00\x6f\x01\x44\x00\x63\x00\x7a\x00\x65\x00\x6e\x00\x69\x00\ +\x65\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x0b\x46\x69\x6e\x69\x73\x68\x20\x6c\x69\ +\x6e\x65\x07\x00\x00\x00\x10\x44\x72\x61\x66\x74\x5f\x46\x69\x6e\ +\x69\x73\x68\x4c\x69\x6e\x65\x01\x03\x00\x00\x00\x3e\x00\x5a\x00\ +\x61\x00\x6b\x00\x6f\x01\x44\x00\x63\x00\x7a\x00\x65\x00\x6e\x00\ +\x69\x00\x65\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x00\ +\x20\x00\x62\x00\x65\x00\x7a\x00\x20\x00\x7a\x00\x61\x00\x6d\x00\ +\x79\x00\x6b\x00\x61\x00\x6e\x00\x69\x00\x61\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x22\x46\x69\x6e\x69\x73\x68\x65\x73\x20\x61\x20\ +\x6c\x69\x6e\x65\x20\x77\x69\x74\x68\x6f\x75\x74\x20\x63\x6c\x6f\ +\x73\x69\x6e\x67\x20\x69\x74\x07\x00\x00\x00\x10\x44\x72\x61\x66\ +\x74\x5f\x46\x69\x6e\x69\x73\x68\x4c\x69\x6e\x65\x01\x03\x00\x00\ +\x00\x6e\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\ +\x00\x32\x00\x2d\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x6f\ +\x00\x77\x00\x65\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x65\x00\x2e\ +\x00\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\ +\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6a\ +\x00\x2c\x00\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\x54\x00\x20\ +\x00\x6f\x00\x67\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x38\x43\x72\x65\x61\x74\x65\ +\x73\x20\x61\x20\x32\x2d\x70\x6f\x69\x6e\x74\x20\x6c\x69\x6e\x65\ +\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\x6e\x61\x70\x2c\x20\ +\x53\x48\x49\x46\x54\x20\x74\x6f\x20\x63\x6f\x6e\x73\x74\x72\x61\ +\x69\x6e\x07\x00\x00\x00\x0a\x44\x72\x61\x66\x74\x5f\x4c\x69\x6e\ +\x65\x01\x03\x00\x00\x00\x0a\x00\x4c\x00\x69\x00\x6e\x00\x69\x00\ +\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04\x4c\x69\x6e\x65\x07\ +\x00\x00\x00\x0a\x44\x72\x61\x66\x74\x5f\x4c\x69\x6e\x65\x01\x03\ +\x00\x00\x00\x0e\x00\x50\x00\x72\x00\x7a\x00\x65\x00\x73\x00\x75\ +\x01\x44\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04\x4d\x6f\x76\x65\ +\x07\x00\x00\x00\x0a\x44\x72\x61\x66\x74\x5f\x4d\x6f\x76\x65\x01\ +\x03\x00\x00\x00\xb4\x00\x50\x00\x72\x00\x7a\x00\x65\x00\x6e\x00\ +\x6f\x00\x73\x00\x69\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\ +\x61\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\x00\x20\x00\x6f\x00\ +\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x20\x00\x6d\x00\ +\x69\x01\x19\x00\x64\x00\x7a\x00\x79\x00\x20\x00\x32\x00\x20\x00\ +\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x79\x00\x2e\x00\x20\x00\ +\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\x00\x7a\x00\ +\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6a\x00\x2c\x00\ +\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\x54\x00\x2c\x00\x20\x00\ +\x6f\x00\x67\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\x00\ +\x2c\x00\x20\x00\x41\x00\x4c\x00\x54\x00\x2c\x00\x20\x00\x6b\x00\ +\x6f\x00\x70\x00\x69\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x5a\x4d\x6f\x76\x65\x73\x20\x74\x68\x65\x20\x73\x65\x6c\ +\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x62\x65\ +\x74\x77\x65\x65\x6e\x20\x32\x20\x70\x6f\x69\x6e\x74\x73\x2e\x20\ +\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\x6e\x61\x70\x2c\x20\x53\x48\ +\x49\x46\x54\x20\x74\x6f\x20\x63\x6f\x6e\x73\x74\x72\x61\x69\x6e\ +\x2c\x20\x41\x4c\x54\x20\x74\x6f\x20\x63\x6f\x70\x79\x07\x00\x00\ +\x00\x0a\x44\x72\x61\x66\x74\x5f\x4d\x6f\x76\x65\x01\x03\x00\x00\ +\x00\x0c\x00\x4f\x00\x66\x00\x66\x00\x73\x00\x65\x00\x74\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x06\x4f\x66\x66\x73\x65\x74\x07\x00\ +\x00\x00\x0c\x44\x72\x61\x66\x74\x5f\x4f\x66\x66\x73\x65\x74\x01\ +\x03\x00\x00\x00\x90\x00\x4f\x00\x66\x00\x66\x00\x73\x00\x65\x00\ +\x74\x00\x20\x00\x61\x00\x6b\x00\x74\x00\x79\x00\x77\x00\x6e\x00\ +\x65\x00\x67\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x75\x00\x2e\x00\x20\x00\x43\x00\x54\x00\x52\x00\ +\x4c\x00\x20\x00\x70\x00\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\ +\x05\x00\x67\x00\x6e\x00\x69\x00\x6a\x00\x2c\x00\x20\x00\x53\x00\ +\x48\x00\x49\x00\x46\x00\x54\x00\x2c\x00\x20\x00\x6f\x00\x67\x00\ +\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\x00\x2c\x00\x20\x00\ +\x41\x00\x4c\x00\x54\x00\x2c\x00\x20\x00\x6b\x00\x6f\x00\x70\x00\ +\x69\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x48\x4f\ +\x66\x66\x73\x65\x74\x73\x20\x74\x68\x65\x20\x61\x63\x74\x69\x76\ +\x65\x20\x6f\x62\x6a\x65\x63\x74\x2e\x20\x43\x54\x52\x4c\x20\x74\ +\x6f\x20\x73\x6e\x61\x70\x2c\x20\x53\x48\x49\x46\x54\x20\x74\x6f\ +\x20\x63\x6f\x6e\x73\x74\x72\x61\x69\x6e\x2c\x20\x41\x4c\x54\x20\ +\x74\x6f\x20\x63\x6f\x70\x79\x07\x00\x00\x00\x0c\x44\x72\x61\x66\ +\x74\x5f\x4f\x66\x66\x73\x65\x74\x01\x03\x00\x00\x00\x74\x00\x54\ +\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\x72\x00\x65\ +\x00\x67\x00\x75\x00\x6c\x00\x61\x00\x72\x00\x6e\x00\x79\x00\x20\ +\x00\x77\x00\x69\x00\x65\x00\x6c\x00\x6f\x00\x62\x00\x6f\x00\x6b\ +\x00\x2e\x00\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\ +\x00\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\ +\x00\x6a\x00\x2c\x00\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\x54\ +\x00\x20\x00\x6f\x00\x67\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\ +\x00\x7a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x3b\x43\x72\x65\x61\ +\x74\x65\x73\x20\x61\x20\x72\x65\x67\x75\x6c\x61\x72\x20\x70\x6f\ +\x6c\x79\x67\x6f\x6e\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\ +\x6e\x61\x70\x2c\x20\x53\x48\x49\x46\x54\x20\x74\x6f\x20\x63\x6f\ +\x6e\x73\x74\x72\x61\x69\x6e\x07\x00\x00\x00\x0d\x44\x72\x61\x66\ +\x74\x5f\x50\x6f\x6c\x79\x67\x6f\x6e\x01\x03\x00\x00\x00\x10\x00\ +\x57\x00\x69\x00\x65\x00\x6c\x00\x6f\x00\x6b\x01\x05\x00\x74\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x07\x50\x6f\x6c\x79\x67\x6f\x6e\ +\x07\x00\x00\x00\x0d\x44\x72\x61\x66\x74\x5f\x50\x6f\x6c\x79\x67\ +\x6f\x6e\x01\x03\x00\x00\x00\x6a\x00\x54\x00\x77\x00\x6f\x00\x72\ +\x00\x7a\x00\x79\x00\x20\x00\x70\x00\x72\x00\x6f\x00\x73\x00\x74\ +\x00\x6f\x00\x6b\x01\x05\x00\x74\x00\x20\x00\x77\x00\x7a\x00\x67\ +\x00\x6c\x01\x19\x00\x64\x00\x65\x00\x6d\x00\x20\x00\x32\x00\x20\ +\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\xf3\x00\x77\x00\x2e\ +\x00\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\ +\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x6e\x00\x69\ +\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x29\x43\x72\x65\x61\ +\x74\x65\x73\x20\x61\x20\x32\x2d\x70\x6f\x69\x6e\x74\x20\x72\x65\ +\x63\x74\x61\x6e\x67\x6c\x65\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\ +\x20\x73\x6e\x61\x70\x07\x00\x00\x00\x0f\x44\x72\x61\x66\x74\x5f\ +\x52\x65\x63\x74\x61\x6e\x67\x6c\x65\x01\x03\x00\x00\x00\x12\x00\ +\x50\x00\x72\x00\x6f\x00\x73\x00\x74\x00\x6f\x00\x6b\x01\x05\x00\ +\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09\x52\x65\x63\x74\x61\ +\x6e\x67\x6c\x65\x07\x00\x00\x00\x0f\x44\x72\x61\x66\x74\x5f\x52\ +\x65\x63\x74\x61\x6e\x67\x6c\x65\x01\x03\x00\x00\x00\x0a\x00\x4f\ +\x00\x62\x00\x72\x00\xf3\x01\x07\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x06\x52\x6f\x74\x61\x74\x65\x07\x00\x00\x00\x0c\x44\x72\x61\ +\x66\x74\x5f\x52\x6f\x74\x61\x74\x65\x01\x03\x00\x00\x00\x94\x00\ +\x4f\x00\x62\x00\x72\x00\x61\x00\x63\x00\x61\x00\x20\x00\x77\x00\ +\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\x65\x00\x20\x00\x6f\x00\ +\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x2e\x00\x20\x00\ +\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\x00\x7a\x00\ +\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6a\x00\x2c\x00\ +\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\x54\x00\x2c\x00\x20\x00\ +\x6f\x00\x67\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\x00\ +\x2c\x00\x20\x00\x41\x00\x4c\x00\x54\x00\x20\x00\x74\x00\x77\x00\ +\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\x6b\x00\x6f\x00\x70\x00\ +\x69\x01\x19\x08\x00\x00\x00\x00\x06\x00\x00\x00\x52\x52\x6f\x74\ +\x61\x74\x65\x73\x20\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\x65\ +\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x2e\x20\x43\x54\x52\x4c\x20\ +\x74\x6f\x20\x73\x6e\x61\x70\x2c\x20\x53\x48\x49\x46\x54\x20\x74\ +\x6f\x20\x63\x6f\x6e\x73\x74\x72\x61\x69\x6e\x2c\x20\x41\x4c\x54\ +\x20\x63\x72\x65\x61\x74\x65\x73\x20\x61\x20\x63\x6f\x70\x79\x07\ +\x00\x00\x00\x0c\x44\x72\x61\x66\x74\x5f\x52\x6f\x74\x61\x74\x65\ +\x01\x03\x00\x00\x00\x0a\x00\x53\x00\x6b\x00\x61\x00\x6c\x00\x61\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\x53\x63\x61\x6c\x65\x07\ +\x00\x00\x00\x0b\x44\x72\x61\x66\x74\x5f\x53\x63\x61\x6c\x65\x01\ +\x03\x00\x00\x00\xd4\x00\x53\x00\x6b\x00\x61\x00\x6c\x00\x75\x00\ +\x6a\x00\x65\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\ +\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\x00\x20\x00\x6f\x00\x62\x00\ +\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x20\x00\x7a\x00\x20\x00\ +\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x75\x00\x20\x00\x62\x00\ +\x61\x00\x7a\x00\x6f\x00\x77\x00\x65\x00\x67\x00\x6f\x00\x2e\x00\ +\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\x00\x72\x00\ +\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6e\x00\ +\x69\x00\x65\x00\x2c\x00\x20\x00\x53\x00\x48\x00\x49\x00\x46\x00\ +\x54\x00\x2c\x00\x20\x00\x61\x00\x62\x00\x79\x00\x20\x00\x6f\x00\ +\x67\x00\x72\x00\x61\x00\x6e\x00\x69\x00\x63\x00\x7a\x00\x79\x01\ +\x07\x00\x2c\x00\x20\x00\x41\x00\x4c\x00\x54\x00\x2c\x00\x20\x00\ +\x61\x00\x62\x00\x79\x00\x20\x00\x73\x00\x6b\x00\x6f\x00\x70\x00\ +\x69\x00\x6f\x00\x77\x00\x61\x01\x07\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x5c\x53\x63\x61\x6c\x65\x73\x20\x74\x68\x65\x20\x73\x65\ +\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x66\ +\x72\x6f\x6d\x20\x61\x20\x62\x61\x73\x65\x20\x70\x6f\x69\x6e\x74\ +\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\x6e\x61\x70\x2c\x20\ +\x53\x48\x49\x46\x54\x20\x74\x6f\x20\x63\x6f\x6e\x73\x74\x72\x61\ +\x69\x6e\x2c\x20\x41\x4c\x54\x20\x74\x6f\x20\x63\x6f\x70\x79\x07\ +\x00\x00\x00\x0b\x44\x72\x61\x66\x74\x5f\x53\x63\x61\x6c\x65\x01\ +\x03\x00\x00\x00\x20\x00\x5a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\ +\x63\x00\x7a\x00\x20\x00\x67\x00\x72\x00\x75\x00\x70\x01\x19\x00\ +\x2e\x00\x2e\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c\x53\ +\x65\x6c\x65\x63\x74\x20\x67\x72\x6f\x75\x70\x07\x00\x00\x00\x11\ +\x44\x72\x61\x66\x74\x5f\x53\x65\x6c\x65\x63\x74\x47\x72\x6f\x75\ +\x70\x01\x03\x00\x00\x00\x6e\x00\x53\x00\x65\x00\x6c\x00\x65\x00\ +\x63\x00\x74\x00\x73\x00\x20\x00\x61\x00\x6c\x00\x6c\x00\x20\x00\ +\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\x73\x00\x20\x00\ +\x77\x00\x69\x00\x74\x00\x68\x00\x20\x00\x74\x00\x68\x00\x65\x00\ +\x20\x00\x73\x00\x61\x00\x6d\x00\x65\x00\x20\x00\x70\x00\x61\x00\ +\x72\x00\x65\x00\x6e\x00\x74\x00\x73\x00\x20\x00\x61\x00\x73\x00\ +\x20\x00\x74\x00\x68\x00\x69\x00\x73\x00\x20\x00\x67\x00\x72\x00\ +\x6f\x00\x75\x00\x70\x08\x00\x00\x00\x00\x06\x00\x00\x00\x37\x53\ +\x65\x6c\x65\x63\x74\x73\x20\x61\x6c\x6c\x20\x6f\x62\x6a\x65\x63\ +\x74\x73\x20\x77\x69\x74\x68\x20\x74\x68\x65\x20\x73\x61\x6d\x65\ +\x20\x70\x61\x72\x65\x6e\x74\x73\x20\x61\x73\x20\x74\x68\x69\x73\ +\x20\x67\x72\x6f\x75\x70\x07\x00\x00\x00\x11\x44\x72\x61\x66\x74\ +\x5f\x53\x65\x6c\x65\x63\x74\x47\x72\x6f\x75\x70\x01\x03\x00\x00\ +\x00\x64\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\ +\x00\x20\x00\x70\x01\x42\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\ +\x00\x79\x00\x7a\x00\x6e\x01\x19\x00\x20\x00\x72\x00\x6f\x00\x62\ +\x00\x6f\x00\x63\x00\x7a\x01\x05\x00\x20\x00\x64\x00\x6f\x00\x20\ +\x00\x74\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x65\x00\x6e\x00\x69\ +\x00\x61\x00\x20\x00\x67\x00\x65\x00\x6f\x00\x6d\x00\x65\x00\x74\ +\x00\x72\x00\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2c\ +\x53\x65\x6c\x65\x63\x74\x20\x61\x20\x77\x6f\x72\x6b\x69\x6e\x67\ +\x20\x70\x6c\x61\x6e\x65\x20\x66\x6f\x72\x20\x67\x65\x6f\x6d\x65\ +\x74\x72\x79\x20\x63\x72\x65\x61\x74\x69\x6f\x6e\x07\x00\x00\x00\ +\x11\x44\x72\x61\x66\x74\x5f\x53\x65\x6c\x65\x63\x74\x50\x6c\x61\ +\x6e\x65\x01\x03\x00\x00\x00\x26\x00\x57\x00\x79\x00\x62\x00\x69\ +\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x70\x01\x42\x00\x61\x00\x73\ +\x00\x7a\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\x6e\x01\x19\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0b\x53\x65\x6c\x65\x63\x74\x50\x6c\ +\x61\x6e\x65\x07\x00\x00\x00\x11\x44\x72\x61\x66\x74\x5f\x53\x65\ +\x6c\x65\x63\x74\x50\x6c\x61\x6e\x65\x01\x03\x00\x00\x00\x54\x00\ +\x43\x00\x72\x00\x65\x00\x61\x00\x74\x00\x65\x00\x73\x00\x20\x00\ +\x53\x00\x68\x00\x61\x00\x70\x00\x65\x00\x20\x00\x32\x00\x44\x00\ +\x20\x00\x76\x00\x69\x00\x65\x00\x77\x00\x73\x00\x20\x00\x6f\x00\ +\x66\x00\x20\x00\x73\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\ +\x65\x00\x64\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\ +\x74\x00\x73\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2a\x43\x72\x65\ +\x61\x74\x65\x73\x20\x53\x68\x61\x70\x65\x20\x32\x44\x20\x76\x69\ +\x65\x77\x73\x20\x6f\x66\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\ +\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\x00\x00\x11\x44\x72\x61\x66\ +\x74\x5f\x53\x68\x61\x70\x65\x32\x44\x56\x69\x65\x77\x01\x03\x00\ +\x00\x00\x1a\x00\x53\x00\x68\x00\x61\x00\x70\x00\x65\x00\x20\x00\ +\x32\x00\x44\x00\x20\x00\x76\x00\x69\x00\x65\x00\x77\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x0d\x53\x68\x61\x70\x65\x20\x32\x44\x20\ +\x76\x69\x65\x77\x07\x00\x00\x00\x11\x44\x72\x61\x66\x74\x5f\x53\ +\x68\x61\x70\x65\x32\x44\x56\x69\x65\x77\x01\x03\x00\x00\x00\x44\ +\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\x61\ +\x00\x64\x00\x6e\x00\x6f\x00\x74\x00\x61\x00\x63\x00\x6a\x00\x65\ +\x00\x2e\x00\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\x20\x00\x70\ +\x00\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x6e\ +\x00\x69\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x23\x43\x72\ +\x65\x61\x74\x65\x73\x20\x61\x6e\x20\x61\x6e\x6e\x6f\x74\x61\x74\ +\x69\x6f\x6e\x2e\x20\x43\x54\x52\x4c\x20\x74\x6f\x20\x73\x6e\x61\ +\x70\x07\x00\x00\x00\x0a\x44\x72\x61\x66\x74\x5f\x54\x65\x78\x74\ +\x01\x03\x00\x00\x00\x0a\x00\x54\x00\x65\x00\x6b\x00\x73\x00\x74\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04\x54\x65\x78\x74\x07\x00\ +\x00\x00\x0a\x44\x72\x61\x66\x74\x5f\x54\x65\x78\x74\x01\x03\x00\ +\x00\x00\x30\x00\x50\x00\x72\x00\x7a\x00\x65\x01\x42\x01\x05\x00\ +\x63\x00\x7a\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x74\x00\x72\x00\ +\x79\x00\x62\x00\x75\x00\x20\x00\x62\x00\x75\x00\x64\x00\x6f\x00\ +\x77\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17\x54\x6f\x67\ +\x67\x6c\x65\x20\x63\x6f\x6e\x73\x74\x72\x75\x63\x69\x6f\x6e\x20\ +\x4d\x6f\x64\x65\x07\x00\x00\x00\x1c\x44\x72\x61\x66\x74\x5f\x54\ +\x6f\x67\x67\x6c\x65\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\ +\x6e\x4d\x6f\x64\x65\x01\x03\x00\x00\x00\x5a\x00\x50\x00\x72\x00\ +\x7a\x00\x65\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x61\x00\x20\x00\ +\x74\x00\x72\x00\x79\x00\x62\x00\x20\x00\x62\x00\x75\x00\x64\x00\ +\x6f\x00\x77\x00\x79\x00\x20\x00\x64\x00\x6c\x00\x61\x00\x20\x00\ +\x6b\x00\x6f\x00\x6c\x00\x65\x00\x6a\x00\x6e\x00\x79\x00\x63\x00\ +\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\xf3\x00\x77\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2f\x54\ +\x6f\x67\x67\x6c\x65\x73\x20\x74\x68\x65\x20\x43\x6f\x6e\x73\x74\ +\x72\x75\x63\x74\x69\x6f\x6e\x20\x4d\x6f\x64\x65\x20\x66\x6f\x72\ +\x20\x6e\x65\x78\x74\x20\x6f\x62\x6a\x65\x63\x74\x73\x2e\x07\x00\ +\x00\x00\x1c\x44\x72\x61\x66\x74\x5f\x54\x6f\x67\x67\x6c\x65\x43\ +\x6f\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\x6e\x4d\x6f\x64\x65\x01\ +\x03\x00\x00\x00\x28\x00\x54\x00\x6f\x00\x67\x00\x67\x00\x6c\x00\ +\x65\x00\x20\x00\x63\x00\x6f\x00\x6e\x00\x74\x00\x69\x00\x6e\x00\ +\x75\x00\x65\x00\x20\x00\x4d\x00\x6f\x00\x64\x00\x65\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x14\x54\x6f\x67\x67\x6c\x65\x20\x63\x6f\ +\x6e\x74\x69\x6e\x75\x65\x20\x4d\x6f\x64\x65\x07\x00\x00\x00\x18\ +\x44\x72\x61\x66\x74\x5f\x54\x6f\x67\x67\x6c\x65\x43\x6f\x6e\x74\ +\x69\x6e\x75\x65\x4d\x6f\x64\x65\x01\x03\x00\x00\x00\x58\x00\x54\ +\x00\x6f\x00\x67\x00\x67\x00\x6c\x00\x65\x00\x73\x00\x20\x00\x74\ +\x00\x68\x00\x65\x00\x20\x00\x43\x00\x6f\x00\x6e\x00\x74\x00\x69\ +\x00\x6e\x00\x75\x00\x65\x00\x20\x00\x4d\x00\x6f\x00\x64\x00\x65\ +\x00\x20\x00\x66\x00\x6f\x00\x72\x00\x20\x00\x6e\x00\x65\x00\x78\ +\x00\x74\x00\x20\x00\x63\x00\x6f\x00\x6d\x00\x6d\x00\x61\x00\x6e\ +\x00\x64\x00\x73\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2c\ +\x54\x6f\x67\x67\x6c\x65\x73\x20\x74\x68\x65\x20\x43\x6f\x6e\x74\ +\x69\x6e\x75\x65\x20\x4d\x6f\x64\x65\x20\x66\x6f\x72\x20\x6e\x65\ +\x78\x74\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x73\x2e\x07\x00\x00\x00\ +\x18\x44\x72\x61\x66\x74\x5f\x54\x6f\x67\x67\x6c\x65\x43\x6f\x6e\ +\x74\x69\x6e\x75\x65\x4d\x6f\x64\x65\x01\x03\x00\x00\x00\xa6\x00\ +\x5a\x00\x61\x00\x6d\x00\x69\x00\x61\x00\x6e\x00\x61\x00\x20\x00\ +\x74\x00\x72\x00\x79\x00\x62\x00\x75\x00\x20\x00\x77\x00\x79\x01\ +\x5b\x00\x77\x00\x69\x00\x65\x00\x74\x00\x6c\x00\x61\x00\x6e\x00\ +\x69\x00\x61\x00\x20\x00\x77\x00\x79\x00\x62\x00\x72\x00\x61\x00\ +\x6e\x00\x79\x00\x63\x00\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\ +\x65\x00\x6b\x00\x74\x00\xf3\x00\x77\x00\x20\x00\x70\x00\x6f\x00\ +\x6d\x00\x69\x01\x19\x00\x64\x00\x7a\x00\x79\x00\x20\x00\x6d\x00\ +\x6f\x00\x64\x00\x65\x00\x6c\x00\x65\x00\x6d\x00\x20\x00\x73\x00\ +\x69\x00\x61\x00\x74\x00\x6b\x00\x6f\x00\x77\x00\x79\x00\x6d\x00\ +\x20\x00\x69\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x6f\x00\ +\x77\x00\x79\x00\x6d\x08\x00\x00\x00\x00\x06\x00\x00\x00\x46\x53\ +\x77\x61\x70\x73\x20\x64\x69\x73\x70\x6c\x61\x79\x20\x6d\x6f\x64\ +\x65\x20\x6f\x66\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x6f\x62\ +\x6a\x65\x63\x74\x73\x20\x62\x65\x74\x77\x65\x65\x6e\x20\x77\x69\ +\x72\x65\x66\x72\x61\x6d\x65\x20\x61\x6e\x64\x20\x66\x6c\x61\x74\ +\x6c\x69\x6e\x65\x73\x07\x00\x00\x00\x17\x44\x72\x61\x66\x74\x5f\ +\x54\x6f\x67\x67\x6c\x65\x44\x69\x73\x70\x6c\x61\x79\x4d\x6f\x64\ +\x65\x01\x03\x00\x00\x00\x34\x00\x50\x00\x72\x00\x7a\x00\x65\x01\ +\x42\x01\x05\x00\x63\x00\x7a\x00\x20\x00\x74\x00\x72\x00\x79\x00\ +\x62\x00\x20\x00\x77\x00\x79\x01\x5b\x00\x77\x00\x69\x00\x65\x00\ +\x74\x00\x6c\x00\x61\x00\x6e\x00\x69\x00\x61\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x13\x54\x6f\x67\x67\x6c\x65\x20\x64\x69\x73\x70\ +\x6c\x61\x79\x20\x6d\x6f\x64\x65\x07\x00\x00\x00\x17\x44\x72\x61\ +\x66\x74\x5f\x54\x6f\x67\x67\x6c\x65\x44\x69\x73\x70\x6c\x61\x79\ +\x4d\x6f\x64\x65\x01\x03\x00\x00\x00\x26\x00\x50\x00\x72\x00\x7a\ +\x00\x79\x00\x74\x00\x6e\x00\x69\x00\x6a\x00\x2f\x00\x52\x00\x6f\ +\x00\x7a\x00\x63\x00\x69\x01\x05\x00\x67\x00\x6e\x00\x69\x00\x6a\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06\x54\x72\x69\x6d\x65\x78\ +\x07\x00\x00\x00\x0c\x44\x72\x61\x66\x74\x5f\x54\x72\x69\x6d\x65\ +\x78\x01\x03\x00\x00\x01\x12\x00\x54\x00\x72\x00\x69\x00\x6d\x00\ +\x73\x00\x20\x00\x6f\x00\x72\x00\x20\x00\x65\x00\x78\x00\x74\x00\ +\x65\x00\x6e\x00\x64\x00\x73\x00\x20\x00\x74\x00\x68\x00\x65\x00\ +\x20\x00\x73\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\x65\x00\ +\x64\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\ +\x2c\x00\x20\x00\x6f\x00\x72\x00\x20\x00\x65\x00\x78\x00\x74\x00\ +\x72\x00\x75\x00\x64\x00\x65\x00\x73\x00\x20\x00\x73\x00\x69\x00\ +\x6e\x00\x67\x00\x6c\x00\x65\x00\x20\x00\x66\x00\x61\x00\x63\x00\ +\x65\x00\x73\x00\x2e\x00\x20\x00\x43\x00\x54\x00\x52\x00\x4c\x00\ +\x20\x00\x73\x00\x6e\x00\x61\x00\x70\x00\x73\x00\x2c\x00\x20\x00\ +\x53\x00\x48\x00\x49\x00\x46\x00\x54\x00\x20\x00\x63\x00\x6f\x00\ +\x6e\x00\x73\x00\x74\x00\x72\x00\x61\x00\x69\x00\x6e\x00\x73\x00\ +\x20\x00\x74\x00\x6f\x00\x20\x00\x63\x00\x75\x00\x72\x00\x72\x00\ +\x65\x00\x6e\x00\x74\x00\x20\x00\x73\x00\x65\x00\x67\x00\x6d\x00\ +\x65\x00\x6e\x00\x74\x00\x20\x00\x6f\x00\x72\x00\x20\x00\x74\x00\ +\x6f\x00\x20\x00\x6e\x00\x6f\x00\x72\x00\x6d\x00\x61\x00\x6c\x00\ +\x2c\x00\x20\x00\x41\x00\x4c\x00\x54\x00\x20\x00\x69\x00\x6e\x00\ +\x76\x00\x65\x00\x72\x00\x74\x00\x73\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x89\x54\x72\x69\x6d\x73\x20\x6f\x72\x20\x65\x78\x74\x65\ +\x6e\x64\x73\x20\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\x65\x64\ +\x20\x6f\x62\x6a\x65\x63\x74\x2c\x20\x6f\x72\x20\x65\x78\x74\x72\ +\x75\x64\x65\x73\x20\x73\x69\x6e\x67\x6c\x65\x20\x66\x61\x63\x65\ +\x73\x2e\x20\x43\x54\x52\x4c\x20\x73\x6e\x61\x70\x73\x2c\x20\x53\ +\x48\x49\x46\x54\x20\x63\x6f\x6e\x73\x74\x72\x61\x69\x6e\x73\x20\ +\x74\x6f\x20\x63\x75\x72\x72\x65\x6e\x74\x20\x73\x65\x67\x6d\x65\ +\x6e\x74\x20\x6f\x72\x20\x74\x6f\x20\x6e\x6f\x72\x6d\x61\x6c\x2c\ +\x20\x41\x4c\x54\x20\x69\x6e\x76\x65\x72\x74\x73\x07\x00\x00\x00\ +\x0c\x44\x72\x61\x66\x74\x5f\x54\x72\x69\x6d\x65\x78\x01\x03\x00\ +\x00\x00\x2c\x00\x43\x00\x6f\x00\x66\x00\x6e\x00\x69\x00\x6a\x00\ +\x20\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x74\x00\x6e\x00\x69\x00\ +\x20\x00\x73\x00\x65\x00\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x11\x55\x6e\x64\x6f\x20\x6c\x61\ +\x73\x74\x20\x73\x65\x67\x6d\x65\x6e\x74\x07\x00\x00\x00\x0e\x44\ +\x72\x61\x66\x74\x5f\x55\x6e\x64\x6f\x4c\x69\x6e\x65\x01\x03\x00\ +\x00\x00\x48\x00\x43\x00\x6f\x00\x66\x00\x61\x00\x20\x00\x6f\x00\ +\x73\x00\x74\x00\x61\x00\x74\x00\x6e\x00\x69\x00\x20\x00\x73\x00\ +\x65\x00\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x20\x00\x72\x00\ +\x79\x00\x73\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x65\x00\x6a\x00\ +\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x35\x55\x6e\x64\x6f\x65\x73\x20\x74\x68\x65\x20\ +\x6c\x61\x73\x74\x20\x64\x72\x61\x77\x6e\x20\x73\x65\x67\x6d\x65\ +\x6e\x74\x20\x6f\x66\x20\x74\x68\x65\x20\x6c\x69\x6e\x65\x20\x62\ +\x65\x69\x6e\x67\x20\x64\x72\x61\x77\x6e\x07\x00\x00\x00\x0e\x44\ +\x72\x61\x66\x74\x5f\x55\x6e\x64\x6f\x4c\x69\x6e\x65\x01\x03\x00\ +\x00\x00\xe2\x01\x41\x01\x05\x00\x63\x00\x7a\x00\x79\x00\x20\x00\ +\x77\x00\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\x65\x00\x20\x00\ +\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x20\x00\ +\x77\x00\x20\x00\x6a\x00\x65\x00\x64\x00\x65\x00\x6e\x00\x2c\x00\ +\x20\x00\x6c\x00\x75\x00\x62\x00\x20\x00\x7a\x00\x61\x00\x6d\x00\ +\x69\x00\x65\x00\x6e\x00\x69\x00\x61\x00\x20\x00\x7a\x00\x61\x00\ +\x6d\x00\x6b\x00\x6e\x00\x69\x01\x19\x00\x74\x00\x65\x00\x20\x00\ +\x70\x00\x6f\x00\x6c\x00\x69\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\ +\x65\x00\x20\x00\x77\x00\x20\x00\x70\x00\x65\x01\x42\x00\x6e\x00\ +\x65\x00\x20\x00\x70\x00\x6f\x00\x77\x00\x69\x00\x65\x00\x72\x00\ +\x7a\x00\x63\x00\x68\x00\x6e\x00\x69\x00\x65\x00\x2c\x00\x20\x00\ +\x6c\x00\x75\x00\x62\x00\x20\x00\x70\x00\x6f\x01\x42\x01\x05\x00\ +\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\x00\x20\x00\x70\x00\x6f\x00\ +\x77\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x63\x00\x68\x00\x6e\x00\ +\x69\x00\x65\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x5d\x4a\ +\x6f\x69\x6e\x73\x20\x74\x68\x65\x20\x73\x65\x6c\x65\x63\x74\x65\ +\x64\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x69\x6e\x74\x6f\x20\x6f\ +\x6e\x65\x2c\x20\x6f\x72\x20\x63\x6f\x6e\x76\x65\x72\x74\x73\x20\ +\x63\x6c\x6f\x73\x65\x64\x20\x77\x69\x72\x65\x73\x20\x74\x6f\x20\ +\x66\x69\x6c\x6c\x65\x64\x20\x66\x61\x63\x65\x73\x2c\x20\x6f\x72\ +\x20\x75\x6e\x69\x74\x65\x20\x66\x61\x63\x65\x73\x07\x00\x00\x00\ +\x0d\x44\x72\x61\x66\x74\x5f\x55\x70\x67\x72\x61\x64\x65\x01\x03\ +\x00\x00\x00\x14\x00\x41\x00\x6b\x00\x74\x00\x75\x00\x61\x00\x6c\ +\x00\x69\x00\x7a\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x07\x55\x70\x67\x72\x61\x64\x65\x07\x00\x00\x00\x0d\x44\x72\ +\x61\x66\x74\x5f\x55\x70\x67\x72\x61\x64\x65\x01\x03\x00\x00\x00\ +\x74\x00\x54\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x79\x00\x20\x00\ +\x6c\x00\x69\x00\x6e\x00\x69\x01\x19\x00\x20\x00\x77\x00\x69\x00\ +\x65\x00\x6c\x00\x6f\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\ +\x6f\x00\x77\x01\x05\x00\x2e\x00\x43\x00\x54\x00\x52\x00\x4c\x00\ +\x20\x00\x70\x00\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\ +\x67\x00\x61\x00\x6a\x00\x2c\x00\x20\x00\x53\x00\x48\x00\x49\x00\ +\x46\x00\x54\x00\x20\x00\x6f\x00\x67\x00\x72\x00\x61\x00\x6e\x00\ +\x69\x00\x63\x00\x7a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x3f\x43\ +\x72\x65\x61\x74\x65\x73\x20\x61\x20\x6d\x75\x6c\x74\x69\x70\x6c\ +\x65\x2d\x70\x6f\x69\x6e\x74\x20\x77\x69\x72\x65\x2e\x20\x43\x54\ +\x52\x4c\x20\x74\x6f\x20\x73\x6e\x61\x70\x2c\x20\x53\x48\x49\x46\ +\x54\x20\x74\x6f\x20\x63\x6f\x6e\x73\x74\x72\x61\x69\x6e\x07\x00\ +\x00\x00\x0a\x44\x72\x61\x66\x74\x5f\x57\x69\x72\x65\x01\x03\x00\ +\x00\x00\x26\x00\x4c\x00\x69\x00\x6e\x00\x69\x00\x61\x00\x20\x00\ +\x77\x00\x69\x00\x65\x00\x6c\x00\x6f\x00\x70\x00\x75\x00\x6e\x00\ +\x6b\x00\x74\x00\x6f\x00\x77\x00\x61\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x04\x57\x69\x72\x65\x07\x00\x00\x00\x0a\x44\x72\x61\x66\ +\x74\x5f\x57\x69\x72\x65\x01\x03\x00\x00\x00\x38\x00\x4b\x00\x6f\ +\x00\x6e\x00\x77\x00\x65\x00\x72\x00\x73\x00\x6a\x00\x61\x00\x20\ +\x00\x4c\x00\x69\x00\x6e\x00\x69\x00\x61\x00\x20\x00\x3c\x00\x2d\ +\x00\x3e\x00\x20\x00\x42\x00\x2d\x00\x53\x00\x70\x00\x6c\x00\x61\ +\x00\x6a\x00\x6e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x21\x43\x6f\ +\x6e\x76\x65\x72\x74\x73\x20\x62\x65\x74\x77\x65\x65\x6e\x20\x57\ +\x69\x72\x65\x20\x61\x6e\x64\x20\x42\x53\x70\x6c\x69\x6e\x65\x07\ +\x00\x00\x00\x13\x44\x72\x61\x66\x74\x5f\x57\x69\x72\x65\x54\x6f\ +\x42\x53\x70\x6c\x69\x6e\x65\x01\x03\x00\x00\x00\x22\x00\x4c\x00\ +\x69\x00\x6e\x00\x69\x00\x61\x00\x20\x00\x64\x00\x6f\x00\x20\x00\ +\x42\x00\x2d\x00\x53\x00\x70\x00\x6c\x00\x61\x00\x6a\x00\x6e\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x0f\x57\x69\x72\x65\x20\x74\x6f\ +\x20\x42\x53\x70\x6c\x69\x6e\x65\x07\x00\x00\x00\x13\x44\x72\x61\ +\x66\x74\x5f\x57\x69\x72\x65\x54\x6f\x42\x53\x70\x6c\x69\x6e\x65\ +\x01\x03\x00\x00\x00\x0e\x00\x41\x00\x6c\x00\x74\x00\x20\x00\x6d\ +\x00\x6f\x00\x64\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07\x41\x6c\ +\x74\x20\x6d\x6f\x64\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\x41\x00\ +\x6c\x00\x74\x00\x65\x00\x72\x00\x6e\x00\x61\x00\x74\x00\x65\x00\ +\x20\x00\x53\x00\x56\x00\x47\x00\x20\x00\x50\x00\x61\x00\x74\x00\ +\x74\x00\x65\x00\x72\x00\x6e\x00\x73\x00\x20\x00\x6c\x00\x6f\x00\ +\x63\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x1f\x41\x6c\x74\x65\x72\x6e\x61\x74\x65\x20\x53\ +\x56\x47\x20\x50\x61\x74\x74\x65\x72\x6e\x73\x20\x6c\x6f\x63\x61\ +\x74\x69\x6f\x6e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x5a\x00\x41\x00\x6c\ +\x00\x77\x00\x61\x00\x79\x00\x73\x00\x20\x00\x73\x00\x6e\x00\x61\ +\x00\x70\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x6a\ +\x00\x65\x00\x63\x00\x74\x00\x73\x00\x20\x00\x28\x00\x64\x00\x69\ +\x00\x73\x00\x61\x00\x62\x00\x6c\x00\x65\x00\x20\x00\x73\x00\x6e\ +\x00\x61\x00\x70\x00\x20\x00\x6d\x00\x6f\x00\x64\x00\x20\x00\x6b\ +\x00\x65\x00\x79\x00\x29\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2d\ +\x41\x6c\x77\x61\x79\x73\x20\x73\x6e\x61\x70\x20\x74\x6f\x20\x6f\ +\x62\x6a\x65\x63\x74\x73\x20\x28\x64\x69\x73\x61\x62\x6c\x65\x20\ +\x73\x6e\x61\x70\x20\x6d\x6f\x64\x20\x6b\x65\x79\x29\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x0a\x00\x41\x00\x72\x00\x69\x00\x61\x00\x6c\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x05\x41\x72\x69\x61\x6c\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x16\x00\x42\x00\x61\x00\x63\x00\x6b\x00\x73\ +\x00\x6c\x00\x61\x00\x73\x00\x68\x00\x20\x00\x35\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x0b\x42\x61\x63\x6b\x73\x6c\x61\x73\x68\x20\ +\x35\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x16\x00\x42\x00\x61\x00\x63\x00\ +\x6b\x00\x73\x00\x6c\x00\x61\x00\x73\x00\x68\x00\x20\x00\x37\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x0b\x42\x61\x63\x6b\x73\x6c\x61\ +\x73\x68\x20\x37\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x16\x00\x42\x00\x61\ +\x00\x63\x00\x6b\x00\x73\x00\x6c\x00\x61\x00\x73\x00\x68\x00\x20\ +\x00\x39\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0b\x42\x61\x63\x6b\ +\x73\x6c\x61\x73\x68\x20\x39\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x72\x00\ +\x5a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\x20\x00\ +\x6a\x00\x65\x01\x5b\x00\x6c\x00\x69\x00\x20\x00\x63\x00\x68\x00\ +\x63\x00\x65\x00\x73\x00\x7a\x00\x20\x00\x7a\x00\x61\x00\x69\x00\ +\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x6f\x00\x77\x00\x61\x01\ +\x07\x00\x20\x00\x70\x00\x6f\x00\x77\x00\x69\x00\x65\x00\x72\x00\ +\x7a\x00\x63\x00\x68\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x28\x00\ +\x33\x00\x44\x00\x20\x00\x66\x00\x61\x00\x63\x00\x65\x00\x29\x00\ +\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x3f\x43\x68\x65\x63\x6b\ +\x20\x74\x68\x69\x73\x20\x69\x66\x20\x79\x6f\x75\x20\x77\x61\x6e\ +\x74\x20\x74\x68\x65\x20\x61\x72\x65\x61\x73\x20\x28\x33\x44\x20\ +\x66\x61\x63\x65\x73\x29\x20\x74\x6f\x20\x62\x65\x20\x69\x6d\x70\ +\x6f\x72\x74\x65\x64\x20\x74\x6f\x6f\x2e\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\xa6\x00\x43\x00\x68\x00\x65\x00\x63\x00\x6b\x00\x20\x00\x74\ +\x00\x68\x00\x69\x00\x73\x00\x20\x00\x69\x00\x66\x00\x20\x00\x79\ +\x00\x6f\x00\x75\x00\x20\x00\x77\x00\x61\x00\x6e\x00\x74\x00\x20\ +\x00\x74\x00\x68\x00\x65\x00\x20\x00\x6e\x00\x6f\x00\x6e\x00\x2d\ +\x00\x6e\x00\x61\x00\x6d\x00\x65\x00\x64\x00\x20\x00\x62\x00\x6c\ +\x00\x6f\x00\x63\x00\x6b\x00\x73\x00\x20\x00\x28\x00\x62\x00\x65\ +\x00\x67\x00\x69\x00\x6e\x00\x6e\x00\x69\x00\x6e\x00\x67\x00\x20\ +\x00\x77\x00\x69\x00\x74\x00\x68\x00\x20\x00\x61\x00\x20\x00\x2a\ +\x00\x29\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x62\x00\x65\x00\x20\ +\x00\x69\x00\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x65\x00\x64\ +\x00\x20\x00\x74\x00\x6f\x00\x6f\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x53\x43\x68\x65\x63\x6b\x20\x74\x68\x69\x73\x20\x69\x66\x20\ +\x79\x6f\x75\x20\x77\x61\x6e\x74\x20\x74\x68\x65\x20\x6e\x6f\x6e\ +\x2d\x6e\x61\x6d\x65\x64\x20\x62\x6c\x6f\x63\x6b\x73\x20\x28\x62\ +\x65\x67\x69\x6e\x6e\x69\x6e\x67\x20\x77\x69\x74\x68\x20\x61\x20\ +\x2a\x29\x20\x74\x6f\x20\x62\x65\x20\x69\x6d\x70\x6f\x72\x74\x65\ +\x64\x20\x74\x6f\x6f\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0e\x00\x4f\x00\ +\x6b\x00\x72\x01\x05\x00\x67\x00\x20\x00\x35\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x08\x43\x69\x72\x63\x6c\x65\x20\x35\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x10\x00\x43\x00\x69\x00\x72\x00\x63\x00\x6c\x00\ +\x65\x00\x20\x00\x37\x08\x00\x00\x00\x00\x06\x00\x00\x00\x08\x43\ +\x69\x72\x63\x6c\x65\x20\x37\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x10\x00\ +\x43\x00\x69\x00\x72\x00\x63\x00\x6c\x00\x65\x00\x20\x00\x39\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x08\x43\x69\x72\x63\x6c\x65\x20\ +\x39\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x44\x00\x4d\x00\x61\x00\x70\x00\ +\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x6b\x00\ +\x6f\x00\x6c\x00\x6f\x00\x72\x00\x75\x00\x20\x00\x64\x00\x6f\x00\ +\x20\x00\x67\x00\x72\x00\x75\x00\x62\x00\x6f\x01\x5b\x00\x63\x00\ +\x69\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x19\x43\x6f\x6c\x6f\x72\x20\x6d\x61\x70\ +\x70\x65\x64\x20\x74\x6f\x20\x6c\x69\x6e\x65\x77\x69\x64\x74\x68\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x4e\x00\x50\x00\x6c\x00\x69\x00\x6b\ +\x00\x20\x00\x6d\x00\x61\x00\x70\x00\x6f\x00\x77\x00\x61\x00\x6e\ +\x00\x69\x00\x61\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\ +\x00\x75\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x67\x00\x72\x00\x75\ +\x00\x62\x00\x6f\x01\x5b\x00\x63\x00\x69\x00\x20\x00\x6c\x00\x69\ +\x00\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x12\ +\x43\x6f\x6c\x6f\x72\x20\x6d\x61\x70\x70\x69\x6e\x67\x20\x66\x69\ +\x6c\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1a\x00\x43\x00\x6f\x00\x6e\ +\x00\x73\x00\x74\x00\x72\x00\x61\x00\x69\x00\x6e\x00\x20\x00\x6d\ +\x00\x6f\x00\x64\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\x43\x6f\ +\x6e\x73\x74\x72\x61\x69\x6e\x20\x6d\x6f\x64\x07\x00\x00\x00\x1d\ +\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\ +\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x16\x00\x4b\x00\x6f\x00\x6e\x00\x73\x00\x74\x00\x72\x00\ +\x75\x00\x6b\x00\x63\x00\x6a\x00\x61\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x0c\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\x6e\x07\ +\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\ +\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x22\x00\x4b\x00\x6f\x00\x6c\x00\x6f\x00\ +\x72\x00\x20\x00\x4b\x00\x6f\x00\x6e\x00\x73\x00\x74\x00\x72\x00\ +\x75\x00\x6b\x00\x63\x00\x6a\x00\x69\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x12\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\x6e\x20\ +\x63\x6f\x6c\x6f\x72\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2e\x00\x4e\x00\ +\x61\x00\x7a\x00\x77\x00\x61\x00\x20\x00\x67\x00\x72\x00\x75\x00\ +\x70\x00\x79\x00\x20\x00\x4b\x00\x6f\x00\x6e\x00\x73\x00\x74\x00\ +\x72\x00\x75\x00\x6b\x00\x63\x00\x6a\x00\x61\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x17\x43\x6f\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\ +\x6e\x20\x67\x72\x6f\x75\x70\x20\x6e\x61\x6d\x65\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x36\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\ +\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\ +\x00\x70\x00\x61\x00\x72\x00\x61\x00\x6d\x00\x65\x00\x74\x00\x72\ +\x00\x79\x00\x63\x00\x7a\x00\x6e\x00\x79\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x19\x43\x72\x65\x61\x74\x65\x20\x70\x61\x72\x61\x6d\ +\x65\x74\x72\x69\x63\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x22\x00\x4f\x00\x70\x00\x63\x00\x6a\x00\x65\x00\ +\x20\x00\x66\x00\x6f\x00\x72\x00\x6d\x00\x61\x00\x74\x00\x75\x00\ +\x20\x00\x44\x00\x58\x00\x46\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x12\x44\x58\x46\x20\x66\x6f\x72\x6d\x61\x74\x20\x6f\x70\x74\x69\ +\x6f\x6e\x73\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1c\x00\x4b\x00\x6f\x00\ +\x6c\x00\x6f\x00\x72\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\ +\x5b\x00\x6c\x00\x6e\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x0d\x44\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6c\x6f\x72\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x48\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\x5b\ +\x00\x6c\x00\x6e\x00\x61\x00\x20\x00\x77\x00\x79\x00\x73\x00\x6f\ +\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x74\x00\x65\x00\x6b\ +\x00\x73\x00\x74\x00\xf3\x00\x77\x00\x20\x00\x69\x00\x20\x00\x77\ +\x00\x79\x00\x6d\x00\x69\x00\x61\x00\x72\x00\xf3\x00\x77\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x27\x44\x65\x66\x61\x75\x6c\x74\x20\ +\x68\x65\x69\x67\x68\x74\x20\x66\x6f\x72\x20\x74\x65\x78\x74\x73\ +\x20\x61\x6e\x64\x20\x64\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x73\x07\ +\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\ +\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x30\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\ +\x5b\x00\x6c\x00\x6e\x00\x61\x00\x20\x00\x73\x00\x7a\x00\x65\x00\ +\x72\x00\x6f\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x6c\x00\ +\x69\x00\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x11\x44\x65\x66\x61\x75\x6c\x74\x20\x6c\x69\x6e\x65\x77\x69\x64\ +\x74\x68\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x30\x00\x44\x00\x6f\x00\x6d\ +\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\x73\x00\x7a\ +\x00\x61\x00\x62\x00\x6c\x00\x6f\x00\x6e\x00\x20\x00\x61\x00\x72\ +\x00\x6b\x00\x75\x00\x73\x00\x7a\x00\x61\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x16\x44\x65\x66\x61\x75\x6c\x74\x20\x74\x65\x6d\x70\ +\x6c\x61\x74\x65\x20\x73\x68\x65\x65\x74\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x30\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\ +\x00\x61\x00\x20\x00\x63\x00\x7a\x00\x63\x00\x69\x00\x6f\x00\x6e\ +\x00\x6b\x00\x61\x00\x20\x00\x74\x00\x65\x00\x6b\x00\x73\x00\x74\ +\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x11\x44\x65\x66\x61\ +\x75\x6c\x74\x20\x74\x65\x78\x74\x20\x66\x6f\x6e\x74\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x30\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\ +\x6c\x00\x6e\x00\x61\x00\x20\x00\x77\x00\x79\x00\x73\x00\x6f\x00\ +\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x74\x00\x65\x00\x6b\x00\ +\x73\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x13\x44\ +\x65\x66\x61\x75\x6c\x74\x20\x74\x65\x78\x74\x20\x68\x65\x69\x67\ +\x68\x74\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x38\x00\x44\x00\x6f\x00\x6d\ +\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x61\x00\x20\x00\x70\x01\x42\ +\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\x6e\ +\x00\x61\x00\x20\x00\x72\x00\x6f\x00\x62\x00\x6f\x00\x63\x00\x7a\ +\x00\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x15\x44\x65\x66\x61\ +\x75\x6c\x74\x20\x77\x6f\x72\x6b\x69\x6e\x67\x20\x70\x6c\x61\x6e\ +\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x22\x00\x53\x00\x74\x00\x79\x00\ +\x6c\x00\x20\x00\x77\x00\x79\x00\x6d\x00\x69\x00\x61\x00\x72\x00\ +\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x61\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x1f\x44\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x73\x20\ +\x26\x20\x4c\x65\x61\x64\x65\x72\x20\x61\x72\x72\x6f\x77\x20\x73\ +\x74\x79\x6c\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2e\x00\x44\x00\x6f\ +\x00\x6b\x01\x42\x00\x61\x00\x64\x00\x6e\x00\x6f\x01\x5b\x01\x07\ +\x00\x20\x00\x77\x00\x79\x00\x6d\x00\x69\x00\x61\x00\x72\x00\x6f\ +\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x61\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x1a\x44\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x73\x20\x70\ +\x72\x65\x63\x69\x73\x69\x6f\x6e\x20\x6c\x65\x76\x65\x6c\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x0a\x00\x44\x00\x6f\x00\x74\x00\x20\x00\x35\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\x44\x6f\x74\x20\x35\x07\ +\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\ +\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x0a\x00\x44\x00\x6f\x00\x74\x00\x20\x00\ +\x37\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\x44\x6f\x74\x20\x37\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x0a\x00\x44\x00\x6f\x00\x74\x00\x20\ +\x00\x39\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\x44\x6f\x74\x20\ +\x39\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x14\x00\x54\x00\x72\x00\x79\x00\ +\x62\x00\x20\x00\x44\x00\x72\x00\x61\x00\x66\x00\x74\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x14\x44\x72\x61\x66\x74\x20\x69\x6e\x74\ +\x65\x72\x66\x61\x63\x65\x20\x6d\x6f\x64\x65\x07\x00\x00\x00\x1d\ +\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\ +\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x58\x00\x45\x00\x6b\x00\x73\x00\x70\x00\x6f\x00\x72\x00\ +\x74\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\x75\x00\x20\x00\x33\x00\x44\x00\x20\x00\x6a\x00\x61\x00\x6b\x00\ +\x6f\x00\x20\x00\x77\x00\x69\x00\x65\x00\x6c\x00\x6f\x00\x66\x00\ +\x61\x00\x73\x00\x65\x00\x74\x00\x6f\x00\x77\x00\x61\x00\x20\x00\ +\x73\x00\x69\x00\x61\x00\x74\x00\x6b\x00\x61\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x24\x45\x78\x70\x6f\x72\x74\x20\x33\x44\x20\x6f\ +\x62\x6a\x65\x63\x74\x73\x20\x61\x73\x20\x70\x6f\x6c\x79\x66\x61\ +\x63\x65\x20\x6d\x65\x73\x68\x65\x73\x07\x00\x00\x00\x1d\x47\x75\ +\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\ +\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x34\x00\x57\x00\x79\x00\x70\x00\x65\x01\x42\x00\x6e\x00\x69\x00\ +\x6a\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\x79\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\ +\x6e\x00\x69\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17\x46\ +\x69\x6c\x6c\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x62\x79\x20\x64\ +\x65\x66\x61\x75\x6c\x74\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\ +\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\ +\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x36\x00\x4f\ +\x00\x67\x00\xf3\x00\x6c\x00\x6e\x00\x65\x00\x20\x00\x75\x00\x73\ +\x00\x74\x00\x61\x00\x77\x00\x69\x00\x65\x00\x6e\x00\x69\x00\x61\ +\x00\x20\x00\x72\x00\x79\x00\x73\x00\x75\x00\x6e\x00\x6b\x00\x6f\ +\x00\x77\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x16\x47\x65\ +\x6e\x65\x72\x61\x6c\x20\x44\x72\x61\x66\x74\x20\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x22\x00\x55\x00\x73\ +\x00\x74\x00\x61\x00\x77\x00\x69\x00\x65\x00\x6e\x00\x69\x00\x61\ +\x00\x20\x00\x6f\x00\x67\x00\xf3\x00\x6c\x00\x6e\x00\x65\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x10\x47\x65\x6e\x65\x72\x61\x6c\x20\ +\x73\x65\x74\x74\x69\x6e\x67\x73\x07\x00\x00\x00\x1d\x47\x75\x69\ +\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\ +\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x30\ +\x00\x54\x00\x72\x00\x79\x00\x62\x00\x20\x00\x67\x00\x6c\x00\x6f\ +\x00\x62\x00\x61\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\x6b\x00\x6f\ +\x00\x70\x00\x69\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x61\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\x47\x6c\x6f\x62\x61\x6c\ +\x20\x63\x6f\x70\x79\x20\x6d\x6f\x64\x65\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x18\x00\x47\x00\x72\x00\x69\x00\x64\x00\x20\x00\x73\x00\x70\ +\x00\x61\x00\x63\x00\x69\x00\x6e\x00\x67\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x0c\x47\x72\x69\x64\x20\x73\x70\x61\x63\x69\x6e\x67\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x2e\x00\x5a\x00\x67\x00\x72\x00\x75\ +\x00\x70\x00\x75\x00\x6a\x00\x20\x00\x77\x00\x61\x00\x72\x00\x73\ +\x00\x74\x00\x77\x00\x79\x00\x20\x00\x77\x00\x20\x00\x42\x00\x6c\ +\x00\x6f\x00\x6b\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x18\ +\x47\x72\x6f\x75\x70\x20\x6c\x61\x79\x65\x72\x73\x20\x69\x6e\x74\ +\x6f\x20\x62\x6c\x6f\x63\x6b\x73\x07\x00\x00\x00\x1d\x47\x75\x69\ +\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\ +\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\xf6\ +\x00\x50\x00\x6f\x00\x64\x00\x61\x00\x6a\x00\x20\x00\x66\x00\x6f\ +\x00\x6c\x00\x64\x00\x65\x00\x72\x00\x20\x00\x7a\x00\x61\x00\x77\ +\x00\x69\x00\x65\x00\x72\x00\x61\x00\x6a\x01\x05\x00\x63\x00\x79\ +\x00\x20\x00\x70\x00\x6c\x00\x69\x00\x6b\x00\x69\x00\x20\x00\x53\ +\x00\x56\x00\x47\x00\x20\x00\x64\x00\x65\x00\x66\x00\x69\x00\x6e\ +\x00\x69\x00\x63\x00\x6a\x00\x69\x00\x20\x00\x77\x00\x7a\x00\x6f\ +\x00\x72\x00\xf3\x00\x77\x00\x20\x00\x77\x00\x79\x00\x70\x00\x65\ +\x01\x42\x00\x6e\x00\x69\x00\x65\x00\x6e\x00\x69\x00\x61\x00\x20\ +\x00\x2c\x00\x6b\x00\x74\x00\xf3\x00\x72\x00\x65\x00\x20\x00\x6d\ +\x00\x6f\x01\x7c\x00\x6e\x00\x61\x00\x20\x00\x64\x00\x6f\x00\x64\ +\x00\x61\x01\x07\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x73\x00\x74\ +\x00\x61\x00\x6e\x00\x64\x00\x61\x00\x72\x00\x64\x00\x6f\x00\x77\ +\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x6d\x00\x6f\x00\x64\x00\x75\ +\x01\x42\x00\x75\x00\x20\x00\x77\x00\x79\x00\x70\x00\x65\x01\x42\ +\x00\x6e\x00\x69\x00\x65\x01\x44\x00\x20\x00\x44\x00\x72\x00\x61\ +\x00\x66\x00\x74\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x8d\ +\x48\x65\x72\x65\x20\x79\x6f\x75\x20\x63\x61\x6e\x20\x73\x70\x65\ +\x63\x69\x66\x79\x20\x61\x20\x64\x69\x72\x65\x63\x74\x6f\x72\x79\ +\x20\x63\x6f\x6e\x74\x61\x69\x6e\x69\x6e\x67\x20\x53\x56\x47\x20\ +\x66\x69\x6c\x65\x73\x20\x63\x6f\x6e\x74\x61\x69\x6e\x69\x6e\x67\ +\x20\x3c\x70\x61\x74\x74\x65\x72\x6e\x3e\x20\x64\x65\x66\x69\x6e\ +\x69\x74\x69\x6f\x6e\x73\x20\x74\x68\x61\x74\x20\x63\x61\x6e\x20\ +\x62\x65\x20\x61\x64\x64\x65\x64\x20\x74\x6f\x20\x74\x68\x65\x20\ +\x73\x74\x61\x6e\x64\x61\x72\x64\x20\x44\x72\x61\x66\x74\x20\x68\ +\x61\x74\x63\x68\x20\x70\x61\x74\x74\x65\x72\x6e\x73\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x56\x00\x49\x00\x66\x00\x20\x00\x63\x00\x68\x00\ +\x65\x00\x63\x00\x6b\x00\x65\x00\x64\x00\x2c\x00\x20\x00\x61\x00\ +\x20\x00\x67\x00\x72\x00\x69\x00\x64\x00\x20\x00\x77\x00\x69\x00\ +\x6c\x00\x6c\x00\x20\x00\x61\x00\x70\x00\x70\x00\x65\x00\x61\x00\ +\x72\x00\x20\x00\x77\x00\x68\x00\x65\x00\x6e\x00\x20\x00\x64\x00\ +\x72\x00\x61\x00\x77\x00\x69\x00\x6e\x00\x67\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x2b\x49\x66\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\ +\x20\x61\x20\x67\x72\x69\x64\x20\x77\x69\x6c\x6c\x20\x61\x70\x70\ +\x65\x61\x72\x20\x77\x68\x65\x6e\x20\x64\x72\x61\x77\x69\x6e\x67\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\xe0\x00\x4a\x00\x65\x01\x5b\x00\x6c\ +\x00\x69\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\ +\x00\x7a\x00\x6f\x00\x6e\x00\x6f\x00\x2c\x00\x20\x00\x46\x00\x72\ +\x00\x65\x00\x65\x00\x43\x00\x41\x00\x44\x00\x20\x00\x73\x00\x70\ +\x00\x72\x00\xf3\x00\x62\x00\x75\x00\x6a\x00\x65\x00\x20\x00\x70\ +\x00\x6f\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x79\x01\x07\x00\x20\ +\x00\x6e\x00\x61\x00\x6b\x01\x42\x00\x61\x00\x64\x00\x61\x00\x6a\ +\x01\x05\x00\x63\x00\x65\x00\x20\x00\x73\x00\x69\x01\x19\x00\x20\ +\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x20\ +\x00\x77\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\x69\x00\x65\x00\x6c\ +\x00\x65\x00\x74\x00\x2e\x00\x20\x00\x55\x00\x77\x00\x61\x00\x67\ +\x00\x61\x00\x2c\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x6d\x00\x6f\ +\x01\x7c\x00\x65\x00\x20\x00\x70\x00\x6f\x00\x74\x00\x72\x00\x77\ +\x00\x61\x01\x07\x00\x20\x00\x63\x00\x68\x00\x77\x00\x69\x00\x6c\ +\x01\x19\x00\x2e\x00\x2e\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x65\x49\x66\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\x66\x72\ +\x65\x65\x63\x61\x64\x20\x77\x69\x6c\x6c\x20\x74\x72\x79\x20\x74\ +\x6f\x20\x6a\x6f\x69\x6e\x74\x20\x63\x6f\x69\x6e\x63\x69\x64\x65\ +\x6e\x74\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x69\x6e\x74\x6f\x20\ +\x77\x69\x72\x65\x73\x2e\x20\x42\x65\x77\x61\x72\x65\x2c\x20\x74\ +\x68\x69\x73\x20\x63\x61\x6e\x20\x74\x61\x6b\x65\x20\x61\x20\x77\ +\x68\x69\x6c\x65\x2e\x2e\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\xa2\x00\ +\x49\x00\x66\x00\x20\x00\x74\x00\x68\x00\x69\x00\x73\x00\x20\x00\ +\x69\x00\x73\x00\x20\x00\x63\x00\x68\x00\x65\x00\x63\x00\x6b\x00\ +\x65\x00\x64\x00\x2c\x00\x20\x00\x61\x00\x6c\x00\x6c\x00\x20\x00\ +\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\x73\x00\x20\x00\ +\x63\x00\x6f\x00\x6e\x00\x74\x00\x61\x00\x69\x00\x6e\x00\x69\x00\ +\x6e\x00\x67\x00\x20\x00\x66\x00\x61\x00\x63\x00\x65\x00\x73\x00\ +\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\x20\x00\x62\x00\x65\x00\ +\x20\x00\x65\x00\x78\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x65\x00\ +\x64\x00\x20\x00\x61\x00\x73\x00\x20\x00\x33\x00\x64\x00\x20\x00\ +\x70\x00\x6f\x00\x6c\x00\x79\x00\x66\x00\x61\x00\x63\x00\x65\x00\ +\x73\x08\x00\x00\x00\x00\x06\x00\x00\x00\x51\x49\x66\x20\x74\x68\ +\x69\x73\x20\x69\x73\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\x61\ +\x6c\x6c\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x63\x6f\x6e\x74\x61\ +\x69\x6e\x69\x6e\x67\x20\x66\x61\x63\x65\x73\x20\x77\x69\x6c\x6c\ +\x20\x62\x65\x20\x65\x78\x70\x6f\x72\x74\x65\x64\x20\x61\x73\x20\ +\x33\x64\x20\x70\x6f\x6c\x79\x66\x61\x63\x65\x73\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\xd0\x00\x4a\x00\x65\x01\x5b\x00\x6c\x00\x69\x00\x20\ +\x00\x77\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\ +\x00\x2c\x00\x20\x00\x74\x00\x72\x00\x79\x00\x62\x00\x20\x00\x6b\ +\x00\x6f\x00\x70\x00\x69\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\ +\x00\x61\x00\x20\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\x00\x61\ +\x00\x6b\x00\x74\x00\x79\x00\x77\x00\x6e\x00\x79\x00\x20\x00\x77\ +\x00\x20\x00\x63\x00\x7a\x00\x61\x00\x73\x00\x69\x00\x65\x00\x20\ +\x00\x6b\x00\x6f\x00\x6d\x00\x65\x00\x6e\x00\x64\x00\x79\x00\x2e\ +\x00\x20\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\ +\x00\x69\x00\x65\x00\x20\x00\x74\x00\x72\x00\x79\x00\x62\x00\x20\ +\x00\x6b\x00\x6f\x00\x70\x00\x69\x00\x6f\x00\x77\x00\x61\x00\x6e\ +\x00\x69\x00\x61\x00\x20\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\ +\x00\x77\x00\x79\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x6f\x00\x6e\ +\x00\x79\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x6f\x49\x66\ +\x20\x74\x68\x69\x73\x20\x69\x73\x20\x63\x68\x65\x63\x6b\x65\x64\ +\x2c\x20\x63\x6f\x70\x79\x20\x6d\x6f\x64\x65\x20\x77\x69\x6c\x6c\ +\x20\x62\x65\x20\x6b\x65\x70\x74\x20\x61\x63\x72\x6f\x73\x73\x20\ +\x63\x6f\x6d\x6d\x61\x6e\x64\x2c\x20\x6f\x74\x68\x65\x72\x77\x69\ +\x73\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x73\x20\x77\x69\x6c\x6c\ +\x20\x61\x6c\x77\x61\x79\x73\x20\x73\x74\x61\x72\x74\x20\x69\x6e\ +\x20\x6e\x6f\x2d\x63\x6f\x70\x79\x20\x6d\x6f\x64\x65\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\xa0\x00\x4a\x00\x65\x01\x5b\x00\x6c\x00\x69\x00\ +\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\ +\x6f\x00\x6e\x00\x65\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x79\x00\x20\x00\x62\x01\x19\x00\x64\x01\x05\x00\ +\x20\x00\x77\x00\x69\x00\x64\x00\x6f\x00\x63\x00\x7a\x00\x6e\x00\ +\x65\x00\x20\x00\x6a\x00\x61\x00\x6b\x00\x6f\x00\x20\x00\x77\x00\ +\x79\x00\x70\x00\x65\x01\x42\x00\x6e\x00\x69\x00\x6f\x00\x6e\x00\ +\x65\x00\x2e\x00\x20\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\ +\x6c\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x6a\x00\x61\x00\x6b\x00\ +\x6f\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\x69\x00\x65\x00\x6c\x00\ +\x65\x00\x74\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x66\x49\ +\x66\x20\x74\x68\x69\x73\x20\x69\x73\x20\x63\x68\x65\x63\x6b\x65\ +\x64\x2c\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x77\x69\x6c\x6c\x20\ +\x61\x70\x70\x65\x61\x72\x20\x61\x73\x20\x66\x69\x6c\x6c\x65\x64\ +\x20\x61\x73\x20\x64\x65\x66\x61\x75\x6c\x74\x2e\x20\x4f\x74\x68\ +\x65\x72\x77\x69\x73\x65\x2c\x20\x74\x68\x65\x79\x20\x77\x69\x6c\ +\x6c\x20\x61\x70\x70\x65\x61\x72\x20\x61\x73\x20\x77\x69\x72\x65\ +\x66\x72\x61\x6d\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x01\x2a\x00\x4a\x00\ +\x65\x01\x5b\x00\x6c\x00\x69\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\ +\x6e\x00\x61\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\x00\x2c\x00\ +\x20\x00\x62\x01\x19\x00\x64\x00\x7a\x00\x69\x00\x65\x00\x20\x00\ +\x7a\x00\x61\x00\x77\x00\x73\x00\x7a\x00\x65\x00\x20\x00\x70\x00\ +\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x01\ +\x42\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x69\x00\x73\x00\x74\x00\ +\x6e\x00\x69\x00\x65\x00\x6a\x01\x05\x00\x63\x00\x79\x00\x63\x00\ +\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\xf3\x00\x77\x00\x20\x00\x70\x00\x6f\x00\x64\x00\x63\x00\x7a\x00\ +\x61\x00\x73\x00\x20\x00\x72\x00\x79\x00\x73\x00\x6f\x00\x77\x00\ +\x61\x00\x6e\x00\x69\x00\x61\x00\x2e\x00\x20\x00\x4a\x00\x65\x01\ +\x5b\x00\x6c\x00\x69\x00\x20\x00\x6e\x00\x69\x00\x65\x00\x2c\x00\ +\x20\x00\x62\x01\x19\x00\x64\x00\x7a\x00\x69\x00\x65\x00\x20\x00\ +\x70\x00\x72\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\ +\x61\x01\x42\x00\x20\x00\x74\x00\x79\x00\x6c\x00\x6b\x00\x6f\x00\ +\x20\x00\x77\x00\x74\x00\x65\x00\x64\x00\x79\x00\x2c\x00\x20\x00\ +\x67\x00\x64\x00\x79\x00\x20\x00\x6e\x00\x61\x00\x63\x00\x69\x01\ +\x5b\x00\x6e\x00\x69\x00\x65\x00\x73\x00\x7a\x00\x20\x00\x43\x00\ +\x54\x00\x52\x00\x4c\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x81\x49\x66\x20\x74\x68\x69\x73\x20\x69\x73\x20\x63\x68\x65\x63\ +\x6b\x65\x64\x2c\x20\x79\x6f\x75\x20\x77\x69\x6c\x6c\x20\x61\x6c\ +\x77\x61\x79\x73\x20\x73\x6e\x61\x70\x20\x74\x6f\x20\x65\x78\x69\ +\x73\x74\x69\x6e\x67\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x77\x68\ +\x69\x6c\x65\x20\x64\x72\x61\x77\x69\x6e\x67\x2e\x20\x49\x66\x20\ +\x6e\x6f\x74\x2c\x20\x79\x6f\x75\x20\x77\x69\x6c\x6c\x20\x62\x65\ +\x20\x73\x6e\x61\x70\x70\x69\x6e\x67\x20\x6f\x6e\x6c\x79\x20\x77\ +\x68\x65\x6e\x20\x70\x72\x65\x73\x73\x69\x6e\x67\x20\x43\x54\x52\ +\x4c\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1c\x00\x49\x00\x6d\x00\x70\ +\x00\x6f\x00\x72\x00\x74\x00\x20\x00\x2a\x00\x42\x00\x6c\x00\x6f\ +\x00\x6b\x00\xf3\x00\x77\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0e\ +\x49\x6d\x70\x6f\x72\x74\x20\x2a\x62\x6c\x6f\x63\x6b\x73\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x2c\x00\x49\x00\x6d\x00\x70\x00\x6f\x00\x72\ +\x00\x74\x00\x20\x00\x70\x00\x6f\x00\x77\x00\x69\x00\x65\x00\x72\ +\x00\x7a\x00\x63\x00\x68\x00\x6e\x00\x69\x00\x20\x00\x4f\x00\x43\ +\x00\x41\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\x49\x6d\x70\x6f\ +\x72\x74\x20\x4f\x43\x41\x20\x61\x72\x65\x61\x73\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x26\x00\x49\x00\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\ +\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x77\ +\x00\x61\x00\x72\x00\x73\x00\x74\x00\x77\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x0e\x49\x6d\x70\x6f\x72\x74\x20\x6c\x61\x79\x6f\x75\ +\x74\x73\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x18\x00\x49\x00\x6d\x00\x70\ +\x00\x6f\x00\x72\x00\x74\x00\x20\x00\x73\x00\x74\x00\x79\x00\x6c\ +\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c\x49\x6d\x70\x6f\ +\x72\x74\x20\x73\x74\x79\x6c\x65\x07\x00\x00\x00\x1d\x47\x75\x69\ +\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\ +\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x30\ +\x00\x49\x00\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x75\x00\x6a\ +\x00\x20\x00\x74\x00\x65\x00\x6b\x00\x73\x00\x74\x00\x20\x00\x69\ +\x00\x20\x00\x77\x00\x79\x00\x6d\x00\x69\x00\x61\x00\x72\x00\x79\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1b\x49\x6d\x70\x6f\x72\x74\ +\x20\x74\x65\x78\x74\x73\x20\x61\x6e\x64\x20\x64\x69\x6d\x65\x6e\ +\x73\x69\x6f\x6e\x73\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1c\x00\x49\x00\ +\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x2f\x00\x65\x00\x6b\x00\ +\x73\x00\x70\x00\x6f\x00\x72\x00\x74\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x0d\x49\x6d\x70\x6f\x72\x74\x2f\x45\x78\x70\x6f\x72\x74\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x30\x00\x49\x00\x6e\x00\x74\x00\x65\ +\x00\x72\x00\x6e\x00\x61\x00\x6c\x00\x20\x00\x70\x00\x72\x00\x65\ +\x00\x63\x00\x69\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x20\x00\x6c\ +\x00\x65\x00\x76\x00\x65\x00\x6c\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x18\x49\x6e\x74\x65\x72\x6e\x61\x6c\x20\x70\x72\x65\x63\x69\ +\x73\x69\x6f\x6e\x20\x6c\x65\x76\x65\x6c\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x1a\x00\x4a\x00\x6f\x00\x69\x00\x6e\x00\x20\x00\x67\x00\x65\ +\x00\x6f\x00\x6d\x00\x65\x00\x74\x00\x72\x00\x79\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x0d\x4a\x6f\x69\x6e\x20\x67\x65\x6f\x6d\x65\ +\x74\x72\x79\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x26\x00\x4c\x00\x65\x00\ +\x77\x00\x6f\x00\x20\x00\x28\x00\x73\x00\x74\x00\x61\x00\x6e\x00\ +\x64\x00\x61\x00\x72\x00\x64\x00\x20\x00\x49\x00\x53\x00\x4f\x00\ +\x29\x08\x00\x00\x00\x00\x06\x00\x00\x00\x13\x4c\x65\x66\x74\x20\ +\x28\x49\x53\x4f\x20\x73\x74\x61\x6e\x64\x61\x72\x64\x29\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x20\x00\x4d\x00\x61\x00\x69\x00\x6e\x00\x20\ +\x00\x6c\x00\x69\x00\x6e\x00\x65\x00\x73\x00\x20\x00\x65\x00\x76\ +\x00\x65\x00\x72\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\ +\x4d\x61\x69\x6e\x20\x6c\x69\x6e\x65\x73\x20\x65\x76\x65\x72\x79\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\xa2\x00\x4d\x00\x61\x00\x69\x00\x6e\ +\x00\x6c\x00\x69\x00\x6e\x00\x65\x00\x73\x00\x20\x00\x77\x00\x69\ +\x00\x6c\x00\x6c\x00\x20\x00\x62\x00\x65\x00\x20\x00\x64\x00\x72\ +\x00\x61\x00\x77\x00\x6e\x00\x20\x00\x74\x00\x68\x00\x69\x00\x63\ +\x00\x6b\x00\x65\x00\x72\x00\x2e\x00\x20\x00\x53\x00\x70\x00\x65\ +\x00\x63\x00\x69\x00\x66\x00\x79\x00\x20\x00\x68\x00\x65\x00\x72\ +\x00\x65\x00\x20\x00\x68\x00\x6f\x00\x77\x00\x20\x00\x6d\x00\x61\ +\x00\x6e\x00\x79\x00\x20\x00\x73\x00\x71\x00\x75\x00\x61\x00\x72\ +\x00\x65\x00\x73\x00\x20\x00\x62\x00\x65\x00\x74\x00\x77\x00\x65\ +\x00\x65\x00\x6e\x00\x20\x00\x6d\x00\x61\x00\x69\x00\x6e\x00\x6c\ +\x00\x69\x00\x6e\x00\x65\x00\x73\x00\x2e\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x51\x4d\x61\x69\x6e\x6c\x69\x6e\x65\x73\x20\x77\x69\ +\x6c\x6c\x20\x62\x65\x20\x64\x72\x61\x77\x6e\x20\x74\x68\x69\x63\ +\x6b\x65\x72\x2e\x20\x53\x70\x65\x63\x69\x66\x79\x20\x68\x65\x72\ +\x65\x20\x68\x6f\x77\x20\x6d\x61\x6e\x79\x20\x73\x71\x75\x61\x72\ +\x65\x73\x20\x62\x65\x74\x77\x65\x65\x6e\x20\x6d\x61\x69\x6e\x6c\ +\x69\x6e\x65\x73\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2a\x00\x4d\x00\ +\x61\x00\x78\x00\x2e\x00\x20\x00\x73\x00\x65\x00\x67\x00\x6d\x00\ +\x65\x00\x6e\x00\x74\x00\x20\x00\x53\x00\x70\x00\x6c\x00\x61\x00\ +\x6a\x00\x6e\x00\x2d\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x12\x4d\x61\x78\x20\x53\x70\x6c\x69\x6e\x65\x20\x53\x65\x67\x6d\ +\x65\x6e\x74\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0a\x01\x7b\x00\x61\x00\ +\x64\x00\x65\x00\x6e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04\x4e\ +\x6f\x6e\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x22\x00\x42\x00\x72\x00\ +\x61\x00\x6b\x00\x20\x00\x28\x00\x6e\x00\x61\x00\x6a\x00\x73\x00\ +\x7a\x00\x79\x00\x62\x00\x73\x00\x7a\x00\x79\x00\x29\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x0e\x4e\x6f\x6e\x65\x20\x28\x66\x61\x73\ +\x74\x65\x73\x74\x29\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\xfe\x00\x4e\x00\ +\x6f\x00\x72\x00\x6d\x00\x61\x00\x6c\x00\x6c\x00\x79\x00\x2c\x00\ +\x20\x00\x61\x00\x66\x00\x74\x00\x65\x00\x72\x00\x20\x00\x63\x00\ +\x6f\x00\x70\x00\x79\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x6f\x00\ +\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\x73\x00\x2c\x00\x20\x00\ +\x74\x00\x68\x00\x65\x00\x20\x00\x63\x00\x6f\x00\x70\x00\x69\x00\ +\x65\x00\x73\x00\x20\x00\x67\x00\x65\x00\x74\x00\x20\x00\x73\x00\ +\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\x65\x00\x64\x00\x2e\x00\ +\x20\x00\x49\x00\x66\x00\x20\x00\x74\x00\x68\x00\x69\x00\x73\x00\ +\x20\x00\x6f\x00\x70\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x20\x00\ +\x69\x00\x73\x00\x20\x00\x63\x00\x68\x00\x65\x00\x63\x00\x6b\x00\ +\x65\x00\x64\x00\x2c\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\ +\x62\x00\x61\x00\x73\x00\x65\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\ +\x65\x00\x63\x00\x74\x00\x73\x00\x20\x00\x77\x00\x69\x00\x6c\x00\ +\x6c\x00\x20\x00\x62\x00\x65\x00\x20\x00\x73\x00\x65\x00\x6c\x00\ +\x65\x00\x63\x00\x74\x00\x65\x00\x64\x00\x20\x00\x69\x00\x6e\x00\ +\x73\x00\x74\x00\x65\x00\x61\x00\x64\x00\x2e\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x7f\x4e\x6f\x72\x6d\x61\x6c\x6c\x79\x2c\x20\x61\ +\x66\x74\x65\x72\x20\x63\x6f\x70\x79\x69\x6e\x67\x20\x6f\x62\x6a\ +\x65\x63\x74\x73\x2c\x20\x74\x68\x65\x20\x63\x6f\x70\x69\x65\x73\ +\x20\x67\x65\x74\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x2e\x20\x49\ +\x66\x20\x74\x68\x69\x73\x20\x6f\x70\x74\x69\x6f\x6e\x20\x69\x73\ +\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\x74\x68\x65\x20\x62\x61\ +\x73\x65\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x77\x69\x6c\x6c\x20\ +\x62\x65\x20\x73\x65\x6c\x65\x63\x74\x65\x64\x20\x69\x6e\x73\x74\ +\x65\x61\x64\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x22\x00\x4f\x00\x70\ +\x00\x63\x00\x6a\x00\x65\x00\x20\x00\x66\x00\x6f\x00\x72\x00\x6d\ +\x00\x61\x00\x74\x00\x75\x00\x20\x00\x4f\x00\x43\x00\x41\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x12\x4f\x43\x41\x20\x66\x6f\x72\x6d\ +\x61\x74\x20\x6f\x70\x74\x69\x6f\x6e\x73\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x44\x00\x4f\x00\x72\x00\x79\x00\x67\x00\x69\x00\x6e\x00\x61\ +\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\ +\x00\x72\x00\x20\x00\x69\x00\x20\x00\x73\x00\x7a\x00\x65\x00\x72\ +\x00\x6f\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x6c\x00\x69\ +\x00\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1c\ +\x4f\x72\x69\x67\x69\x6e\x61\x6c\x20\x63\x6f\x6c\x6f\x72\x20\x61\ +\x6e\x64\x20\x6c\x69\x6e\x65\x77\x69\x64\x74\x68\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x0a\x00\x50\x00\x72\x00\x61\x00\x77\x00\x6f\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x05\x52\x69\x67\x68\x74\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x22\x00\x4f\x00\x70\x00\x63\x00\x6a\x00\x65\x00\ +\x20\x00\x66\x00\x6f\x00\x72\x00\x6d\x00\x61\x00\x74\x00\x75\x00\ +\x20\x00\x53\x00\x56\x00\x47\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x12\x53\x56\x47\x20\x66\x6f\x72\x6d\x61\x74\x20\x6f\x70\x74\x69\ +\x6f\x6e\x73\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x64\x00\x5a\x00\x61\x00\ +\x70\x00\x69\x00\x73\x00\x7a\x00\x20\x00\x62\x00\x69\x00\x65\x01\ +\x7c\x01\x05\x00\x63\x00\x79\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\ +\x6f\x00\x72\x00\x20\x00\x69\x00\x20\x00\x73\x00\x7a\x00\x65\x00\ +\x72\x00\x6f\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x6c\x00\ +\x69\x00\x6e\x00\x69\x00\x69\x00\x20\x00\x63\x00\x61\x01\x42\x00\ +\x65\x00\x6a\x00\x20\x00\x73\x00\x65\x00\x73\x00\x6a\x00\x69\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x30\x53\x61\x76\x65\x20\x63\x75\ +\x72\x72\x65\x6e\x74\x20\x63\x6f\x6c\x6f\x72\x20\x61\x6e\x64\x20\ +\x6c\x69\x6e\x65\x77\x69\x64\x74\x68\x20\x61\x63\x72\x6f\x73\x73\ +\x20\x73\x65\x73\x73\x69\x6f\x6e\x73\x07\x00\x00\x00\x1d\x47\x75\ +\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\ +\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x42\x00\x53\x00\x65\x00\x6c\x00\x65\x00\x63\x00\x74\x00\x20\x00\ +\x62\x00\x61\x00\x73\x00\x65\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\ +\x65\x00\x63\x00\x74\x00\x73\x00\x20\x00\x61\x00\x66\x00\x74\x00\ +\x65\x00\x72\x00\x20\x00\x63\x00\x6f\x00\x70\x00\x79\x00\x69\x00\ +\x6e\x00\x67\x08\x00\x00\x00\x00\x06\x00\x00\x00\x21\x53\x65\x6c\ +\x65\x63\x74\x20\x62\x61\x73\x65\x20\x6f\x62\x6a\x65\x63\x74\x73\ +\x20\x61\x66\x74\x65\x72\x20\x63\x6f\x70\x79\x69\x6e\x67\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x0e\x00\x53\x00\x6c\x00\x61\x00\x73\x00\x68\ +\x00\x20\x00\x35\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07\x53\x6c\ +\x61\x73\x68\x20\x35\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0e\x00\x53\x00\ +\x6c\x00\x61\x00\x73\x00\x68\x00\x20\x00\x37\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x07\x53\x6c\x61\x73\x68\x20\x37\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x0e\x00\x53\x00\x6c\x00\x61\x00\x73\x00\x68\x00\x20\ +\x00\x39\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07\x53\x6c\x61\x73\ +\x68\x20\x39\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x26\x00\x50\x00\x72\x00\ +\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6e\x00\ +\x69\x00\x65\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\ +\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0a\x53\x6e\x61\x70\x20\ +\x63\x6f\x6c\x6f\x72\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\ +\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\ +\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x12\x00\x54\x00\ +\x72\x00\x79\x00\x62\x00\x20\x00\x53\x00\x6e\x00\x61\x00\x70\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x08\x53\x6e\x61\x70\x20\x6d\x6f\ +\x64\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x14\x00\x53\x00\x6e\x00\x61\x00\ +\x70\x00\x20\x00\x72\x00\x61\x00\x6e\x00\x67\x00\x65\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x0a\x53\x6e\x61\x70\x20\x72\x61\x6e\x67\ +\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x16\x00\x50\x00\x61\x00\x73\x00\ +\x65\x00\x6b\x00\x20\x00\x7a\x00\x61\x00\x64\x00\x61\x01\x44\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x08\x54\x61\x73\x6b\x76\x69\x65\ +\x77\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x3a\x00\x54\x00\x68\x00\x65\x00\ +\x20\x00\x43\x00\x6f\x00\x6e\x00\x73\x00\x74\x00\x72\x00\x61\x00\ +\x69\x00\x6e\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x6d\x00\x6f\x00\ +\x64\x00\x69\x00\x66\x00\x69\x00\x65\x00\x72\x00\x20\x00\x6b\x00\ +\x65\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1d\x54\x68\x65\ +\x20\x43\x6f\x6e\x73\x74\x72\x61\x69\x6e\x69\x6e\x67\x20\x6d\x6f\ +\x64\x69\x66\x69\x65\x72\x20\x6b\x65\x79\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x28\x00\x54\x00\x68\x00\x65\x00\x20\x00\x61\x00\x6c\x00\x74\ +\x00\x20\x00\x6d\x00\x6f\x00\x64\x00\x69\x00\x66\x00\x69\x00\x65\ +\x00\x72\x00\x20\x00\x6b\x00\x65\x00\x79\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x14\x54\x68\x65\x20\x61\x6c\x74\x20\x6d\x6f\x64\x69\ +\x66\x69\x65\x72\x20\x6b\x65\x79\x07\x00\x00\x00\x1d\x47\x75\x69\ +\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\ +\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x58\ +\x00\x50\x00\x6c\x00\x69\x00\x6b\x00\x20\x00\x6d\x00\x61\x00\x70\ +\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x61\x00\x20\x00\x6b\ +\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\xf3\x00\x77\x00\x20\x00\x44\ +\x00\x58\x00\x46\x00\x20\x00\x6e\x00\x61\x00\x20\x00\x67\x00\x72\ +\x00\x75\x00\x62\x00\x6f\x01\x5b\x00\x63\x00\x69\x00\x20\x00\x6c\ +\x00\x69\x00\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x41\x54\x68\x65\x20\x63\x6f\x6c\x6f\x72\x20\x6d\x61\x70\x70\ +\x69\x6e\x67\x20\x66\x69\x6c\x65\x20\x66\x6f\x72\x20\x74\x72\x61\ +\x6e\x73\x6c\x61\x74\x69\x6e\x67\x20\x64\x78\x66\x20\x63\x6f\x6c\ +\x6f\x72\x73\x20\x69\x6e\x74\x6f\x20\x6c\x69\x6e\x65\x77\x69\x64\ +\x74\x68\x73\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x7a\x00\x44\x00\x6f\x00\ +\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\x73\x00\ +\x7a\x00\x61\x00\x62\x00\x6c\x00\x6f\x00\x6e\x00\x20\x00\x70\x00\ +\x6f\x00\x64\x00\x63\x00\x7a\x00\x61\x00\x73\x00\x20\x00\x74\x00\ +\x77\x00\x6f\x00\x72\x00\x7a\x00\x65\x00\x6e\x00\x69\x00\x61\x00\ +\x20\x00\x6e\x00\x6f\x00\x77\x00\x65\x00\x67\x00\x6f\x00\x20\x00\ +\x61\x00\x72\x00\x6b\x00\x75\x00\x73\x00\x7a\x00\x61\x00\x20\x00\ +\x72\x00\x79\x00\x73\x00\x75\x00\x6e\x00\x6b\x00\x6f\x00\x77\x00\ +\x65\x00\x67\x00\x6f\x08\x00\x00\x00\x00\x06\x00\x00\x00\x3d\x54\ +\x68\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x74\x65\x6d\x70\x6c\ +\x61\x74\x65\x20\x74\x6f\x20\x75\x73\x65\x20\x77\x68\x65\x6e\x20\ +\x63\x72\x65\x61\x74\x69\x6e\x67\x20\x61\x20\x6e\x65\x77\x20\x64\ +\x72\x61\x77\x69\x6e\x67\x20\x73\x68\x65\x65\x74\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x72\x00\x49\x00\x6c\x00\x6f\x01\x5b\x01\x07\x00\x20\ +\x00\x6d\x00\x69\x00\x65\x00\x6a\x00\x73\x00\x63\x00\x20\x00\x64\ +\x00\x7a\x00\x69\x00\x65\x00\x73\x00\x69\x01\x19\x00\x74\x00\x6e\ +\x00\x79\x00\x63\x00\x68\x00\x20\x00\x64\x00\x6c\x00\x61\x00\x20\ +\x00\x77\x00\x73\x00\x70\x00\xf3\x01\x42\x00\x72\x00\x7a\x01\x19\ +\x00\x64\x00\x6e\x00\x79\x00\x63\x00\x68\x00\x20\x00\x77\x00\x65\ +\x00\x77\x00\x6e\x01\x19\x00\x74\x00\x72\x00\x7a\x00\x6e\x00\x79\ +\x00\x63\x00\x68\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x4d\ +\x54\x68\x65\x20\x6e\x75\x6d\x62\x65\x72\x20\x6f\x66\x20\x64\x65\ +\x63\x69\x6d\x61\x6c\x73\x20\x69\x6e\x20\x69\x6e\x74\x65\x72\x6e\ +\x61\x6c\x20\x63\x6f\x6f\x72\x64\x69\x6e\x61\x74\x65\x73\x20\x6f\ +\x70\x65\x72\x61\x74\x69\x6f\x6e\x73\x20\x28\x66\x6f\x72\x20\x65\ +\x78\x2e\x20\x33\x20\x3d\x20\x30\x2e\x30\x30\x31\x29\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x9c\x00\x54\x00\x68\x00\x65\x00\x20\x00\x72\x00\ +\x61\x00\x64\x00\x69\x00\x75\x00\x73\x00\x20\x00\x66\x00\x6f\x00\ +\x72\x00\x20\x00\x73\x00\x6e\x00\x61\x00\x70\x00\x70\x00\x69\x00\ +\x6e\x00\x67\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x73\x00\x70\x00\ +\x65\x00\x63\x00\x69\x00\x61\x00\x6c\x00\x20\x00\x70\x00\x6f\x00\ +\x69\x00\x6e\x00\x74\x00\x73\x00\x2e\x00\x20\x00\x53\x00\x65\x00\ +\x74\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x30\x00\x20\x00\x66\x00\ +\x6f\x00\x72\x00\x20\x00\x6e\x00\x6f\x00\x20\x00\x64\x00\x69\x00\ +\x73\x00\x74\x00\x61\x00\x6e\x00\x63\x00\x65\x00\x20\x00\x28\x00\ +\x69\x00\x6e\x00\x66\x00\x69\x00\x6e\x00\x69\x00\x74\x00\x65\x00\ +\x29\x08\x00\x00\x00\x00\x06\x00\x00\x00\x4e\x54\x68\x65\x20\x72\ +\x61\x64\x69\x75\x73\x20\x66\x6f\x72\x20\x73\x6e\x61\x70\x70\x69\ +\x6e\x67\x20\x74\x6f\x20\x73\x70\x65\x63\x69\x61\x6c\x20\x70\x6f\ +\x69\x6e\x74\x73\x2e\x20\x53\x65\x74\x20\x74\x6f\x20\x30\x20\x66\ +\x6f\x72\x20\x6e\x6f\x20\x64\x69\x73\x74\x61\x6e\x63\x65\x20\x28\ +\x69\x6e\x66\x69\x6e\x69\x74\x65\x29\x07\x00\x00\x00\x1d\x47\x75\ +\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\ +\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x2a\x00\x54\x00\x68\x00\x65\x00\x20\x00\x73\x00\x6e\x00\x61\x00\ +\x70\x00\x20\x00\x6d\x00\x6f\x00\x64\x00\x69\x00\x66\x00\x69\x00\ +\x65\x00\x72\x00\x20\x00\x6b\x00\x65\x00\x79\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x15\x54\x68\x65\x20\x73\x6e\x61\x70\x20\x6d\x6f\ +\x64\x69\x66\x69\x65\x72\x20\x6b\x65\x79\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x44\x00\x54\x00\x68\x00\x65\x00\x20\x00\x73\x00\x70\x00\x61\ +\x00\x63\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x62\x00\x65\x00\x74\ +\x00\x77\x00\x65\x00\x65\x00\x6e\x00\x20\x00\x65\x00\x61\x00\x63\ +\x00\x68\x00\x20\x00\x67\x00\x72\x00\x69\x00\x64\x00\x20\x00\x6c\ +\x00\x69\x00\x6e\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x22\ +\x54\x68\x65\x20\x73\x70\x61\x63\x69\x6e\x67\x20\x62\x65\x74\x77\ +\x65\x65\x6e\x20\x65\x61\x63\x68\x20\x67\x72\x69\x64\x20\x6c\x69\ +\x6e\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x01\x9e\x00\x54\x00\x68\x00\x69\ +\x00\x73\x00\x20\x00\x69\x00\x73\x00\x20\x00\x74\x00\x68\x00\x65\ +\x00\x20\x00\x55\x00\x49\x00\x20\x00\x6d\x00\x6f\x00\x64\x00\x65\ +\x00\x20\x00\x69\x00\x6e\x00\x20\x00\x77\x00\x68\x00\x69\x00\x63\ +\x00\x68\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x44\x00\x72\ +\x00\x61\x00\x66\x00\x74\x00\x20\x00\x6d\x00\x6f\x00\x64\x00\x75\ +\x00\x6c\x00\x65\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\x20\ +\x00\x77\x00\x6f\x00\x72\x00\x6b\x00\x3a\x00\x20\x00\x54\x00\x6f\ +\x00\x6f\x00\x6c\x00\x62\x00\x61\x00\x72\x00\x20\x00\x6d\x00\x6f\ +\x00\x64\x00\x65\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\x20\ +\x00\x70\x00\x6c\x00\x61\x00\x63\x00\x65\x00\x20\x00\x61\x00\x6c\ +\x00\x6c\x00\x20\x00\x44\x00\x72\x00\x61\x00\x66\x00\x74\x00\x20\ +\x00\x73\x00\x65\x00\x74\x00\x74\x00\x69\x00\x6e\x00\x67\x00\x73\ +\x00\x20\x00\x69\x00\x6e\x00\x20\x00\x61\x00\x20\x00\x73\x00\x65\ +\x00\x70\x00\x61\x00\x72\x00\x61\x00\x74\x00\x65\x00\x20\x00\x74\ +\x00\x6f\x00\x6f\x00\x6c\x00\x62\x00\x61\x00\x72\x00\x2c\x00\x20\ +\x00\x77\x00\x68\x00\x69\x00\x6c\x00\x65\x00\x20\x00\x74\x00\x61\ +\x00\x73\x00\x6b\x00\x62\x00\x61\x00\x72\x00\x20\x00\x6d\x00\x6f\ +\x00\x64\x00\x65\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\x20\ +\x00\x75\x00\x73\x00\x65\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\ +\x00\x46\x00\x72\x00\x65\x00\x65\x00\x43\x00\x41\x00\x44\x00\x20\ +\x00\x54\x00\x61\x00\x73\x00\x6b\x00\x76\x00\x69\x00\x65\x00\x77\ +\x00\x20\x00\x73\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x20\ +\x00\x66\x00\x6f\x00\x72\x00\x20\x00\x61\x00\x6c\x00\x6c\x00\x20\ +\x00\x69\x00\x74\x00\x73\x00\x20\x00\x75\x00\x73\x00\x65\x00\x72\ +\x00\x20\x00\x69\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x61\x00\x63\ +\x00\x74\x00\x69\x00\x6f\x00\x6e\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\xcf\x54\x68\x69\x73\x20\x69\x73\x20\x74\x68\x65\x20\x55\x49\ +\x20\x6d\x6f\x64\x65\x20\x69\x6e\x20\x77\x68\x69\x63\x68\x20\x74\ +\x68\x65\x20\x44\x72\x61\x66\x74\x20\x6d\x6f\x64\x75\x6c\x65\x20\ +\x77\x69\x6c\x6c\x20\x77\x6f\x72\x6b\x3a\x20\x54\x6f\x6f\x6c\x62\ +\x61\x72\x20\x6d\x6f\x64\x65\x20\x77\x69\x6c\x6c\x20\x70\x6c\x61\ +\x63\x65\x20\x61\x6c\x6c\x20\x44\x72\x61\x66\x74\x20\x73\x65\x74\ +\x74\x69\x6e\x67\x73\x20\x69\x6e\x20\x61\x20\x73\x65\x70\x61\x72\ +\x61\x74\x65\x20\x74\x6f\x6f\x6c\x62\x61\x72\x2c\x20\x77\x68\x69\ +\x6c\x65\x20\x74\x61\x73\x6b\x62\x61\x72\x20\x6d\x6f\x64\x65\x20\ +\x77\x69\x6c\x6c\x20\x75\x73\x65\x20\x74\x68\x65\x20\x46\x72\x65\ +\x65\x43\x41\x44\x20\x54\x61\x73\x6b\x76\x69\x65\x77\x20\x73\x79\ +\x73\x74\x65\x6d\x20\x66\x6f\x72\x20\x61\x6c\x6c\x20\x69\x74\x73\ +\x20\x75\x73\x65\x72\x20\x69\x6e\x74\x65\x72\x61\x63\x74\x69\x6f\ +\x6e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x94\x00\x4a\x00\x65\x00\x73\x00\ +\x74\x00\x20\x00\x74\x00\x6f\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\ +\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\x6b\x00\x6f\x00\ +\x6c\x00\x6f\x00\x72\x00\x20\x00\x64\x00\x6c\x00\x61\x00\x20\x00\ +\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\xf3\x00\x77\x00\ +\x2c\x00\x20\x00\x6b\x00\x74\x00\xf3\x00\x72\x00\x65\x00\x20\x00\ +\x73\x01\x05\x00\x20\x00\x73\x00\x70\x00\x6f\x00\x72\x00\x7a\x01\ +\x05\x00\x64\x00\x7a\x00\x6f\x00\x6e\x00\x65\x00\x20\x00\x77\x00\ +\x20\x00\x74\x00\x72\x00\x79\x00\x62\x00\x69\x00\x65\x00\x20\x00\ +\x62\x00\x75\x00\x64\x00\x6f\x00\x77\x00\x79\x00\x2e\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x4d\x54\x68\x69\x73\x20\x69\x73\x20\x74\ +\x68\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6c\x6f\x72\ +\x20\x66\x6f\x72\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x62\x65\x69\ +\x6e\x67\x20\x64\x72\x61\x77\x6e\x20\x77\x68\x69\x6c\x65\x20\x69\ +\x6e\x20\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x69\x6f\x6e\x20\x6d\ +\x6f\x64\x65\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x01\xe0\x00\x54\x00\x6f\ +\x00\x20\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\x00\x6e\x00\x61\ +\x00\x7a\x00\x77\x00\x61\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\ +\x01\x5b\x00\x6c\x00\x6e\x00\x65\x00\x6a\x00\x20\x00\x63\x00\x7a\ +\x00\x63\x00\x69\x00\x6f\x00\x6e\x00\x6b\x00\x69\x00\x20\x00\x64\ +\x00\x6c\x00\x61\x00\x20\x00\x77\x00\x73\x00\x7a\x00\x79\x00\x73\ +\x00\x74\x00\x6b\x00\x69\x00\x63\x00\x68\x00\x20\x00\x74\x00\x65\ +\x00\x6b\x00\x73\x00\x74\x00\xf3\x00\x77\x00\x20\x00\x69\x00\x20\ +\x00\x77\x00\x79\x00\x6d\x00\x69\x00\x61\x00\x72\x00\xf3\x00\x77\ +\x00\x2e\x00\x20\x00\x4d\x00\x6f\x01\x7c\x00\x65\x00\x20\x00\x74\ +\x00\x6f\x00\x20\x00\x62\x00\x79\x01\x07\x00\x20\x00\x6e\x00\x70\ +\x00\x2e\x00\x20\x00\x6e\x00\x61\x00\x7a\x00\x77\x00\x61\x00\x20\ +\x00\x63\x00\x7a\x00\x63\x00\x69\x00\x6f\x00\x6e\x00\x6b\x00\x69\ +\x00\x20\x00\x22\x00\x41\x00\x72\x00\x69\x00\x61\x00\x6c\x00\x22\ +\x00\x2c\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\ +\x00\x6e\x00\x79\x00\x20\x00\x73\x00\x74\x00\x79\x00\x6c\x00\x2c\ +\x00\x20\x00\x74\x00\x61\x00\x6b\x00\x20\x00\x6a\x00\x61\x00\x6b\ +\x00\x20\x00\x22\x00\x73\x00\x61\x00\x6e\x00\x73\x00\x22\x00\x2c\ +\x00\x20\x00\x22\x00\x73\x00\x65\x00\x72\x00\x69\x00\x66\x00\x22\ +\x00\x20\x00\x6c\x00\x75\x00\x62\x00\x20\x00\x22\x00\x6d\x00\x6f\ +\x00\x6e\x00\x6f\x00\x22\x00\x20\x00\x6c\x00\x75\x00\x62\x00\x20\ +\x00\x72\x00\x6f\x00\x64\x00\x7a\x00\x69\x00\x6e\x00\x79\x00\x2c\ +\x00\x20\x00\x6a\x00\x61\x00\x6b\x00\x20\x00\x6e\x00\x70\x00\x2e\ +\x00\x20\x00\x22\x00\x41\x00\x72\x00\x69\x00\x61\x00\x6c\x00\x2c\ +\x00\x20\x00\x48\x00\x65\x00\x6c\x00\x76\x00\x65\x00\x74\x00\x69\ +\x00\x63\x00\x61\x00\x2c\x00\x20\x00\x73\x00\x61\x00\x6e\x00\x73\ +\x00\x20\x00\x22\x00\x6c\x00\x75\x00\x62\x00\x20\x00\x6e\x00\x61\ +\x00\x7a\x00\x77\x01\x19\x00\x20\x00\x77\x00\x20\x00\x73\x00\x74\ +\x00\x79\x00\x6c\x00\x75\x00\x20\x00\x6e\x00\x70\x00\x2e\x00\x22\ +\x00\x20\x00\x41\x00\x72\x00\x69\x00\x61\x00\x6c\x00\x3a\x00\x20\ +\x00\x42\x00\x6f\x00\x6c\x00\x64\x00\x20\x00\x22\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\xf2\x54\x68\x69\x73\x20\x69\x73\x20\x74\x68\ +\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x66\x6f\x6e\x74\x20\x6e\ +\x61\x6d\x65\x20\x66\x6f\x72\x20\x61\x6c\x6c\x20\x44\x72\x61\x66\ +\x74\x20\x74\x65\x78\x74\x73\x20\x61\x6e\x64\x20\x64\x69\x6d\x65\ +\x6e\x73\x69\x6f\x6e\x73\x2e\x0a\x49\x74\x20\x63\x61\x6e\x20\x62\ +\x65\x20\x61\x20\x66\x6f\x6e\x74\x20\x6e\x61\x6d\x65\x20\x73\x75\ +\x63\x68\x20\x61\x73\x20\x22\x41\x72\x69\x61\x6c\x22\x2c\x20\x61\ +\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x73\x74\x79\x6c\x65\x20\x73\ +\x75\x63\x68\x20\x61\x73\x20\x22\x73\x61\x6e\x73\x22\x2c\x20\x22\ +\x73\x65\x72\x69\x66\x22\x0a\x6f\x72\x20\x22\x6d\x6f\x6e\x6f\x22\ +\x2c\x20\x6f\x72\x20\x61\x20\x66\x61\x6d\x69\x6c\x79\x20\x73\x75\ +\x63\x68\x20\x61\x73\x20\x22\x41\x72\x69\x61\x6c\x2c\x48\x65\x6c\ +\x76\x65\x74\x69\x63\x61\x2c\x73\x61\x6e\x73\x22\x20\x6f\x72\x20\ +\x61\x20\x6e\x61\x6d\x65\x20\x77\x69\x74\x68\x20\x61\x20\x73\x74\ +\x79\x6c\x65\x0a\x73\x75\x63\x68\x20\x61\x73\x20\x22\x41\x72\x69\ +\x61\x6c\x3a\x42\x6f\x6c\x64\x22\x07\x00\x00\x00\x1d\x47\x75\x69\ +\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\ +\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x6c\ +\x00\x4a\x00\x65\x00\x73\x00\x74\x00\x20\x00\x74\x00\x6f\x00\x20\ +\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x61\ +\x00\x20\x00\x6e\x00\x61\x00\x7a\x00\x77\x00\x61\x00\x20\x00\x67\ +\x00\x72\x00\x75\x00\x70\x00\x79\x00\x20\x00\x64\x00\x6c\x00\x61\ +\x00\x20\x00\x67\x00\x65\x00\x6f\x00\x6d\x00\x65\x00\x74\x00\x72\ +\x00\x69\x00\x69\x00\x20\x00\x6b\x00\x6f\x00\x6e\x00\x73\x00\x74\ +\x00\x72\x00\x75\x00\x6b\x00\x63\x00\x6a\x00\x69\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x38\x54\x68\x69\x73\x20\x69\x73\x20\x74\x68\ +\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x67\x72\x6f\x75\x70\x20\ +\x6e\x61\x6d\x65\x20\x66\x6f\x72\x20\x63\x6f\x6e\x73\x74\x72\x75\ +\x63\x74\x69\x6f\x6e\x20\x67\x65\x6f\x6d\x65\x74\x72\x79\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x6c\x00\x57\x00\x79\x00\x62\x00\x72\x00\x61\ +\x00\x6e\x00\x6f\x00\x20\x00\x6d\x00\x65\x00\x74\x00\x6f\x00\x64\ +\x01\x19\x00\x20\x00\x69\x00\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\ +\x00\x75\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x75\ +\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x75\ +\x00\x20\x00\x53\x00\x56\x00\x47\x00\x20\x00\x64\x00\x6f\x00\x20\ +\x00\x46\x00\x72\x00\x65\x00\x65\x00\x43\x00\x41\x00\x44\x00\x61\ +\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x47\x54\x68\x69\x73\ +\x20\x69\x73\x20\x74\x68\x65\x20\x6d\x65\x74\x68\x6f\x64\x20\x63\ +\x68\x6f\x6f\x73\x65\x64\x20\x66\x6f\x72\x20\x69\x6d\x70\x6f\x72\ +\x74\x69\x6e\x67\x20\x53\x56\x47\x20\x6f\x62\x6a\x65\x63\x74\x20\ +\x63\x6f\x6c\x6f\x72\x20\x69\x6e\x74\x6f\x20\x46\x72\x65\x65\x43\ +\x41\x44\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\ +\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\ +\x44\x72\x61\x66\x74\x01\x03\x00\x00\x01\xc6\x00\x54\x00\x68\x00\ +\x69\x00\x73\x00\x20\x00\x69\x00\x73\x00\x20\x00\x74\x00\x68\x00\ +\x65\x00\x20\x00\x6d\x00\x65\x00\x74\x00\x68\x00\x6f\x00\x64\x00\ +\x20\x00\x63\x00\x68\x00\x6f\x00\x6f\x00\x73\x00\x65\x00\x64\x00\ +\x20\x00\x66\x00\x6f\x00\x72\x00\x20\x00\x69\x00\x6d\x00\x70\x00\ +\x6f\x00\x72\x00\x74\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x6f\x00\ +\x72\x00\x20\x00\x74\x00\x72\x00\x61\x00\x6e\x00\x73\x00\x6c\x00\ +\x61\x00\x74\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x44\x00\x58\x00\ +\x46\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\ +\x20\x00\x63\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\x69\x00\ +\x6e\x00\x74\x00\x6f\x00\x20\x00\x46\x00\x72\x00\x65\x00\x65\x00\ +\x43\x00\x41\x00\x44\x00\x2e\x00\x20\x00\x0a\x00\x49\x00\x66\x00\ +\x20\x00\x63\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\x6d\x00\ +\x61\x00\x70\x00\x70\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x69\x00\ +\x73\x00\x20\x00\x63\x00\x68\x00\x6f\x00\x6f\x00\x73\x00\x65\x00\ +\x64\x00\x2c\x00\x20\x00\x79\x00\x6f\x00\x75\x00\x20\x00\x6d\x00\ +\x75\x00\x73\x00\x74\x00\x20\x00\x63\x00\x68\x00\x6f\x00\x6f\x00\ +\x73\x00\x65\x00\x20\x00\x61\x00\x20\x00\x63\x00\x6f\x00\x6c\x00\ +\x6f\x00\x72\x00\x20\x00\x6d\x00\x61\x00\x70\x00\x70\x00\x69\x00\ +\x6e\x00\x67\x00\x20\x00\x66\x00\x69\x00\x6c\x00\x65\x00\x20\x00\ +\x63\x00\x6f\x00\x6e\x00\x74\x00\x61\x00\x69\x00\x6e\x00\x69\x00\ +\x6e\x00\x67\x00\x20\x00\x61\x00\x20\x00\x74\x00\x72\x00\x61\x00\ +\x6e\x00\x73\x00\x6c\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\ +\x20\x00\x74\x00\x61\x00\x62\x00\x6c\x00\x65\x00\x20\x00\x74\x00\ +\x68\x00\x61\x00\x74\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\ +\x20\x00\x63\x00\x6f\x00\x6e\x00\x76\x00\x65\x00\x72\x00\x74\x00\ +\x20\x00\x63\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x73\x00\x20\x00\ +\x69\x00\x6e\x00\x74\x00\x6f\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\ +\x65\x00\x77\x00\x69\x00\x64\x00\x74\x00\x68\x00\x73\x00\x2e\x00\ +\x0a\x08\x00\x00\x00\x00\x06\x00\x00\x00\xe3\x54\x68\x69\x73\x20\ +\x69\x73\x20\x74\x68\x65\x20\x6d\x65\x74\x68\x6f\x64\x20\x63\x68\ +\x6f\x6f\x73\x65\x64\x20\x66\x6f\x72\x20\x69\x6d\x70\x6f\x72\x74\ +\x69\x6e\x67\x20\x6f\x72\x20\x74\x72\x61\x6e\x73\x6c\x61\x74\x69\ +\x6e\x67\x20\x44\x58\x46\x20\x6f\x62\x6a\x65\x63\x74\x20\x63\x6f\ +\x6c\x6f\x72\x20\x69\x6e\x74\x6f\x20\x46\x72\x65\x65\x43\x41\x44\ +\x2e\x20\x0a\x49\x66\x20\x63\x6f\x6c\x6f\x72\x20\x6d\x61\x70\x70\ +\x69\x6e\x67\x20\x69\x73\x20\x63\x68\x6f\x6f\x73\x65\x64\x2c\x20\ +\x79\x6f\x75\x20\x6d\x75\x73\x74\x20\x63\x68\x6f\x6f\x73\x65\x20\ +\x61\x20\x63\x6f\x6c\x6f\x72\x20\x6d\x61\x70\x70\x69\x6e\x67\x20\ +\x66\x69\x6c\x65\x20\x63\x6f\x6e\x74\x61\x69\x6e\x69\x6e\x67\x20\ +\x61\x20\x74\x72\x61\x6e\x73\x6c\x61\x74\x69\x6f\x6e\x20\x74\x61\ +\x62\x6c\x65\x20\x74\x68\x61\x74\x20\x77\x69\x6c\x6c\x20\x63\x6f\ +\x6e\x76\x65\x72\x74\x20\x63\x6f\x6c\x6f\x72\x73\x20\x69\x6e\x74\ +\x6f\x20\x6c\x69\x6e\x65\x77\x69\x64\x74\x68\x73\x2e\x0a\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\xfc\x00\x54\x00\x68\x00\x69\x00\x73\x00\x20\ +\x00\x69\x00\x73\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x6f\ +\x00\x72\x00\x69\x00\x65\x00\x6e\x00\x74\x00\x61\x00\x74\x00\x69\ +\x00\x6f\x00\x6e\x00\x20\x00\x6f\x00\x66\x00\x20\x00\x74\x00\x68\ +\x00\x65\x00\x20\x00\x64\x00\x69\x00\x6d\x00\x65\x00\x6e\x00\x73\ +\x00\x69\x00\x6f\x00\x6e\x00\x20\x00\x74\x00\x65\x00\x78\x00\x74\ +\x00\x73\x00\x20\x00\x77\x00\x68\x00\x65\x00\x6e\x00\x20\x00\x74\ +\x00\x68\x00\x6f\x00\x73\x00\x65\x00\x20\x00\x64\x00\x69\x00\x6d\ +\x00\x65\x00\x6e\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x73\x00\x20\ +\x00\x61\x00\x72\x00\x65\x00\x20\x00\x76\x00\x65\x00\x72\x00\x74\ +\x00\x69\x00\x63\x00\x61\x00\x6c\x00\x2e\x00\x20\x00\x44\x00\x65\ +\x00\x66\x00\x61\x00\x75\x00\x6c\x00\x74\x00\x20\x00\x69\x00\x73\ +\x00\x20\x00\x6c\x00\x65\x00\x66\x00\x74\x00\x2c\x00\x20\x00\x77\ +\x00\x68\x00\x69\x00\x63\x00\x68\x00\x20\x00\x69\x00\x73\x00\x20\ +\x00\x74\x00\x68\x00\x65\x00\x20\x00\x49\x00\x53\x00\x4f\x00\x20\ +\x00\x73\x00\x74\x00\x61\x00\x6e\x00\x64\x00\x61\x00\x72\x00\x64\ +\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x7e\x54\x68\x69\x73\ +\x20\x69\x73\x20\x74\x68\x65\x20\x6f\x72\x69\x65\x6e\x74\x61\x74\ +\x69\x6f\x6e\x20\x6f\x66\x20\x74\x68\x65\x20\x64\x69\x6d\x65\x6e\ +\x73\x69\x6f\x6e\x20\x74\x65\x78\x74\x73\x20\x77\x68\x65\x6e\x20\ +\x74\x68\x6f\x73\x65\x20\x64\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x73\ +\x20\x61\x72\x65\x20\x76\x65\x72\x74\x69\x63\x61\x6c\x2e\x20\x44\ +\x65\x66\x61\x75\x6c\x74\x20\x69\x73\x20\x6c\x65\x66\x74\x2c\x20\ +\x77\x68\x69\x63\x68\x20\x69\x73\x20\x74\x68\x65\x20\x49\x53\x4f\ +\x20\x73\x74\x61\x6e\x64\x61\x72\x64\x2e\x07\x00\x00\x00\x1d\x47\ +\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\ +\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\xf6\x00\x54\x00\x68\x00\x69\x00\x73\x00\x20\x00\x69\x00\x73\ +\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x76\x00\x61\x00\x6c\ +\x00\x75\x00\x65\x00\x20\x00\x75\x00\x73\x00\x65\x00\x64\x00\x20\ +\x00\x62\x00\x79\x00\x20\x00\x66\x00\x75\x00\x6e\x00\x63\x00\x74\ +\x00\x69\x00\x6f\x00\x6e\x00\x73\x00\x20\x00\x74\x00\x68\x00\x61\ +\x00\x74\x00\x20\x00\x75\x00\x73\x00\x65\x00\x20\x00\x61\x00\x20\ +\x00\x74\x00\x6f\x00\x6c\x00\x65\x00\x72\x00\x61\x00\x6e\x00\x63\ +\x00\x65\x00\x2e\x00\x0a\x00\x56\x00\x61\x00\x6c\x00\x75\x00\x65\ +\x00\x73\x00\x20\x00\x77\x00\x69\x00\x74\x00\x68\x00\x20\x00\x64\ +\x00\x69\x00\x66\x00\x66\x00\x65\x00\x72\x00\x65\x00\x6e\x00\x63\ +\x00\x65\x00\x73\x00\x20\x00\x62\x00\x65\x00\x6c\x00\x6f\x00\x77\ +\x00\x20\x00\x74\x00\x68\x00\x69\x00\x73\x00\x20\x00\x76\x00\x61\ +\x00\x6c\x00\x75\x00\x65\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\ +\x00\x20\x00\x62\x00\x65\x00\x20\x00\x74\x00\x72\x00\x65\x00\x61\ +\x00\x74\x00\x65\x00\x64\x00\x20\x00\x61\x00\x73\x00\x20\x00\x73\ +\x00\x61\x00\x6d\x00\x65\x00\x2e\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x7b\x54\x68\x69\x73\x20\x69\x73\x20\x74\x68\x65\x20\x76\x61\ +\x6c\x75\x65\x20\x75\x73\x65\x64\x20\x62\x79\x20\x66\x75\x6e\x63\ +\x74\x69\x6f\x6e\x73\x20\x74\x68\x61\x74\x20\x75\x73\x65\x20\x61\ +\x20\x74\x6f\x6c\x65\x72\x61\x6e\x63\x65\x2e\x0a\x56\x61\x6c\x75\ +\x65\x73\x20\x77\x69\x74\x68\x20\x64\x69\x66\x66\x65\x72\x65\x6e\ +\x63\x65\x73\x20\x62\x65\x6c\x6f\x77\x20\x74\x68\x69\x73\x20\x76\ +\x61\x6c\x75\x65\x20\x77\x69\x6c\x6c\x20\x62\x65\x20\x74\x72\x65\ +\x61\x74\x65\x64\x20\x61\x73\x20\x73\x61\x6d\x65\x2e\x07\x00\x00\ +\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\ +\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x14\x00\x54\x00\x6f\x00\x6c\x00\x65\x00\x72\x00\ +\x61\x00\x6e\x00\x63\x00\x6a\x00\x61\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x09\x54\x6f\x6c\x65\x72\x61\x6e\x63\x65\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x1c\x00\x50\x00\x61\x00\x73\x00\x65\x00\x6b\x00\x20\ +\x00\x6e\x00\x61\x00\x72\x00\x7a\x01\x19\x00\x64\x00\x7a\x00\x69\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07\x54\x6f\x6f\x6c\x62\x61\ +\x72\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x52\x00\x55\x01\x7c\x00\x79\x00\ +\x6a\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\ +\x6e\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\ +\x6f\x00\x72\x00\x75\x00\x20\x00\x69\x00\x20\x00\x73\x00\x7a\x00\ +\x65\x00\x72\x00\x6f\x00\x6b\x00\x6f\x01\x5b\x00\x63\x00\x69\x00\ +\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x1f\x55\x73\x65\x20\x64\x65\x66\x61\x75\x6c\x74\ +\x20\x63\x6f\x6c\x6f\x72\x20\x61\x6e\x64\x20\x6c\x69\x6e\x65\x77\ +\x69\x64\x74\x68\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x10\x00\x55\x00\x73\ +\x00\x65\x00\x20\x00\x67\x00\x72\x00\x69\x00\x64\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x08\x55\x73\x65\x20\x67\x72\x69\x64\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x48\x00\x56\x00\x65\x00\x72\x00\x74\x00\x69\ +\x00\x63\x00\x61\x00\x6c\x00\x20\x00\x64\x00\x69\x00\x6d\x00\x65\ +\x00\x6e\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x73\x00\x20\x00\x74\ +\x00\x65\x00\x78\x00\x74\x00\x20\x00\x6f\x00\x72\x00\x69\x00\x65\ +\x00\x6e\x00\x74\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x24\x56\x65\x72\x74\x69\x63\x61\x6c\ +\x20\x64\x69\x6d\x65\x6e\x73\x69\x6f\x6e\x73\x20\x74\x65\x78\x74\ +\x20\x6f\x72\x69\x65\x6e\x74\x61\x74\x69\x6f\x6e\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x01\xb4\x00\x50\x00\x6f\x00\x64\x00\x63\x00\x7a\x00\x61\ +\x00\x73\x00\x20\x00\x65\x00\x6b\x00\x73\x00\x70\x00\x6f\x00\x72\ +\x00\x74\x00\x75\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x44\x00\x58\ +\x00\x46\x00\x20\x00\x53\x00\x70\x00\x6c\x00\x61\x00\x6a\x00\x6e\ +\x00\x79\x00\x20\x00\x7a\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x6e\ +\x01\x05\x00\x20\x00\x70\x00\x72\x00\x7a\x00\x65\x00\x6b\x00\x6f\ +\x00\x6e\x00\x77\x00\x65\x00\x72\x00\x74\x00\x6f\x00\x77\x00\x61\ +\x00\x6e\x00\x65\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x70\x00\x6f\ +\x00\x6c\x00\x69\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x00\x2e\ +\x00\x20\x00\x50\x00\x6f\x00\x64\x00\x61\x00\x6e\x00\x61\x00\x20\ +\x00\x77\x00\x61\x00\x72\x00\x74\x00\x6f\x01\x5b\x01\x07\x00\x20\ +\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\x00\x6d\x00\x61\x00\x78\ +\x00\x2e\x00\x20\x00\x64\x01\x42\x00\x75\x00\x67\x00\x6f\x01\x5b\ +\x00\x63\x00\x69\x01\x05\x00\x20\x00\x6b\x00\x61\x01\x7c\x00\x64\ +\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x73\x00\x65\x00\x67\x00\x6d\ +\x00\x65\x00\x6e\x00\x74\x00\x75\x00\x20\x00\x70\x00\x6f\x00\x6c\ +\x00\x69\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\x00\x2e\x00\x20\ +\x00\x4a\x00\x65\x01\x5b\x00\x6c\x00\x69\x00\x20\x00\x77\x00\x61\ +\x00\x72\x00\x74\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x77\x00\x79\ +\x00\x6e\x00\x6f\x00\x73\x00\x69\x00\x20\x00\x27\x00\x30\x00\x27\ +\x00\x2c\x00\x20\x00\x63\x00\x61\x01\x42\x00\x61\x00\x20\x00\x70\ +\x00\x6f\x00\x6c\x00\x69\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x61\ +\x00\x20\x00\x62\x01\x19\x00\x64\x00\x7a\x00\x69\x00\x65\x00\x20\ +\x00\x74\x00\x72\x00\x61\x00\x6b\x00\x74\x00\x6f\x00\x77\x00\x61\ +\x00\x6e\x00\x61\x00\x20\x00\x6a\x00\x61\x00\x6b\x00\x6f\x00\x20\ +\x00\x70\x00\x6f\x00\x6a\x00\x65\x00\x64\x00\x79\x00\x6e\x00\x63\ +\x00\x7a\x00\x79\x00\x20\x00\x73\x00\x65\x00\x67\x00\x6d\x00\x65\ +\x00\x6e\x00\x74\x00\x2e\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\xc2\x57\x68\x65\x6e\x20\x65\x78\x70\x6f\x72\x74\x69\x6e\x67\ +\x20\x73\x70\x6c\x69\x6e\x65\x73\x20\x74\x6f\x20\x44\x58\x46\x2c\ +\x20\x74\x68\x65\x79\x20\x61\x72\x65\x20\x74\x72\x61\x6e\x73\x66\ +\x6f\x72\x6d\x65\x64\x20\x69\x6e\x20\x70\x6f\x6c\x79\x6c\x69\x6e\ +\x65\x73\x2e\x20\x54\x68\x69\x73\x20\x76\x61\x6c\x75\x65\x20\x69\ +\x73\x20\x74\x68\x65\x20\x6d\x61\x78\x69\x6d\x75\x6d\x20\x6c\x65\ +\x6e\x67\x74\x68\x20\x6f\x66\x20\x65\x61\x63\x68\x20\x6f\x66\x20\ +\x74\x68\x65\x20\x70\x6f\x6c\x79\x6c\x69\x6e\x65\x20\x73\x65\x67\ +\x6d\x65\x6e\x74\x73\x2e\x20\x49\x66\x20\x30\x2c\x20\x74\x68\x65\ +\x6e\x20\x74\x68\x65\x20\x77\x68\x6f\x6c\x65\x20\x73\x70\x6c\x69\ +\x6e\x65\x20\x69\x73\x20\x74\x72\x65\x61\x74\x65\x64\x20\x61\x73\ +\x20\x61\x20\x73\x74\x72\x61\x69\x67\x68\x74\x20\x73\x65\x67\x6d\ +\x65\x6e\x74\x2e\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\ +\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\ +\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x12\x00\x58\x00\x59\ +\x00\x20\x00\x28\x00\x67\x00\xf3\x00\x72\x00\x61\x00\x29\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x08\x58\x59\x20\x28\x54\x6f\x70\x29\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x14\x00\x58\x00\x5a\x00\x20\x00\x28\ +\x00\x70\x00\x72\x00\x7a\x00\xf3\x00\x64\x00\x29\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x0a\x58\x5a\x20\x28\x46\x72\x6f\x6e\x74\x29\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x16\x00\x59\x00\x5a\x00\x20\x00\x28\ +\x00\x73\x00\x74\x00\x72\x00\x6f\x00\x6e\x00\x61\x00\x29\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x09\x59\x5a\x20\x28\x53\x69\x64\x65\ +\x29\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\ +\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x06\x00\x41\x00\x4c\x00\x54\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x03\x61\x6c\x74\x07\x00\x00\x00\ +\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\ +\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x9e\x00\x5a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\ +\x00\x7a\x00\x2c\x00\x20\x00\x6a\x00\x65\x01\x5b\x00\x6c\x00\x69\ +\x00\x20\x00\x63\x00\x68\x00\x63\x00\x65\x00\x73\x00\x7a\x00\x20\ +\x00\x75\x01\x7c\x00\x79\x01\x07\x00\x20\x00\x6a\x00\x61\x00\x6b\ +\x00\x6f\x00\x20\x00\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\ +\x00\x6e\x00\x79\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\ +\x00\x2f\x00\x73\x00\x7a\x00\x65\x00\x72\x00\x6f\x00\x6b\x00\x6f\ +\x01\x5b\x01\x07\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x69\x00\x69\ +\x00\x20\x00\x7a\x00\x20\x00\x70\x00\x61\x00\x73\x00\x6b\x00\x61\ +\x00\x20\x00\x6e\x00\x61\x00\x72\x00\x7a\x01\x19\x00\x64\x00\x7a\ +\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x4d\x63\x68\x65\x63\ +\x6b\x20\x74\x68\x69\x73\x20\x69\x66\x20\x79\x6f\x75\x20\x77\x61\ +\x6e\x74\x20\x74\x6f\x20\x75\x73\x65\x20\x74\x68\x65\x20\x63\x6f\ +\x6c\x6f\x72\x2f\x6c\x69\x6e\x65\x77\x69\x64\x74\x68\x20\x66\x72\ +\x6f\x6d\x20\x74\x68\x65\x20\x74\x6f\x6f\x6c\x62\x61\x72\x20\x61\ +\x73\x20\x64\x65\x66\x61\x75\x6c\x74\x07\x00\x00\x00\x1d\x47\x75\ +\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\ +\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x08\x00\x43\x00\x54\x00\x52\x00\x4c\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x04\x63\x74\x72\x6c\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x01\x26\x00\ +\x69\x00\x66\x00\x20\x00\x74\x00\x68\x00\x69\x00\x73\x00\x20\x00\ +\x69\x00\x73\x00\x20\x00\x63\x00\x68\x00\x65\x00\x63\x00\x6b\x00\ +\x65\x00\x64\x00\x2c\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\ +\x63\x00\x74\x00\x73\x00\x20\x00\x66\x00\x72\x00\x6f\x00\x6d\x00\ +\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x73\x00\x61\x00\x6d\x00\ +\x65\x00\x20\x00\x6c\x00\x61\x00\x79\x00\x65\x00\x72\x00\x73\x00\ +\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\x20\x00\x62\x00\x65\x00\ +\x20\x00\x6a\x00\x6f\x00\x69\x00\x6e\x00\x65\x00\x64\x00\x20\x00\ +\x69\x00\x6e\x00\x74\x00\x6f\x00\x20\x00\x44\x00\x72\x00\x61\x00\ +\x66\x00\x74\x00\x20\x00\x42\x00\x6c\x00\x6f\x00\x63\x00\x6b\x00\ +\x73\x00\x2c\x00\x20\x00\x74\x00\x75\x00\x72\x00\x6e\x00\x69\x00\ +\x6e\x00\x67\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x64\x00\ +\x69\x00\x73\x00\x70\x00\x6c\x00\x61\x00\x79\x00\x20\x00\x66\x00\ +\x61\x00\x73\x00\x74\x00\x65\x00\x72\x00\x2c\x00\x20\x00\x62\x00\ +\x75\x00\x74\x00\x20\x00\x6d\x00\x61\x00\x6b\x00\x69\x00\x6e\x00\ +\x67\x00\x20\x00\x74\x00\x68\x00\x65\x00\x6d\x00\x20\x00\x6c\x00\ +\x65\x00\x73\x00\x73\x00\x20\x00\x65\x00\x61\x00\x73\x00\x69\x00\ +\x6c\x00\x79\x00\x20\x00\x65\x00\x64\x00\x69\x00\x74\x00\x61\x00\ +\x62\x00\x6c\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x93\x69\ +\x66\x20\x74\x68\x69\x73\x20\x69\x73\x20\x63\x68\x65\x63\x6b\x65\ +\x64\x2c\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x66\x72\x6f\x6d\x20\ +\x74\x68\x65\x20\x73\x61\x6d\x65\x20\x6c\x61\x79\x65\x72\x73\x20\ +\x77\x69\x6c\x6c\x20\x62\x65\x20\x6a\x6f\x69\x6e\x65\x64\x20\x69\ +\x6e\x74\x6f\x20\x44\x72\x61\x66\x74\x20\x42\x6c\x6f\x63\x6b\x73\ +\x2c\x20\x74\x75\x72\x6e\x69\x6e\x67\x20\x74\x68\x65\x20\x64\x69\ +\x73\x70\x6c\x61\x79\x20\x66\x61\x73\x74\x65\x72\x2c\x20\x62\x75\ +\x74\x20\x6d\x61\x6b\x69\x6e\x67\x20\x74\x68\x65\x6d\x20\x6c\x65\ +\x73\x73\x20\x65\x61\x73\x69\x6c\x79\x20\x65\x64\x69\x74\x61\x62\ +\x6c\x65\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x92\x00\x4a\x00\x65\x01\x5b\ +\x00\x6c\x00\x69\x00\x20\x00\x7a\x00\x61\x00\x7a\x00\x6e\x00\x61\ +\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x6f\x00\x2c\x00\x20\x00\x7a\ +\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x6e\x01\x05\x00\x20\x00\x72\ +\x00\xf3\x00\x77\x00\x6e\x00\x69\x00\x65\x01\x7c\x00\x20\x00\x7a\ +\x00\x61\x00\x69\x00\x6d\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x6f\ +\x00\x77\x00\x61\x00\x6e\x00\x65\x00\x20\x00\x6f\x00\x62\x00\x69\ +\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x20\x00\x7a\x00\x20\x00\x6f\ +\x00\x62\x00\x73\x00\x7a\x00\x61\x00\x72\x00\x75\x00\x20\x00\x70\ +\x00\x61\x00\x70\x00\x69\x00\x65\x00\x72\x00\x75\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x3c\x69\x66\x20\x74\x68\x69\x73\x20\x69\x73\ +\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\x70\x61\x70\x65\x72\x20\ +\x73\x70\x61\x63\x65\x20\x6f\x62\x6a\x65\x63\x74\x73\x20\x77\x69\ +\x6c\x6c\x20\x62\x65\x20\x69\x6d\x70\x6f\x72\x74\x65\x64\x20\x74\ +\x6f\x6f\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\ +\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x86\x00\x6a\x00\x65\x01\x5b\ +\x00\x6c\x00\x69\x00\x20\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\ +\x00\x74\x00\x6f\x00\x20\x00\x6f\x00\x64\x00\x7a\x00\x6e\x00\x61\ +\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\x00\x2c\x00\x20\x00\x74\ +\x00\x65\x00\x6b\x00\x73\x00\x74\x00\x79\x00\x20\x00\x2f\x00\x20\ +\x00\x6d\x00\x74\x00\x65\x00\x78\x00\x74\x00\x73\x00\x20\x00\x6e\ +\x00\x69\x00\x65\x00\x20\x00\x7a\x00\x6f\x00\x73\x00\x74\x00\x61\ +\x00\x6e\x01\x05\x00\x20\x00\x7a\x00\x61\x00\x69\x00\x6d\x00\x70\ +\x00\x6f\x00\x72\x00\x74\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x65\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x34\x69\x66\x20\x74\x68\x69\ +\x73\x20\x69\x73\x20\x75\x6e\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\ +\x74\x65\x78\x74\x73\x2f\x6d\x74\x65\x78\x74\x73\x20\x77\x6f\x6e\ +\x27\x74\x20\x62\x65\x20\x69\x6d\x70\x6f\x72\x74\x65\x64\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x04\x00\x70\x00\x78\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x02\x70\x78\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\ +\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\ +\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0a\x00\x53\ +\x00\x48\x00\x49\x00\x46\x00\x54\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x05\x73\x68\x69\x66\x74\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\ +\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\ +\x69\x6e\x67\x73\x44\x72\x61\x66\x74\x01\x03\x00\x00\x00\x44\x00\ +\x64\x00\x6f\x00\x6d\x00\x79\x01\x5b\x00\x6c\x00\x6e\x00\x79\x00\ +\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\x64\x00\ +\x6c\x00\x61\x00\x20\x00\x6e\x00\x6f\x00\x77\x00\x79\x00\x63\x00\ +\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\ +\xf3\x00\x77\x08\x00\x00\x00\x00\x06\x00\x00\x00\x21\x74\x68\x65\ +\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6c\x6f\x72\x20\x66\ +\x6f\x72\x20\x6e\x65\x77\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\ +\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\x3a\ +\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x4e\x00\x44\x00\x6f\x00\x6d\x00\x79\x01\x5b\ +\x00\x6c\x00\x6e\x00\x79\x00\x20\x00\x6b\x00\x6f\x00\x6c\x00\x6f\ +\x00\x72\x00\x20\x00\x64\x00\x6c\x00\x61\x00\x20\x00\x70\x00\x72\ +\x00\x7a\x00\x79\x00\x63\x00\x69\x01\x05\x00\x67\x00\x61\x00\x6e\ +\x00\x69\x00\x61\x00\x20\x00\x73\x00\x79\x00\x6d\x00\x62\x00\x6f\ +\x00\x6c\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x22\x74\x68\ +\x65\x20\x64\x65\x66\x61\x75\x6c\x74\x20\x63\x6f\x6c\x6f\x72\x20\ +\x66\x6f\x72\x20\x73\x6e\x61\x70\x20\x73\x79\x6d\x62\x6f\x6c\x73\ +\x07\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\ +\x3a\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x58\x00\x44\x00\x6f\x00\x6d\x00\x79\ +\x01\x5b\x00\x6c\x00\x6e\x00\x61\x00\x20\x00\x73\x00\x7a\x00\x65\ +\x00\x72\x00\x6f\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x6c\ +\x00\x69\x00\x6e\x00\x69\x00\x69\x00\x20\x00\x64\x00\x6c\x00\x61\ +\x00\x20\x00\x6e\x00\x6f\x00\x77\x00\x79\x00\x63\x00\x68\x00\x20\ +\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\xf3\x00\x77\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x25\x74\x68\x65\x20\x64\x65\ +\x66\x61\x75\x6c\x74\x20\x6c\x69\x6e\x65\x77\x69\x64\x74\x68\x20\ +\x66\x6f\x72\x20\x6e\x65\x77\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\ +\x00\x00\x00\x1d\x47\x75\x69\x3a\x3a\x44\x69\x61\x6c\x6f\x67\x3a\ +\x3a\x44\x6c\x67\x53\x65\x74\x74\x69\x6e\x67\x73\x44\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x0e\x00\x5a\x00\x61\x00\x6d\x00\x6b\x00\ +\x6e\x00\x69\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06\x26\ +\x43\x6c\x6f\x73\x65\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x24\x00\x5a\x00\x61\x00\x6d\x00\x6b\x00\x6e\x00\ +\x69\x01\x19\x00\x74\x00\x6f\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\ +\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x09\x26\x43\x6f\x6e\x74\x69\x6e\x75\x65\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0c\x00\x4b\x00\x6f\ +\x00\x70\x00\x69\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x05\x26\x43\x6f\x70\x79\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x10\x00\x26\x00\x5a\x00\x61\x00\x6b\x00\ +\x6f\x01\x44\x00\x63\x00\x7a\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x07\x26\x46\x69\x6e\x69\x73\x68\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x22\x00\x26\x00\x4f\x00\x43\x00\x43\ +\x00\x2d\x00\x73\x00\x74\x00\x79\x00\x6c\x00\x65\x00\x20\x00\x6f\ +\x00\x66\x00\x66\x00\x73\x00\x65\x00\x74\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x11\x26\x4f\x43\x43\x2d\x73\x74\x79\x6c\x65\x20\x6f\ +\x66\x66\x73\x65\x74\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x12\x00\x26\x00\x52\x00\x65\x00\x6c\x00\x61\x00\ +\x74\x00\x69\x00\x76\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x09\x26\x52\x65\x6c\x61\x74\x69\x76\x65\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0c\x00\x43\x00\x6f\x00\x66\ +\x00\x6e\x00\x69\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\ +\x26\x55\x6e\x64\x6f\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x0c\x00\x26\x00\x57\x00\x79\x00\x6d\x00\x61\x01\ +\x7c\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05\x26\x57\x69\x70\x65\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3a\ +\x00\x41\x00\x6b\x00\x74\x00\x79\x00\x77\x00\x6e\x00\x65\x00\x20\ +\x00\x70\x00\x6f\x00\x6c\x00\x65\x00\x63\x00\x65\x00\x6e\x00\x69\ +\x00\x65\x00\x20\x00\x6b\x00\x72\x00\x65\x01\x5b\x00\x6c\x00\x61\ +\x00\x72\x00\x73\x00\x6b\x00\x69\x00\x65\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x14\x41\x63\x74\x69\x76\x65\x20\x44\x72\x61\x66\x74\ +\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x6c\x00\x41\x00\x6b\x00\x74\x00\x79\ +\x00\x77\x00\x6e\x00\x79\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\ +\x00\x6b\x00\x74\x00\x20\x00\x6d\x00\x75\x00\x73\x00\x69\x00\x20\ +\x00\x70\x00\x6f\x00\x73\x00\x69\x00\x61\x00\x64\x00\x61\x01\x07\ +\x00\x20\x00\x77\x00\x69\x01\x19\x00\x63\x00\x65\x00\x6a\x00\x20\ +\x00\x6e\x00\x69\x01\x7c\x00\x20\x00\x32\x00\x20\x00\x70\x00\x75\ +\x00\x6e\x00\x6b\x00\x74\x00\x79\x00\x2f\x00\x77\x01\x19\x00\x7a\ +\x01\x42\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\x33\x41\x63\ +\x74\x69\x76\x65\x20\x6f\x62\x6a\x65\x63\x74\x20\x6d\x75\x73\x74\ +\x20\x68\x61\x76\x65\x20\x6d\x6f\x72\x65\x20\x74\x68\x61\x6e\x20\ +\x74\x77\x6f\x20\x70\x6f\x69\x6e\x74\x73\x2f\x6e\x6f\x64\x65\x73\ +\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x42\x00\x44\x00\x6f\x00\x64\x00\x61\x00\x6a\x00\x20\x00\x70\x00\ +\x75\x00\x6e\x00\x6b\x00\x74\x00\x79\x00\x20\x00\x64\x00\x6f\x00\ +\x20\x00\x61\x00\x6b\x00\x74\x00\x79\x00\x77\x00\x6e\x00\x65\x00\ +\x67\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\ +\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x20\x41\x64\x64\ +\x20\x70\x6f\x69\x6e\x74\x73\x20\x74\x6f\x20\x74\x68\x65\x20\x63\ +\x75\x72\x72\x65\x6e\x74\x20\x6f\x62\x6a\x65\x63\x74\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x10\x00\x41\x00\ +\x70\x00\x65\x00\x72\x00\x74\x00\x75\x00\x72\x00\x65\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x08\x41\x70\x65\x72\x74\x75\x72\x65\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x20\x00\ +\x41\x00\x70\x00\x65\x00\x72\x00\x74\x00\x75\x00\x72\x00\x65\x00\ +\x20\x00\x61\x00\x6e\x00\x67\x00\x6c\x00\x65\x00\x3a\x00\x0a\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x10\x41\x70\x65\x72\x74\x75\x72\ +\x65\x20\x61\x6e\x67\x6c\x65\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x3c\x00\x5a\x00\x61\x00\x73\x00\ +\x74\x00\x6f\x00\x73\x00\x75\x00\x6a\x00\x20\x00\x64\x00\x6f\x00\ +\x20\x00\x77\x00\x79\x00\x62\x00\x72\x00\x61\x00\x6e\x00\x79\x00\ +\x63\x00\x68\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\ +\x74\x00\xf3\x00\x77\x08\x00\x00\x00\x00\x06\x00\x00\x00\x19\x41\ +\x70\x70\x6c\x79\x20\x74\x6f\x20\x73\x65\x6c\x65\x63\x74\x65\x64\ +\x20\x6f\x62\x6a\x65\x63\x74\x73\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x06\x01\x41\x00\x75\x00\x6b\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x03\x41\x72\x63\x07\x00\x00\x00\x05\ +\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x46\x00\x4e\x00\x69\x00\ +\x65\x00\x20\x00\x6d\x00\x6f\x01\x7c\x00\x6e\x00\x61\x00\x20\x00\ +\x6f\x00\x64\x00\x73\x00\x75\x00\x6e\x01\x05\x01\x07\x00\x20\x00\ +\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x75\x00\x20\x00\ +\x74\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x74\x00\x79\x00\x70\x00\ +\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1f\x43\x61\x6e\x6e\x6f\ +\x74\x20\x6f\x66\x66\x73\x65\x74\x20\x74\x68\x69\x73\x20\x6f\x62\ +\x6a\x65\x63\x74\x20\x74\x79\x70\x65\x0a\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x10\x01\x5a\x00\x72\x00\x6f\ +\x00\x64\x00\x65\x00\x6b\x00\x20\x00\x58\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x08\x43\x65\x6e\x74\x65\x72\x20\x58\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x18\x00\x5a\x00\x6d\ +\x00\x69\x00\x61\x00\x6e\x00\x61\x00\x20\x00\x53\x00\x74\x00\x79\ +\x00\x6c\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c\x43\x68\ +\x61\x6e\x67\x65\x20\x53\x74\x79\x6c\x65\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\xb6\x00\x43\x00\x68\x00\x65\ +\x00\x63\x00\x6b\x00\x20\x00\x74\x00\x68\x00\x69\x00\x73\x00\x20\ +\x00\x69\x00\x66\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x6f\ +\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\x20\x00\x73\x00\x68\ +\x00\x6f\x00\x75\x00\x6c\x00\x64\x00\x20\x00\x61\x00\x70\x00\x70\ +\x00\x65\x00\x61\x00\x72\x00\x20\x00\x61\x00\x73\x00\x20\x00\x66\ +\x00\x69\x00\x6c\x00\x6c\x00\x65\x00\x64\x00\x2c\x00\x20\x00\x6f\ +\x00\x74\x00\x68\x00\x65\x00\x72\x00\x77\x00\x69\x00\x73\x00\x65\ +\x00\x20\x00\x69\x00\x74\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\ +\x00\x20\x00\x61\x00\x70\x00\x70\x00\x65\x00\x61\x00\x72\x00\x20\ +\x00\x61\x00\x73\x00\x20\x00\x77\x00\x69\x00\x72\x00\x65\x00\x66\ +\x00\x72\x00\x61\x00\x6d\x00\x65\x00\x20\x00\x28\x00\x69\x00\x29\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x5b\x43\x68\x65\x63\x6b\x20\ +\x74\x68\x69\x73\x20\x69\x66\x20\x74\x68\x65\x20\x6f\x62\x6a\x65\ +\x63\x74\x20\x73\x68\x6f\x75\x6c\x64\x20\x61\x70\x70\x65\x61\x72\ +\x20\x61\x73\x20\x66\x69\x6c\x6c\x65\x64\x2c\x20\x6f\x74\x68\x65\ +\x72\x77\x69\x73\x65\x20\x69\x74\x20\x77\x69\x6c\x6c\x20\x61\x70\ +\x70\x65\x61\x72\x20\x61\x73\x20\x77\x69\x72\x65\x66\x72\x61\x6d\ +\x65\x20\x28\x69\x29\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x0a\x00\x4f\x00\x6b\x00\x72\x01\x05\x00\x67\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x06\x43\x69\x72\x63\x6c\x65\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x8a\x00\ +\x57\x00\x73\x00\x70\x00\xf3\x01\x42\x00\x72\x00\x7a\x01\x19\x00\ +\x64\x00\x6e\x00\x65\x00\x20\x00\x77\x00\x20\x00\x73\x00\x74\x00\ +\x6f\x00\x73\x00\x75\x00\x6e\x00\x6b\x00\x75\x00\x20\x00\x64\x00\ +\x6f\x00\x20\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x74\x00\x6e\x00\ +\x69\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x70\x00\x75\x00\x6e\x00\ +\x6b\x00\x74\x00\x75\x00\x20\x00\x6c\x00\x75\x00\x62\x00\x20\x00\ +\x62\x00\x65\x00\x7a\x00\x77\x00\x7a\x00\x67\x00\x6c\x01\x19\x00\ +\x64\x00\x6e\x00\x65\x00\x6a\x00\x20\x00\x28\x00\x53\x00\x50\x00\ +\x41\x00\x43\x00\x4a\x00\x41\x00\x29\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x36\x43\x6f\x6f\x72\x64\x69\x6e\x61\x74\x65\x73\x20\x72\ +\x65\x6c\x61\x74\x69\x76\x65\x20\x74\x6f\x20\x6c\x61\x73\x74\x20\ +\x70\x6f\x69\x6e\x74\x20\x6f\x72\x20\x61\x62\x73\x6f\x6c\x75\x74\ +\x65\x20\x28\x53\x50\x41\x43\x45\x29\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x0c\x00\x4b\x00\x6f\x00\x70\x00\ +\x69\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04\x43\ +\x6f\x70\x79\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x14\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\x00\ +\x20\x01\x41\x00\x75\x00\x6b\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x0a\x43\x72\x65\x61\x74\x65\x20\x41\x72\x63\x07\x00\x00\x00\x05\ +\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1e\x00\x55\x00\x74\x00\ +\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\x42\x00\x2d\x00\x53\x00\ +\x70\x00\x6c\x00\x61\x00\x6a\x00\x6e\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x0e\x43\x72\x65\x61\x74\x65\x20\x42\x53\x70\x6c\x69\x6e\ +\x65\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x18\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\ +\x4f\x00\x6b\x00\x72\x01\x05\x00\x67\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x0d\x43\x72\x65\x61\x74\x65\x20\x43\x69\x72\x63\x6c\x65\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x26\ +\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\x57\ +\x00\x79\x00\x6d\x00\x69\x00\x61\x00\x72\x00\x6f\x00\x77\x00\x61\ +\x00\x6e\x00\x69\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\ +\x43\x72\x65\x61\x74\x65\x20\x44\x69\x6d\x65\x6e\x73\x69\x6f\x6e\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1e\ +\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\x57\ +\x00\x69\x00\x65\x00\x6c\x00\x6f\x00\x6b\x01\x05\x00\x74\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0e\x43\x72\x65\x61\x74\x65\x20\x50\ +\x6f\x6c\x79\x67\x6f\x6e\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x20\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\ +\x00\x7a\x00\x20\x00\x50\x00\x72\x00\x6f\x00\x73\x00\x74\x00\x6f\ +\x00\x6b\x01\x05\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\ +\x43\x72\x65\x61\x74\x65\x20\x52\x65\x63\x74\x61\x6e\x67\x6c\x65\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x18\ +\x00\x55\x00\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\x54\ +\x00\x65\x00\x6b\x00\x73\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x0b\x43\x72\x65\x61\x74\x65\x20\x54\x65\x78\x74\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1e\x00\x55\x00\ +\x74\x00\x77\x00\xf3\x00\x72\x00\x7a\x00\x20\x00\x53\x00\x7a\x00\ +\x6b\x00\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x0b\x43\x72\x65\x61\x74\x65\x20\x57\x69\x72\x65\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x24\ +\x00\x44\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x65\x00\x20\x00\x4d\ +\x00\x65\x00\x61\x00\x73\x00\x75\x00\x72\x00\x65\x00\x6d\x00\x65\ +\x00\x6e\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\x12\x44\x65\ +\x6c\x65\x74\x65\x20\x4d\x65\x61\x73\x75\x72\x65\x6d\x65\x6e\x74\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x1e\ +\x00\x44\x00\x69\x00\x73\x00\x70\x00\x6c\x00\x61\x00\x79\x00\x20\ +\x00\x6f\x00\x70\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x73\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0f\x44\x69\x73\x70\x6c\x61\x79\x20\ +\x6f\x70\x74\x69\x6f\x6e\x73\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x12\x00\x4f\x00\x64\x00\x6c\x00\x65\x00\ +\x67\x01\x42\x00\x6f\x01\x5b\x01\x07\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x08\x44\x69\x73\x74\x61\x6e\x63\x65\x07\x00\x00\x00\x05\ +\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x52\x00\x4e\x00\x69\x00\ +\x65\x00\x20\x00\x72\x00\x7a\x00\x75\x00\x74\x00\x75\x00\x6a\x00\ +\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\xf3\x00\x77\x00\ +\x20\x00\x6e\x00\x61\x00\x20\x00\x70\x01\x42\x00\x61\x00\x73\x00\ +\x7a\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\x6e\x01\x19\x00\x20\x00\ +\x72\x00\x79\x00\x73\x00\x75\x00\x6e\x00\x6b\x00\x75\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x28\x44\x6f\x20\x6e\x6f\x74\x20\x70\x72\ +\x6f\x6a\x65\x63\x74\x20\x70\x6f\x69\x6e\x74\x73\x20\x74\x6f\x20\ +\x61\x20\x64\x72\x61\x77\x69\x6e\x67\x20\x70\x6c\x61\x6e\x65\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0a\x00\ +\x44\x00\x72\x00\x61\x00\x66\x00\x74\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x05\x44\x72\x61\x66\x74\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x16\x00\x44\x00\x72\x00\x61\x00\x66\ +\x00\x74\x00\x20\x00\x74\x00\x6f\x00\x6f\x00\x6c\x00\x73\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0b\x44\x72\x61\x66\x74\x20\x74\x6f\ +\x6f\x6c\x73\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x3a\x00\x4b\x00\x72\x00\x61\x00\x77\x01\x19\x00\x64\x00\ +\x7a\x00\x69\x00\x65\x00\x20\x00\x6e\x00\x69\x00\x65\x00\x20\x00\ +\x70\x00\x72\x00\x7a\x00\x65\x00\x63\x00\x69\x00\x6e\x00\x61\x00\ +\x6a\x01\x05\x00\x20\x00\x73\x00\x69\x01\x19\x00\x21\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x17\x45\x64\x67\x65\x73\x20\x64\x6f\x6e\ +\x27\x74\x20\x69\x6e\x74\x65\x72\x73\x65\x63\x74\x21\x0a\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0c\x00\x45\ +\x00\x64\x00\x79\x00\x74\x00\x75\x00\x6a\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x04\x45\x64\x69\x74\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x16\x00\x57\x00\x26\x00\x79\x00\x70\ +\x00\x65\x01\x42\x00\x6e\x00\x69\x00\x6f\x00\x6e\x00\x65\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x07\x46\x26\x69\x6c\x6c\x65\x64\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x22\x00\ +\x4b\x00\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\x70\x00\x6f\x00\ +\x77\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x63\x00\x68\x00\x6e\x00\ +\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0a\x46\x61\x63\x65\x20\ +\x43\x6f\x6c\x6f\x72\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x46\x00\x5a\x00\x61\x00\x6b\x00\x61\x01\x44\x00\ +\x63\x00\x7a\x00\x61\x00\x20\x00\x69\x00\x20\x00\x7a\x00\x61\x00\ +\x6d\x00\x79\x00\x6b\x00\x61\x00\x20\x00\x62\x00\x69\x00\x65\x01\ +\x7c\x01\x05\x00\x63\x01\x05\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\ +\x69\x01\x19\x00\x20\x00\x28\x00\x43\x00\x29\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x28\x46\x69\x6e\x69\x73\x68\x65\x73\x20\x61\x6e\ +\x64\x20\x63\x6c\x6f\x73\x65\x73\x20\x74\x68\x65\x20\x63\x75\x72\ +\x72\x65\x6e\x74\x20\x6c\x69\x6e\x65\x20\x28\x43\x29\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x6a\x00\x46\x00\ +\x69\x00\x6e\x00\x69\x00\x73\x00\x68\x00\x65\x00\x73\x00\x20\x00\ +\x74\x00\x68\x00\x65\x00\x20\x00\x63\x00\x75\x00\x72\x00\x72\x00\ +\x65\x00\x6e\x00\x74\x00\x20\x00\x64\x00\x72\x00\x61\x00\x77\x00\ +\x69\x00\x6e\x00\x67\x00\x20\x00\x6f\x00\x72\x00\x20\x00\x65\x00\ +\x64\x00\x69\x00\x74\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x6f\x00\ +\x70\x00\x65\x00\x72\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\ +\x20\x00\x28\x00\x46\x00\x29\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x35\x46\x69\x6e\x69\x73\x68\x65\x73\x20\x74\x68\x65\x20\x63\x75\ +\x72\x72\x65\x6e\x74\x20\x64\x72\x61\x77\x69\x6e\x67\x20\x6f\x72\ +\x20\x65\x64\x69\x74\x69\x6e\x67\x20\x6f\x70\x65\x72\x61\x74\x69\ +\x6f\x6e\x20\x28\x46\x29\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x20\x00\x52\x00\x6f\x00\x7a\x00\x6d\x00\x69\ +\x00\x61\x00\x72\x00\x20\x00\x43\x00\x7a\x00\x63\x00\x69\x00\x6f\ +\x00\x6e\x00\x6b\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09\ +\x46\x6f\x6e\x74\x20\x53\x69\x7a\x65\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x6c\x00\x5a\x00\x6e\x00\x61\x00\ +\x6c\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\ +\x31\x00\x20\x00\x7a\x00\x61\x00\x6d\x00\x6b\x00\x6e\x00\x69\x01\ +\x19\x00\x74\x00\x79\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x20\x00\x53\x00\x7a\x00\x6b\x00\x69\x00\x63\x00\ +\x3a\x00\x20\x00\x74\x00\x77\x00\x6f\x00\x72\x00\x7a\x00\x65\x00\ +\x6e\x00\x69\x00\x65\x00\x20\x00\x66\x00\x61\x00\x73\x00\x65\x00\ +\x74\x00\x6b\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x34\x46\ +\x6f\x75\x6e\x64\x20\x31\x20\x63\x6c\x6f\x73\x65\x64\x20\x73\x6b\ +\x65\x74\x63\x68\x20\x6f\x62\x6a\x65\x63\x74\x3a\x20\x6d\x61\x6b\ +\x69\x6e\x67\x20\x61\x20\x66\x61\x63\x65\x20\x66\x72\x6f\x6d\x20\ +\x69\x74\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x54\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\x00\ +\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x31\x00\x20\x00\x66\x00\ +\x61\x00\x73\x00\x65\x00\x74\x00\x6b\x01\x19\x00\x3a\x00\x20\x00\ +\x65\x00\x6b\x00\x73\x00\x74\x00\x72\x00\x61\x00\x6b\x00\x63\x00\ +\x6a\x00\x61\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\x69\x00\x65\x00\ +\x6c\x00\x65\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x23\x46\x6f\x75\x6e\x64\x20\x31\x20\x66\x61\x63\x65\x3a\x20\x65\ +\x78\x74\x72\x61\x63\x74\x69\x6e\x67\x20\x69\x74\x73\x20\x77\x69\ +\x72\x65\x73\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x62\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\ +\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x31\x00\x20\x00\x6f\ +\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x6e\x00\x69\ +\x00\x65\x00\x70\x00\x61\x00\x72\x00\x61\x00\x6d\x00\x65\x00\x74\ +\x00\x72\x00\x79\x00\x63\x00\x7a\x00\x6e\x00\x79\x00\x3a\x00\x20\ +\x00\x64\x00\x72\x00\x61\x00\x66\x00\x74\x00\x79\x00\x66\x00\x79\ +\x00\x69\x00\x6e\x00\x67\x08\x00\x00\x00\x00\x06\x00\x00\x00\x2f\ +\x46\x6f\x75\x6e\x64\x20\x31\x20\x6e\x6f\x6e\x2d\x70\x61\x72\x61\ +\x6d\x65\x74\x72\x69\x63\x20\x6f\x62\x6a\x65\x63\x74\x73\x3a\x20\ +\x64\x72\x61\x66\x74\x69\x66\x79\x69\x6e\x67\x20\x69\x74\x0a\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x50\x00\ +\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\ +\x6e\x00\x6f\x00\x20\x00\x31\x00\x20\x00\x6f\x00\x74\x00\x77\x00\ +\x61\x00\x72\x00\x74\x00\x79\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\ +\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x00\x3a\x00\x20\x00\x7a\x00\ +\x61\x00\x6d\x00\x79\x00\x6b\x00\x61\x00\x6e\x00\x69\x00\x65\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x1e\x46\x6f\x75\x6e\x64\x20\x31\ +\x20\x6f\x70\x65\x6e\x20\x77\x69\x72\x65\x3a\x20\x63\x6c\x6f\x73\ +\x69\x6e\x67\x20\x69\x74\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x6e\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\ +\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x31\x00\ +\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\x00\ +\x70\x00\x61\x00\x72\x00\x61\x00\x6d\x00\x65\x00\x74\x00\x72\x00\ +\x79\x00\x63\x00\x7a\x00\x6e\x00\x79\x00\x3a\x00\x20\x00\x6b\x00\ +\x61\x00\x73\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x65\x00\ +\x20\x00\x7a\x00\x61\x00\x6c\x00\x65\x01\x7c\x00\x6e\x00\x6f\x01\ +\x5b\x00\x63\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x35\x46\ +\x6f\x75\x6e\x64\x20\x31\x20\x70\x61\x72\x61\x6d\x65\x74\x72\x69\ +\x63\x20\x6f\x62\x6a\x65\x63\x74\x3a\x20\x62\x72\x65\x61\x6b\x69\ +\x6e\x67\x20\x69\x74\x73\x20\x64\x65\x70\x65\x6e\x64\x65\x6e\x63\ +\x69\x65\x73\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x5a\x00\x46\x00\x6f\x00\x75\x00\x6e\x00\x64\x00\x20\ +\x00\x31\x00\x20\x00\x73\x00\x6f\x00\x6c\x00\x69\x00\x64\x00\x69\ +\x00\x66\x00\x69\x00\x63\x00\x61\x00\x62\x00\x6c\x00\x65\x00\x20\ +\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\x63\x00\x74\x00\x3a\x00\x20\ +\x00\x73\x00\x6f\x00\x6c\x00\x69\x00\x64\x00\x69\x00\x66\x00\x79\ +\x00\x69\x00\x6e\x00\x67\x00\x20\x00\x69\x00\x74\x00\x0a\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x2d\x46\x6f\x75\x6e\x64\x20\x31\x20\ +\x73\x6f\x6c\x69\x64\x69\x66\x69\x63\x61\x62\x6c\x65\x20\x6f\x62\ +\x6a\x65\x63\x74\x3a\x20\x73\x6f\x6c\x69\x64\x69\x66\x79\x69\x6e\ +\x67\x20\x69\x74\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x4e\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\ +\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x32\x00\x20\x00\ +\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x3a\x00\ +\x20\x00\x7a\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x6e\x01\x05\x00\ +\x20\x00\x70\x00\x6f\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x6f\x00\ +\x6e\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1d\x46\x6f\x75\ +\x6e\x64\x20\x32\x20\x6f\x62\x6a\x65\x63\x74\x73\x3a\x20\x66\x75\ +\x73\x69\x6e\x67\x20\x74\x68\x65\x6d\x0a\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x42\x00\x5a\x00\x6e\x00\x61\ +\x00\x6c\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\ +\x00\x32\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\ +\x00\x79\x00\x3a\x00\x20\x00\x6f\x00\x64\x00\x65\x00\x6a\x00\x6d\ +\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x65\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x22\x46\x6f\x75\x6e\x64\x20\x32\x20\x6f\x62\ +\x6a\x65\x63\x74\x73\x3a\x20\x73\x75\x62\x74\x72\x61\x63\x74\x69\ +\x6e\x67\x20\x74\x68\x65\x6d\x0a\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x62\x00\x5a\x00\x6e\x00\x61\x00\x6c\ +\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x7a\ +\x00\x61\x00\x6d\x00\x6b\x00\x6e\x00\x69\x01\x19\x00\x74\x00\x65\ +\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\x69\x00\x65\x00\x6c\x00\x65\ +\x00\x74\x00\x79\x00\x3a\x00\x20\x00\x74\x00\x77\x00\x6f\x00\x72\ +\x00\x7a\x00\x65\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x66\x00\x61\ +\x00\x73\x00\x65\x00\x74\x00\x65\x00\x6b\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x21\x46\x6f\x75\x6e\x64\x20\x63\x6c\x6f\x73\x65\x64\ +\x20\x77\x69\x72\x65\x73\x3a\x20\x6d\x61\x6b\x69\x6e\x67\x20\x66\ +\x61\x63\x65\x73\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x74\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\ +\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x67\x00\x72\x00\ +\x75\x00\x70\x00\x79\x00\x3a\x00\x20\x00\x7a\x00\x61\x00\x6d\x00\ +\x79\x00\x6b\x00\x61\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x6b\x00\ +\x61\x01\x7c\x00\x64\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x6f\x00\ +\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x75\x00\x20\x00\x77\x00\ +\x65\x00\x77\x00\x6e\x01\x05\x00\x74\x00\x72\x00\x7a\x00\x20\x00\ +\x67\x00\x72\x00\x75\x00\x70\x00\x79\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x2e\x46\x6f\x75\x6e\x64\x20\x67\x72\x6f\x75\x70\x73\x3a\ +\x20\x63\x6c\x6f\x73\x69\x6e\x67\x20\x65\x61\x63\x68\x20\x6f\x70\ +\x65\x6e\x20\x6f\x62\x6a\x65\x63\x74\x20\x69\x6e\x73\x69\x64\x65\ +\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x5e\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\x00\x69\x00\ +\x6f\x00\x6e\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x79\x00\x20\x00\x7a\x00\x61\x00\x77\x00\x69\x00\ +\x65\x00\x72\x00\x61\x00\x6a\x01\x05\x00\x63\x00\x65\x00\x20\x00\ +\x6b\x00\x72\x00\x7a\x00\x79\x00\x77\x00\x65\x00\x3a\x00\x20\x01\ +\x42\x01\x05\x00\x63\x00\x7a\x00\x65\x00\x6e\x00\x69\x00\x65\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x2d\x46\x6f\x75\x6e\x64\x20\x6f\ +\x62\x6a\x65\x63\x74\x73\x20\x63\x6f\x6e\x74\x61\x69\x6e\x69\x6e\ +\x67\x20\x63\x75\x72\x76\x65\x73\x3a\x20\x66\x75\x73\x69\x6e\x67\ +\x20\x74\x68\x65\x6d\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x64\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\ +\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x77\x00\x79\ +\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x6e\x00\x69\x00\x65\x00\x20\ +\x00\x73\x00\x7a\x00\x6b\x00\x69\x00\x65\x00\x6c\x00\x65\x00\x74\ +\x00\x3a\x00\x20\x00\x65\x00\x6b\x00\x73\x00\x74\x00\x72\x00\x61\ +\x00\x6b\x00\x63\x00\x6a\x00\x61\x00\x20\x00\x6b\x00\x72\x00\x61\ +\x00\x77\x01\x19\x00\x64\x00\x7a\x00\x69\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x29\x46\x6f\x75\x6e\x64\x20\x6f\x6e\x6c\x79\x20\x77\ +\x69\x72\x65\x73\x3a\x20\x65\x78\x74\x72\x61\x63\x74\x69\x6e\x67\ +\x20\x74\x68\x65\x69\x72\x20\x65\x64\x67\x65\x73\x0a\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x5c\x00\x5a\x00\ +\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\ +\x6f\x00\x20\x00\x6b\x00\x69\x00\x6c\x00\x6b\x00\x61\x00\x20\x00\ +\x6b\x00\x72\x00\x61\x00\x77\x01\x19\x00\x64\x00\x7a\x00\x69\x00\ +\x3a\x00\x20\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x65\x00\x6e\x00\ +\x69\x00\x65\x00\x20\x00\x77\x00\x20\x00\x73\x00\x7a\x00\x6b\x00\ +\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x21\x46\x6f\x75\x6e\x64\x20\x73\x65\x76\x65\x72\x61\x6c\ +\x20\x65\x64\x67\x65\x73\x3a\x20\x77\x69\x72\x69\x6e\x67\x20\x74\ +\x68\x65\x6d\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x4a\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\ +\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x6b\x00\x69\x00\x6c\ +\x00\x6b\x00\x20\x00\x66\x00\x61\x00\x73\x00\x65\x00\x74\x00\x65\ +\x00\x6b\x00\x3a\x00\x20\x00\x72\x00\x6f\x00\x7a\x00\x64\x00\x7a\ +\x00\x69\x00\x65\x00\x6c\x00\x61\x00\x6e\x00\x69\x00\x65\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x24\x46\x6f\x75\x6e\x64\x20\x73\x65\ +\x76\x65\x72\x61\x6c\x20\x66\x61\x63\x65\x73\x3a\x20\x73\x70\x6c\ +\x69\x74\x74\x69\x6e\x67\x20\x74\x68\x65\x6d\x0a\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x66\x00\x46\x00\x6f\ +\x00\x75\x00\x6e\x00\x64\x00\x20\x00\x73\x00\x65\x00\x76\x00\x65\ +\x00\x72\x00\x61\x00\x6c\x00\x20\x00\x6e\x00\x6f\x00\x6e\x00\x2d\ +\x00\x63\x00\x6f\x00\x6e\x00\x6e\x00\x65\x00\x63\x00\x74\x00\x65\ +\x00\x64\x00\x20\x00\x65\x00\x64\x00\x67\x00\x65\x00\x73\x00\x3a\ +\x00\x20\x00\x6d\x00\x61\x00\x6b\x00\x69\x00\x6e\x00\x67\x00\x20\ +\x00\x63\x00\x6f\x00\x6d\x00\x70\x00\x6f\x00\x75\x00\x6e\x00\x64\ +\x00\x0a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x33\x46\x6f\x75\x6e\ +\x64\x20\x73\x65\x76\x65\x72\x61\x6c\x20\x6e\x6f\x6e\x2d\x63\x6f\ +\x6e\x6e\x65\x63\x74\x65\x64\x20\x65\x64\x67\x65\x73\x3a\x20\x6d\ +\x61\x6b\x69\x6e\x67\x20\x63\x6f\x6d\x70\x6f\x75\x6e\x64\x0a\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x6a\x00\ +\x46\x00\x6f\x00\x75\x00\x6e\x00\x64\x00\x20\x00\x73\x00\x65\x00\ +\x76\x00\x65\x00\x72\x00\x61\x00\x6c\x00\x20\x00\x6e\x00\x6f\x00\ +\x6e\x00\x2d\x00\x74\x00\x72\x00\x65\x00\x61\x00\x74\x00\x61\x00\ +\x62\x00\x6c\x00\x65\x00\x20\x00\x6f\x00\x62\x00\x6a\x00\x65\x00\ +\x63\x00\x74\x00\x73\x00\x3a\x00\x20\x00\x6d\x00\x61\x00\x6b\x00\ +\x69\x00\x6e\x00\x67\x00\x20\x00\x63\x00\x6f\x00\x6d\x00\x70\x00\ +\x6f\x00\x75\x00\x6e\x00\x64\x00\x0a\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x35\x46\x6f\x75\x6e\x64\x20\x73\x65\x76\x65\x72\x61\x6c\ +\x20\x6e\x6f\x6e\x2d\x74\x72\x65\x61\x74\x61\x62\x6c\x65\x20\x6f\ +\x62\x6a\x65\x63\x74\x73\x3a\x20\x6d\x61\x6b\x69\x6e\x67\x20\x63\ +\x6f\x6d\x70\x6f\x75\x6e\x64\x0a\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x80\x00\x5a\x00\x6e\x00\x61\x00\x6c\ +\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\x20\x00\x6f\ +\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\x20\x00\x6c\ +\x00\x75\x00\x62\x00\x20\x00\x66\x00\x61\x00\x73\x00\x65\x00\x74\ +\x00\x6b\x00\x69\x00\x3a\x00\x20\x00\x74\x00\x77\x00\x6f\x00\x72\ +\x00\x7a\x00\x65\x00\x6e\x00\x69\x00\x65\x00\x20\x00\x66\x00\x61\ +\x00\x73\x00\x65\x00\x74\x00\x6b\x00\x69\x00\x20\x00\x70\x00\x61\ +\x00\x72\x00\x61\x00\x6d\x00\x65\x00\x74\x00\x72\x00\x79\x00\x63\ +\x00\x7a\x00\x6e\x00\x65\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x39\x46\x6f\x75\x6e\x64\x20\x73\x65\x76\x65\x72\x61\x6c\x20\ +\x6f\x62\x6a\x65\x63\x74\x73\x20\x6f\x72\x20\x66\x61\x63\x65\x73\ +\x3a\x20\x6d\x61\x6b\x69\x6e\x67\x20\x61\x20\x70\x61\x72\x61\x6d\ +\x65\x74\x72\x69\x63\x20\x66\x61\x63\x65\x0a\x07\x00\x00\x00\x05\ +\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x38\x00\x5a\x00\x6e\x00\ +\x61\x00\x6c\x00\x65\x00\x7a\x00\x69\x00\x6f\x00\x6e\x00\x6f\x00\ +\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x79\x00\ +\x3a\x00\x20\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x65\x00\x6e\x00\ +\x69\x00\x65\x08\x00\x00\x00\x00\x06\x00\x00\x00\x23\x46\x6f\x75\ +\x6e\x64\x20\x73\x65\x76\x65\x72\x61\x6c\x20\x6f\x62\x6a\x65\x63\ +\x74\x73\x3a\x20\x66\x75\x73\x69\x6e\x67\x20\x74\x68\x65\x6d\x0a\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x72\ +\x00\x5a\x00\x6e\x00\x61\x00\x6c\x00\x65\x00\x7a\x00\x69\x00\x6f\ +\x00\x6e\x00\x6f\x00\x20\x00\x6b\x00\x69\x00\x6c\x00\x6b\x00\x61\ +\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\xf3\ +\x00\x77\x00\x3a\x00\x20\x00\x6f\x00\x64\x00\x65\x00\x6a\x00\x6d\ +\x00\x75\x00\x6a\x01\x19\x00\x20\x00\x6f\x00\x64\x00\x20\x00\x70\ +\x00\x69\x00\x65\x00\x72\x00\x77\x00\x73\x00\x7a\x00\x65\x00\x67\ +\x00\x6f\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\ +\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x3b\x46\x6f\x75\x6e\ +\x64\x20\x73\x65\x76\x65\x72\x61\x6c\x20\x6f\x62\x6a\x65\x63\x74\ +\x73\x3a\x20\x73\x75\x62\x74\x72\x61\x63\x74\x69\x6e\x67\x20\x74\ +\x68\x65\x6d\x20\x66\x72\x6f\x6d\x20\x74\x68\x65\x20\x66\x69\x72\ +\x73\x74\x20\x6f\x6e\x65\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x9e\x00\x49\x00\x66\x00\x20\x00\x63\x00\ +\x68\x00\x65\x00\x63\x00\x6b\x00\x65\x00\x64\x00\x2c\x00\x20\x00\ +\x61\x00\x6e\x00\x20\x00\x4f\x00\x43\x00\x43\x00\x2d\x00\x73\x00\ +\x74\x00\x79\x00\x6c\x00\x65\x00\x20\x00\x6f\x00\x66\x00\x66\x00\ +\x73\x00\x65\x00\x74\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\ +\x20\x00\x62\x00\x65\x00\x20\x00\x70\x00\x65\x00\x72\x00\x66\x00\ +\x6f\x00\x72\x00\x6d\x00\x65\x00\x64\x00\x20\x00\x69\x00\x6e\x00\ +\x73\x00\x74\x00\x65\x00\x61\x00\x64\x00\x20\x00\x6f\x00\x66\x00\ +\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x63\x00\x6c\x00\x61\x00\ +\x73\x00\x73\x00\x69\x00\x63\x00\x20\x00\x6f\x00\x66\x00\x66\x00\ +\x73\x00\x65\x00\x74\x08\x00\x00\x00\x00\x06\x00\x00\x00\x4f\x49\ +\x66\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\x61\x6e\x20\x4f\x43\ +\x43\x2d\x73\x74\x79\x6c\x65\x20\x6f\x66\x66\x73\x65\x74\x20\x77\ +\x69\x6c\x6c\x20\x62\x65\x20\x70\x65\x72\x66\x6f\x72\x6d\x65\x64\ +\x20\x69\x6e\x73\x74\x65\x61\x64\x20\x6f\x66\x20\x74\x68\x65\x20\ +\x63\x6c\x61\x73\x73\x69\x63\x20\x6f\x66\x66\x73\x65\x74\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x98\x00\x49\ +\x00\x66\x00\x20\x00\x63\x00\x68\x00\x65\x00\x63\x00\x6b\x00\x65\ +\x00\x64\x00\x2c\x00\x20\x00\x63\x00\x6f\x00\x6d\x00\x6d\x00\x61\ +\x00\x6e\x00\x64\x00\x20\x00\x77\x00\x69\x00\x6c\x00\x6c\x00\x20\ +\x00\x6e\x00\x6f\x00\x74\x00\x20\x00\x66\x00\x69\x00\x6e\x00\x69\ +\x00\x73\x00\x68\x00\x20\x00\x75\x00\x6e\x00\x74\x00\x69\x00\x6c\ +\x00\x20\x00\x79\x00\x6f\x00\x75\x00\x20\x00\x70\x00\x72\x00\x65\ +\x00\x73\x00\x73\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x63\ +\x00\x6f\x00\x6d\x00\x6d\x00\x61\x00\x6e\x00\x64\x00\x20\x00\x62\ +\x00\x75\x00\x74\x00\x74\x00\x6f\x00\x6e\x00\x20\x00\x61\x00\x67\ +\x00\x61\x00\x69\x00\x6e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x4c\ +\x49\x66\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\x63\x6f\x6d\x6d\ +\x61\x6e\x64\x20\x77\x69\x6c\x6c\x20\x6e\x6f\x74\x20\x66\x69\x6e\ +\x69\x73\x68\x20\x75\x6e\x74\x69\x6c\x20\x79\x6f\x75\x20\x70\x72\ +\x65\x73\x73\x20\x74\x68\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x20\ +\x62\x75\x74\x74\x6f\x6e\x20\x61\x67\x61\x69\x6e\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x9e\x00\x4a\x00\x65\ +\x01\x5b\x00\x6c\x00\x69\x00\x20\x00\x70\x00\x6f\x00\x6c\x00\x65\ +\x00\x20\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\x00\x7a\x00\x61\ +\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\x6f\x00\x6e\x00\x65\ +\x00\x2c\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\ +\x00\x79\x00\x20\x00\x7a\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x6e\ +\x01\x05\x00\x20\x00\x73\x00\x6b\x00\x6f\x00\x70\x00\x69\x00\x6f\ +\x00\x77\x00\x61\x00\x6e\x00\x65\x00\x20\x00\x7a\x00\x61\x00\x6d\ +\x00\x69\x00\x61\x00\x73\x00\x74\x00\x20\x00\x70\x00\x72\x00\x7a\ +\x00\x65\x00\x6e\x00\x69\x00\x65\x00\x73\x00\x69\x00\x6f\x00\x6e\ +\x00\x65\x00\x20\x00\x28\x00\x43\x00\x29\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x37\x49\x66\x20\x63\x68\x65\x63\x6b\x65\x64\x2c\x20\ +\x6f\x62\x6a\x65\x63\x74\x73\x20\x77\x69\x6c\x6c\x20\x62\x65\x20\ +\x63\x6f\x70\x69\x65\x64\x20\x69\x6e\x73\x74\x65\x61\x64\x20\x6f\ +\x66\x20\x6d\x6f\x76\x65\x64\x20\x28\x43\x29\x07\x00\x00\x00\x05\ +\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x20\x00\x49\x00\x6e\x00\ +\x73\x00\x74\x00\x61\x00\x6c\x00\x6c\x00\x65\x00\x64\x00\x20\x00\ +\x4d\x00\x61\x00\x63\x00\x72\x00\x6f\x00\x73\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x10\x49\x6e\x73\x74\x61\x6c\x6c\x65\x64\x20\x4d\ +\x61\x63\x72\x6f\x73\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x3a\x00\x4f\x00\x73\x00\x74\x00\x61\x00\x74\x00\ +\x6e\x00\x69\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\ +\x20\x00\x7a\x00\x6f\x00\x73\x00\x74\x00\x61\x01\x42\x00\x20\x00\ +\x75\x00\x73\x00\x75\x00\x6e\x00\x69\x01\x19\x00\x74\x00\x79\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x1c\x4c\x61\x73\x74\x20\x70\x6f\ +\x69\x6e\x74\x20\x68\x61\x73\x20\x62\x65\x65\x6e\x20\x72\x65\x6d\ +\x6f\x76\x65\x64\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x0a\x00\x4c\x00\x69\x00\x6e\x00\x69\x00\x61\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x04\x4c\x69\x6e\x65\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x16\x00\x4b\x00\ +\x6f\x00\x6c\x00\x6f\x00\x72\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\ +\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0a\x4c\x69\x6e\ +\x65\x20\x43\x6f\x6c\x6f\x72\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x1e\x00\x53\x00\x7a\x00\x65\x00\x72\x00\ +\x6f\x00\x6b\x00\x6f\x01\x5b\x01\x07\x00\x20\x00\x6c\x00\x69\x00\ +\x6e\x00\x69\x00\x69\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0a\x4c\ +\x69\x6e\x65\x20\x57\x69\x64\x74\x68\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x0e\x00\x50\x00\x72\x00\x7a\x00\ +\x65\x00\x73\x00\x75\x01\x44\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x04\x4d\x6f\x76\x65\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\ +\x03\x00\x00\x00\x0a\x01\x7b\x00\x61\x00\x64\x00\x65\x00\x6e\x08\ +\x00\x00\x00\x00\x06\x00\x00\x00\x04\x4e\x6f\x6e\x65\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x18\x00\x4c\x00\ +\x69\x00\x63\x00\x7a\x00\x62\x00\x61\x00\x20\x00\x62\x00\x6f\x00\ +\x6b\x00\xf3\x00\x77\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0f\x4e\ +\x75\x6d\x62\x65\x72\x20\x6f\x66\x20\x73\x69\x64\x65\x73\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0c\x00\x4f\ +\x00\x66\x00\x66\x00\x73\x00\x65\x00\x74\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x06\x4f\x66\x66\x73\x65\x74\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x74\x00\x4f\x00\x66\x00\x66\ +\x00\x73\x00\x65\x00\x74\x00\x20\x00\x64\x00\x7a\x00\x69\x00\x61\ +\x01\x42\x00\x61\x00\x20\x00\x74\x00\x79\x00\x6c\x00\x6b\x00\x6f\ +\x00\x20\x00\x6e\x00\x61\x00\x20\x00\x6a\x00\x65\x00\x64\x00\x6e\ +\x00\x79\x00\x6d\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\ +\x00\x63\x00\x69\x00\x65\x00\x20\x00\x77\x00\x20\x00\x74\x00\x79\ +\x00\x6d\x00\x20\x00\x73\x00\x61\x00\x6d\x00\x79\x00\x6d\x00\x20\ +\x00\x63\x00\x7a\x00\x61\x00\x73\x00\x69\x00\x65\x00\x20\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x2a\x4f\x66\x66\x73\x65\x74\x20\x6f\ +\x6e\x6c\x79\x20\x77\x6f\x72\x6b\x73\x20\x6f\x6e\x20\x6f\x6e\x65\ +\x20\x6f\x62\x6a\x65\x63\x74\x20\x61\x74\x20\x61\x20\x74\x69\x6d\ +\x65\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x1c\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\ +\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0b\x50\x69\x63\x6b\x20\x4f\x62\x6a\ +\x65\x63\x74\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x74\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\ +\x7a\x00\x20\x00\x70\x00\x6f\x00\x77\x00\x69\x00\x65\x00\x72\x00\ +\x7a\x00\x63\x00\x68\x00\x6e\x00\x69\x01\x19\x00\x20\x00\x64\x00\ +\x6f\x00\x20\x00\x7a\x00\x64\x00\x65\x00\x66\x00\x69\x00\x6e\x00\ +\x69\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\x00\x61\x00\x20\x00\ +\x70\x01\x42\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\x00\x79\x00\ +\x7a\x00\x6e\x00\x79\x00\x20\x00\x72\x00\x79\x00\x73\x00\x75\x00\ +\x6e\x00\x6b\x00\x75\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x28\x50\x69\x63\x6b\x20\x61\x20\x66\x61\x63\x65\x20\x74\x6f\x20\ +\x64\x65\x66\x69\x6e\x65\x20\x74\x68\x65\x20\x64\x72\x61\x77\x69\ +\x6e\x67\x20\x70\x6c\x61\x6e\x65\x0a\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x1e\x00\x50\x00\x69\x00\x63\x00\ +\x6b\x00\x20\x00\x61\x00\x70\x00\x65\x00\x72\x00\x74\x00\x75\x00\ +\x72\x00\x65\x00\x3a\x00\x0a\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x0f\x50\x69\x63\x6b\x20\x61\x70\x65\x72\x74\x75\x72\x65\x3a\x0a\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2e\ +\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\ +\x00\x70\x00\x6f\x00\x64\x00\x73\x00\x74\x00\x61\x00\x77\x00\x6f\ +\x00\x77\x00\x79\x00\x20\x00\x6b\x01\x05\x00\x74\x00\x20\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x11\x50\x69\x63\x6b\x20\x62\x61\x73\ +\x65\x20\x61\x6e\x67\x6c\x65\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x2a\x00\x57\x00\x79\x00\x62\x00\ +\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x70\x00\x75\x00\x6e\x00\ +\x6b\x00\x74\x00\x20\x00\x62\x00\x61\x00\x7a\x00\x6f\x00\x77\x00\ +\x79\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x11\x50\x69\x63\ +\x6b\x20\x62\x61\x73\x65\x20\x70\x6f\x69\x6e\x74\x3a\x0a\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2e\x00\x57\ +\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x70\ +\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x20\x01\x5b\x00\x72\x00\x6f\ +\x00\x64\x00\x6b\x00\x6f\x00\x77\x00\x79\x00\x20\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x13\x50\x69\x63\x6b\x20\x63\x65\x6e\x74\x65\ +\x72\x20\x70\x6f\x69\x6e\x74\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x22\x00\x57\x00\x79\x00\x62\x00\ +\x72\x00\x61\x01\x07\x00\x20\x00\x6f\x00\x64\x00\x6c\x00\x65\x00\ +\x67\x01\x42\x00\x6f\x01\x5b\x01\x07\x00\x20\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x0f\x50\x69\x63\x6b\x20\x64\x69\x73\x74\x61\x6e\ +\x63\x65\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x2c\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\ +\x00\x7a\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x20\ +\x00\x6b\x00\x6f\x01\x44\x00\x63\x00\x6f\x00\x77\x00\x79\x00\x20\ +\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\x50\x69\x63\x6b\x20\x65\ +\x6e\x64\x20\x70\x6f\x69\x6e\x74\x3a\x0a\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2e\x00\x57\x00\x79\x00\x62\ +\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x70\x00\x69\x00\x65\ +\x00\x72\x00\x77\x00\x73\x00\x7a\x00\x79\x00\x20\x00\x70\x00\x75\ +\x00\x6e\x00\x6b\x00\x74\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x12\x50\x69\x63\x6b\x20\x66\x69\x72\x73\x74\x20\x70\x6f\x69\ +\x6e\x74\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x36\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\ +\x00\x7a\x00\x20\x00\x6c\x00\x6f\x00\x6b\x00\x61\x00\x6c\x00\x69\ +\x00\x7a\x00\x61\x00\x63\x00\x6a\x01\x19\x00\x20\x00\x70\x00\x75\ +\x00\x6e\x00\x6b\x00\x74\x00\x75\x00\x20\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x15\x50\x69\x63\x6b\x20\x6c\x6f\x63\x61\x74\x69\x6f\ +\x6e\x20\x70\x6f\x69\x6e\x74\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x6a\x00\x57\x00\x79\x00\x62\x00\ +\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x6e\x00\x61\x00\x73\x00\ +\x74\x01\x19\x00\x70\x00\x6e\x00\x79\x00\x20\x00\x70\x00\x75\x00\ +\x6e\x00\x6b\x00\x74\x00\x2c\x00\x20\x00\x61\x00\x6c\x00\x62\x00\ +\x6f\x00\x20\x00\x28\x00\x46\x00\x29\x00\x6b\x00\x6f\x00\x6e\x00\ +\x69\x00\x65\x00\x63\x00\x20\x00\x6c\x00\x75\x00\x62\x00\x20\x00\ +\x28\x00\x43\x00\x29\x00\x7a\x00\x61\x00\x6d\x00\x6b\x00\x6e\x00\ +\x69\x00\x6a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x29\x50\x69\x63\ +\x6b\x20\x6e\x65\x78\x74\x20\x70\x6f\x69\x6e\x74\x2c\x20\x6f\x72\ +\x20\x28\x46\x29\x69\x6e\x69\x73\x68\x20\x6f\x72\x20\x28\x43\x29\ +\x6c\x6f\x73\x65\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x2e\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\ +\x00\x72\x00\x7a\x00\x20\x00\x6e\x00\x61\x00\x73\x00\x74\x01\x19\ +\x00\x70\x00\x6e\x00\x79\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\ +\x00\x74\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x11\x50\x69\ +\x63\x6b\x20\x6e\x65\x78\x74\x20\x70\x6f\x69\x6e\x74\x3a\x0a\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x36\x00\ +\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\ +\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x20\x00\x70\x00\x72\x00\ +\x7a\x00\x65\x00\x63\x00\x69\x00\x77\x00\x6c\x00\x65\x00\x67\x01\ +\x42\x00\x79\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x15\x50\ +\x69\x63\x6b\x20\x6f\x70\x70\x6f\x73\x69\x74\x65\x20\x70\x6f\x69\ +\x6e\x74\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\ +\x00\x00\x00\x20\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\ +\x00\x7a\x00\x20\x00\x70\x00\x72\x00\x6f\x00\x6d\x00\x69\x00\x65\ +\x01\x44\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\x50\x69\ +\x63\x6b\x20\x72\x61\x64\x69\x75\x73\x3a\x0a\x07\x00\x00\x00\x05\ +\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x26\x00\x57\x00\x79\x00\ +\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x6b\x01\x05\x00\ +\x74\x00\x20\x00\x6f\x00\x62\x00\x72\x00\x6f\x00\x74\x00\x75\x00\ +\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x15\x50\x69\x63\x6b\x20\ +\x72\x6f\x74\x61\x74\x69\x6f\x6e\x20\x61\x6e\x67\x6c\x65\x3a\x0a\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2c\ +\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\ +\x01\x5b\x00\x72\x00\x6f\x00\x64\x00\x65\x00\x6b\x00\x20\x00\x6f\ +\x00\x62\x00\x72\x00\x6f\x00\x74\x00\x75\x00\x20\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x16\x50\x69\x63\x6b\x20\x72\x6f\x74\x61\x74\ +\x69\x6f\x6e\x20\x63\x65\x6e\x74\x65\x72\x3a\x0a\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\x57\x00\x79\ +\x00\x62\x00\x72\x00\x61\x01\x07\x00\x20\x00\x77\x00\x73\x00\x70\ +\x00\xf3\x01\x42\x00\x63\x00\x7a\x00\x79\x00\x6e\x00\x6e\x00\x69\ +\x00\x6b\x00\x20\x00\x73\x00\x6b\x00\x61\x00\x6c\x00\x6f\x00\x77\ +\x00\x61\x00\x6e\x00\x69\x00\x61\x00\x20\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x13\x50\x69\x63\x6b\x20\x73\x63\x61\x6c\x65\x20\x66\ +\x61\x63\x74\x6f\x72\x3a\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x2e\x00\x57\x00\x79\x00\x62\x00\x69\x00\ +\x65\x00\x72\x00\x7a\x00\x20\x00\x4b\x01\x05\x00\x74\x00\x20\x00\ +\x70\x00\x6f\x00\x63\x00\x7a\x01\x05\x00\x74\x00\x6b\x00\x6f\x00\ +\x77\x00\x79\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x12\x50\ +\x69\x63\x6b\x20\x73\x74\x61\x72\x74\x20\x61\x6e\x67\x6c\x65\x3a\ +\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x32\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\ +\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x20\x00\x70\x00\ +\x6f\x00\x63\x00\x7a\x01\x05\x00\x74\x00\x6b\x00\x6f\x00\x77\x00\ +\x79\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x12\x50\x69\x63\ +\x6b\x20\x73\x74\x61\x72\x74\x20\x70\x6f\x69\x6e\x74\x3a\x0a\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x0a\x00\ +\x50\x00\x75\x00\x6e\x00\x6b\x00\x74\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x05\x50\x6f\x69\x6e\x74\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x0e\x00\x50\x00\x72\x00\x6f\x00\x6d\ +\x00\x69\x00\x65\x01\x44\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06\ +\x52\x61\x64\x69\x75\x73\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\ +\x01\x03\x00\x00\x00\x1c\x00\x50\x00\x72\x00\x6f\x00\x6d\x00\x69\ +\x00\x65\x01\x44\x00\x20\x00\x6f\x00\x6b\x00\x72\x01\x19\x00\x67\ +\x00\x75\x08\x00\x00\x00\x00\x06\x00\x00\x00\x10\x52\x61\x64\x69\ +\x75\x73\x20\x6f\x66\x20\x43\x69\x72\x63\x6c\x65\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\x55\x00\x73\ +\x00\x75\x01\x44\x00\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\ +\x00\x79\x00\x20\x00\x7a\x00\x20\x00\x61\x00\x6b\x00\x74\x00\x79\ +\x00\x77\x00\x6e\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x6f\x00\x62\ +\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x75\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x25\x52\x65\x6d\x6f\x76\x65\x20\x70\x6f\x69\x6e\x74\ +\x73\x20\x66\x72\x6f\x6d\x20\x74\x68\x65\x20\x63\x75\x72\x72\x65\ +\x6e\x74\x20\x6f\x62\x6a\x65\x63\x74\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x0a\x00\x4f\x00\x62\x00\x72\x00\ +\xf3\x01\x07\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06\x52\x6f\x74\ +\x61\x74\x65\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\ +\x00\x00\x0a\x00\x53\x00\x6b\x00\x61\x00\x6c\x00\x61\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x05\x53\x63\x61\x6c\x65\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x26\x00\x57\x00\x79\ +\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x50\x01\x42\ +\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\x6e\ +\x01\x19\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c\x53\x65\x6c\x65\ +\x63\x74\x20\x50\x6c\x61\x6e\x65\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x2c\x00\x57\x00\x79\x00\x62\x00\x69\ +\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x70\x01\x42\x00\x61\x00\x73\ +\x00\x7a\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\x6e\x01\x19\x00\x20\ +\x00\x58\x00\x59\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0f\x53\x65\ +\x6c\x65\x63\x74\x20\x58\x59\x20\x70\x6c\x61\x6e\x65\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x2c\x00\x57\x00\ +\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x70\x01\ +\x42\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\x00\x79\x00\x7a\x00\ +\x6e\x01\x19\x00\x20\x00\x58\x00\x5a\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x0f\x53\x65\x6c\x65\x63\x74\x20\x58\x5a\x20\x70\x6c\x61\ +\x6e\x65\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x2c\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\ +\x00\x20\x00\x70\x01\x42\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\ +\x00\x79\x00\x7a\x00\x6e\x01\x19\x00\x20\x00\x59\x00\x5a\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0f\x53\x65\x6c\x65\x63\x74\x20\x59\ +\x5a\x20\x70\x6c\x61\x6e\x65\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x40\x00\x5a\x00\x61\x00\x7a\x00\x6e\x00\ +\x61\x00\x63\x00\x7a\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\ +\x6b\x00\x74\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x70\x00\x72\x00\ +\x7a\x00\x65\x00\x6e\x00\x69\x00\x65\x00\x73\x00\x69\x00\x65\x00\ +\x6e\x00\x69\x00\x61\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\ +\x19\x53\x65\x6c\x65\x63\x74\x20\x61\x6e\x20\x6f\x62\x6a\x65\x63\ +\x74\x20\x74\x6f\x20\x6d\x6f\x76\x65\x0a\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x32\x00\x57\x00\x79\x00\x62\ +\x00\x69\x00\x65\x00\x72\x00\x7a\x00\x20\x00\x6f\x00\x62\x00\x69\ +\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x6f\ +\x00\x66\x00\x66\x00\x73\x00\x65\x00\x74\x00\x20\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x1b\x53\x65\x6c\x65\x63\x74\x20\x61\x6e\x20\ +\x6f\x62\x6a\x65\x63\x74\x20\x74\x6f\x20\x6f\x66\x66\x73\x65\x74\ +\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x38\x00\x5a\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\ +\x20\x00\x6f\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x2c\x00\ +\x20\x00\x61\x00\x62\x00\x79\x00\x20\x00\x6f\x00\x62\x00\x72\x00\ +\xf3\x00\x63\x00\x69\x01\x07\x00\x20\x08\x00\x00\x00\x00\x06\x00\ +\x00\x00\x1b\x53\x65\x6c\x65\x63\x74\x20\x61\x6e\x20\x6f\x62\x6a\ +\x65\x63\x74\x20\x74\x6f\x20\x72\x6f\x74\x61\x74\x65\x0a\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3a\x00\x5a\ +\x00\x61\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\x20\x00\x6f\ +\x00\x62\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x64\x00\x6f\ +\x00\x20\x00\x73\x00\x6b\x00\x61\x00\x6c\x00\x6f\x00\x77\x00\x61\ +\x00\x6e\x00\x69\x00\x61\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\ +\x00\x1a\x53\x65\x6c\x65\x63\x74\x20\x61\x6e\x20\x6f\x62\x6a\x65\ +\x63\x74\x20\x74\x6f\x20\x73\x63\x61\x6c\x65\x0a\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x56\x00\x5a\x00\x61\ +\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\x20\x00\x6f\x00\x62\ +\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x2c\x00\x20\x00\x64\x00\x6f\ +\x00\x20\x00\x7a\x00\x77\x01\x19\x01\x7c\x00\x65\x00\x6e\x00\x69\ +\x00\x61\x00\x20\x00\x2f\x00\x20\x00\x72\x00\x6f\x00\x7a\x00\x73\ +\x00\x7a\x00\x65\x00\x72\x00\x7a\x00\x65\x00\x6e\x00\x69\x00\x61\ +\x00\x20\x08\x00\x00\x00\x00\x06\x00\x00\x00\x20\x53\x65\x6c\x65\ +\x63\x74\x20\x61\x6e\x20\x6f\x62\x6a\x65\x63\x74\x20\x74\x6f\x20\ +\x74\x72\x69\x6d\x2f\x65\x78\x74\x65\x6e\x64\x0a\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x40\x00\x5a\x00\x61\ +\x00\x7a\x00\x6e\x00\x61\x00\x63\x00\x7a\x00\x20\x00\x6f\x00\x62\ +\x00\x69\x00\x65\x00\x6b\x00\x74\x00\x20\x00\x64\x00\x6f\x00\x20\ +\x00\x75\x00\x61\x00\x6b\x00\x74\x00\x75\x00\x61\x00\x6c\x00\x6e\ +\x00\x69\x00\x65\x00\x6e\x00\x69\x00\x61\x00\x20\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x1c\x53\x65\x6c\x65\x63\x74\x20\x61\x6e\x20\ +\x6f\x62\x6a\x65\x63\x74\x20\x74\x6f\x20\x75\x70\x67\x72\x61\x64\ +\x65\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x68\x00\x57\x00\x79\x00\x62\x00\x69\x00\x65\x00\x72\x00\x7a\ +\x00\x20\x00\x70\x01\x42\x00\x61\x00\x73\x00\x7a\x00\x63\x00\x7a\ +\x00\x79\x00\x7a\x00\x6e\x01\x19\x00\x20\x00\x70\x00\x72\x00\x6f\ +\x00\x73\x00\x74\x00\x6f\x00\x70\x00\x61\x00\x64\x01\x42\x01\x05\ +\x00\x20\x00\x64\x00\x6f\x00\x20\x00\x61\x00\x6b\x00\x74\x00\x75\ +\x00\x61\x00\x6c\x00\x6e\x00\x65\x00\x67\x00\x6f\x00\x20\x00\x77\ +\x00\x69\x00\x64\x00\x6f\x00\x6b\x00\x75\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x2e\x53\x65\x6c\x65\x63\x74\x20\x70\x6c\x61\x6e\x65\ +\x20\x70\x65\x72\x70\x65\x6e\x64\x69\x63\x75\x6c\x61\x72\x20\x74\ +\x6f\x20\x74\x68\x65\x20\x63\x75\x72\x72\x65\x6e\x74\x20\x76\x69\ +\x65\x77\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x24\x00\x5a\x00\x61\x00\x6d\x00\x6b\x00\x6e\x00\x69\x01\x19\ +\x00\x74\x00\x6f\x00\x20\x00\x42\x00\x2d\x00\x53\x00\x70\x00\x6c\ +\x00\x61\x00\x6a\x00\x6e\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17\ +\x53\x70\x6c\x69\x6e\x65\x20\x68\x61\x73\x20\x62\x65\x65\x6e\x20\ +\x63\x6c\x6f\x73\x65\x64\x0a\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x1c\x00\x4b\x01\x05\x00\x74\x00\x20\x00\ +\x70\x00\x6f\x00\x63\x00\x7a\x01\x05\x00\x74\x00\x6b\x00\x6f\x00\ +\x77\x00\x79\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0b\x53\x74\x61\ +\x72\x74\x20\x41\x6e\x67\x6c\x65\x07\x00\x00\x00\x05\x64\x72\x61\ +\x66\x74\x01\x03\x00\x00\x00\x46\x00\x54\x00\x65\x00\x6e\x00\x20\ +\x00\x74\x00\x79\x00\x70\x00\x20\x00\x6f\x00\x62\x00\x69\x00\x65\ +\x00\x6b\x00\x74\x00\x75\x00\x20\x00\x6e\x00\x69\x00\x65\x00\x20\ +\x00\x6a\x00\x65\x00\x73\x00\x74\x00\x20\x00\x65\x00\x64\x00\x79\ +\x00\x74\x00\x6f\x00\x77\x00\x61\x00\x6c\x00\x6e\x00\x79\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x21\x54\x68\x69\x73\x20\x6f\x62\x6a\ +\x65\x63\x74\x20\x74\x79\x70\x65\x20\x69\x73\x20\x6e\x6f\x74\x20\ +\x65\x64\x69\x74\x61\x62\x6c\x65\x0a\x07\x00\x00\x00\x05\x64\x72\ +\x61\x66\x74\x01\x03\x00\x00\x00\x32\x00\x50\x00\x72\x00\x7a\x00\ +\x65\x01\x42\x01\x05\x00\x63\x00\x7a\x00\x61\x00\x20\x00\x64\x00\ +\x6f\x00\x20\x00\x74\x00\x72\x00\x79\x00\x62\x00\x75\x00\x20\x00\ +\x62\x00\x75\x00\x64\x00\x6f\x00\x77\x00\x79\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x19\x54\x6f\x67\x67\x6c\x65\x73\x20\x43\x6f\x6e\ +\x73\x74\x72\x75\x63\x74\x69\x6f\x6e\x20\x4d\x6f\x64\x65\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x10\x00\x55\ +\x00\x63\x00\x69\x00\x6e\x00\x61\x00\x6e\x00\x69\x00\x65\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x04\x54\x72\x69\x6d\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\x43\x00\x6f\ +\x00\x66\x00\x61\x00\x20\x00\x6f\x00\x73\x00\x74\x00\x61\x00\x74\ +\x00\x6e\x00\x69\x00\x20\x00\x73\x00\x65\x00\x67\x00\x6d\x00\x65\ +\x00\x6e\x00\x74\x00\x20\x00\x28\x00\x43\x00\x54\x00\x52\x00\x4c\ +\x00\x20\x00\x2b\x00\x20\x00\x5a\x00\x29\x08\x00\x00\x00\x00\x06\ +\x00\x00\x00\x1e\x55\x6e\x64\x6f\x20\x74\x68\x65\x20\x6c\x61\x73\ +\x74\x20\x73\x65\x67\x6d\x65\x6e\x74\x20\x28\x43\x54\x52\x4c\x2b\ +\x5a\x29\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x0a\x00\x57\x00\x69\x00\x64\x00\x6f\x00\x6b\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x04\x56\x69\x65\x77\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\xa2\x00\x57\x00\x69\x00\x70\ +\x00\x65\x00\x73\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\x00\x65\ +\x00\x78\x00\x69\x00\x73\x00\x74\x00\x69\x00\x6e\x00\x67\x00\x20\ +\x00\x73\x00\x65\x00\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x73\ +\x00\x20\x00\x6f\x00\x66\x00\x20\x00\x74\x00\x68\x00\x69\x00\x73\ +\x00\x20\x00\x6c\x00\x69\x00\x6e\x00\x65\x00\x20\x00\x61\x00\x6e\ +\x00\x64\x00\x20\x00\x73\x00\x74\x00\x61\x00\x72\x00\x74\x00\x73\ +\x00\x20\x00\x61\x00\x67\x00\x61\x00\x69\x00\x6e\x00\x20\x00\x66\ +\x00\x72\x00\x6f\x00\x6d\x00\x20\x00\x74\x00\x68\x00\x65\x00\x20\ +\x00\x6c\x00\x61\x00\x73\x00\x74\x00\x20\x00\x70\x00\x6f\x00\x69\ +\x00\x6e\x00\x74\x00\x20\x00\x28\x00\x57\x00\x29\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x51\x57\x69\x70\x65\x73\x20\x74\x68\x65\x20\ +\x65\x78\x69\x73\x74\x69\x6e\x67\x20\x73\x65\x67\x6d\x65\x6e\x74\ +\x73\x20\x6f\x66\x20\x74\x68\x69\x73\x20\x6c\x69\x6e\x65\x20\x61\ +\x6e\x64\x20\x73\x74\x61\x72\x74\x73\x20\x61\x67\x61\x69\x6e\x20\ +\x66\x72\x6f\x6d\x20\x74\x68\x65\x20\x6c\x61\x73\x74\x20\x70\x6f\ +\x69\x6e\x74\x20\x28\x57\x29\x07\x00\x00\x00\x05\x64\x72\x61\x66\ +\x74\x01\x03\x00\x00\x00\x24\x00\x5a\x00\x61\x00\x6d\x00\x6b\x00\ +\x6e\x00\x69\x01\x19\x00\x74\x00\x6f\x00\x20\x00\x73\x00\x7a\x00\ +\x6b\x00\x69\x00\x65\x00\x6c\x00\x65\x00\x74\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x15\x57\x69\x72\x65\x20\x68\x61\x73\x20\x62\x65\ +\x65\x6e\x20\x63\x6c\x6f\x73\x65\x64\x0a\x07\x00\x00\x00\x05\x64\ +\x72\x61\x66\x74\x01\x03\x00\x00\x00\x14\x00\x57\x00\x69\x00\x72\ +\x00\x65\x00\x20\x00\x74\x00\x6f\x00\x6f\x00\x6c\x00\x73\x08\x00\ +\x00\x00\x00\x06\x00\x00\x00\x0a\x57\x69\x72\x65\x20\x74\x6f\x6f\ +\x6c\x73\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\ +\x00\x02\x00\x58\x08\x00\x00\x00\x00\x06\x00\x00\x00\x01\x58\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\ +\x57\x00\x73\x00\x70\x00\xf3\x01\x42\x00\x72\x00\x7a\x01\x19\x00\ +\x64\x00\x6e\x00\x61\x00\x20\x00\x58\x00\x20\x00\x6e\x00\x61\x00\ +\x73\x00\x74\x01\x19\x00\x70\x00\x6e\x00\x65\x00\x67\x00\x6f\x00\ +\x20\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x75\x08\x00\x00\ +\x00\x00\x06\x00\x00\x00\x1a\x58\x20\x63\x6f\x6f\x72\x64\x69\x6e\ +\x61\x74\x65\x20\x6f\x66\x20\x6e\x65\x78\x74\x20\x70\x6f\x69\x6e\ +\x74\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x04\x00\x58\x00\x59\x08\x00\x00\x00\x00\x06\x00\x00\x00\x02\x58\ +\x59\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x04\x00\x58\x00\x5a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x02\x58\ +\x5a\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\ +\x02\x00\x59\x08\x00\x00\x00\x00\x06\x00\x00\x00\x01\x59\x07\x00\ +\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\x57\ +\x00\x73\x00\x70\x00\xf3\x01\x42\x00\x72\x00\x7a\x01\x19\x00\x64\ +\x00\x6e\x00\x61\x00\x20\x00\x59\x00\x20\x00\x6e\x00\x61\x00\x73\ +\x00\x74\x01\x19\x00\x70\x00\x6e\x00\x65\x00\x67\x00\x6f\x00\x20\ +\x00\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x75\x08\x00\x00\x00\ +\x00\x06\x00\x00\x00\x1a\x59\x20\x63\x6f\x6f\x72\x64\x69\x6e\x61\ +\x74\x65\x20\x6f\x66\x20\x6e\x65\x78\x74\x20\x70\x6f\x69\x6e\x74\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x04\ +\x00\x59\x00\x5a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x02\x59\x5a\ +\x07\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x02\ +\x00\x5a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x01\x5a\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x3e\x00\x57\x00\ +\x73\x00\x70\x00\xf3\x01\x42\x00\x72\x00\x7a\x01\x19\x00\x64\x00\ +\x6e\x00\x61\x00\x20\x00\x5a\x00\x20\x00\x6e\x00\x61\x00\x73\x00\ +\x74\x01\x19\x00\x70\x00\x6e\x00\x65\x00\x67\x00\x6f\x00\x20\x00\ +\x70\x00\x75\x00\x6e\x00\x6b\x00\x74\x00\x75\x08\x00\x00\x00\x00\ +\x06\x00\x00\x00\x1a\x5a\x20\x63\x6f\x6f\x72\x64\x69\x6e\x61\x74\ +\x65\x20\x6f\x66\x20\x6e\x65\x78\x74\x20\x70\x6f\x69\x6e\x74\x07\ +\x00\x00\x00\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x24\x00\ +\x61\x00\x6b\x00\x74\x00\x79\x00\x77\x00\x6e\x00\x65\x00\x20\x00\ +\x70\x00\x6f\x00\x6c\x00\x65\x00\x63\x00\x65\x00\x6e\x00\x69\x00\ +\x65\x00\x3a\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0f\x61\x63\x74\ +\x69\x76\x65\x20\x63\x6f\x6d\x6d\x61\x6e\x64\x3a\x07\x00\x00\x00\ +\x05\x64\x72\x61\x66\x74\x01\x03\x00\x00\x00\x36\x00\x50\x00\x61\ +\x00\x73\x00\x65\x00\x6b\x00\x20\x00\x70\x00\x6f\x00\x6c\x00\x65\ +\x00\x63\x00\x65\x01\x44\x00\x20\x00\x70\x00\x72\x00\x6f\x00\x6a\ +\x00\x65\x00\x6b\x00\x74\x00\x6f\x00\x77\x00\x61\x00\x6e\x00\x69\ +\x00\x61\x08\x00\x00\x00\x00\x06\x00\x00\x00\x11\x64\x72\x61\x66\ +\x74\x20\x43\x6f\x6d\x6d\x61\x6e\x64\x20\x42\x61\x72\x07\x00\x00\ +\x00\x05\x64\x72\x61\x66\x74\x01\ \x00\x00\x95\xad\ \x3c\ \xb8\x64\x18\xca\xef\x9c\x95\xcd\x21\x1c\xbf\x60\xa1\xbd\xdd\x42\ @@ -23802,388 +26614,416 @@ qt_resource_data = "\ \x93\x83\x1e\x48\xef\x57\xc6\xa2\x49\xdb\x13\x44\xd4\xba\x3f\x06\ \x46\x3f\xfe\x6c\x03\x93\xf1\x73\xb1\x4b\x54\x79\xc9\xd8\x04\x84\ \x23\xc5\xbe\x37\x98\x7a\x44\xf4\xff\x03\x15\x2c\x14\x99\ -\x00\x00\x09\x10\ +\x00\x00\x09\x69\ \x00\ -\x00\x45\x1d\x78\x9c\xed\x5c\x6d\x73\xdb\x36\x12\xfe\xee\x5f\x81\ -\xd1\x87\xbb\xb4\xe3\x5a\x96\x5f\x93\x9c\xac\x4e\x62\xd7\x49\x6e\ -\x92\x6b\x7a\x72\xd3\xfb\xe6\x81\x48\x48\x44\x4d\x12\x2a\x00\x5a\ -\x52\x7f\xfd\xed\x02\xa0\xf8\x22\xea\xdd\x92\x1c\x8f\x66\x3c\x23\ -\x11\x00\x77\x17\x8b\x67\x17\x8b\xc5\x5a\xcd\x9f\x87\x51\x48\x1e\ -\x99\x54\x5c\xc4\x57\xb5\xc6\xd1\x71\x8d\xb0\xd8\x13\x3e\x8f\x7b\ -\x57\xb5\xdf\xef\x6e\x7f\x7a\x5d\xfb\xb9\x75\xd0\x4c\x78\x36\xe8\ -\x0c\x06\xb5\x0e\x48\xd3\x0b\xa9\x52\xad\x0f\x09\x7f\xfb\xf6\x86\ -\xd3\x50\xf4\xe0\x33\xec\xb5\x99\xd6\xf0\xb2\xba\x91\xb4\xab\x9b\ -\x75\x3b\x08\x46\x0f\xb8\xdf\x63\x9a\x98\xe7\xab\xda\x6f\x7f\x98\ -\xc7\x1a\x89\x69\xc4\xae\x6a\x33\x89\x20\x33\xd2\xec\x4b\xd1\x67\ -\x52\x8f\xdc\x1b\x3d\x26\x22\xa6\xe5\xc8\x74\x92\xa6\x64\x9e\x36\ -\xdf\x48\x73\xd8\x3a\x6e\xd6\x87\xee\x61\x84\x0f\x23\xf7\x00\x22\ -\xe8\xa0\x75\x7e\x79\xde\xac\xdb\xaf\xb6\x39\x60\xbc\x17\xe8\xd6\ -\xc5\xc9\x9b\x66\xdd\x7d\x37\x34\xeb\x29\xd1\x66\x3d\x65\x5e\x25\ -\xc9\x80\xc7\xbe\x18\xdc\x71\x1d\x32\x27\x8c\xd2\x12\x84\x6f\x7d\ -\x8a\xfa\x42\xea\xfa\x2f\x43\xfc\x68\xd6\x5d\xeb\x24\xbd\x90\x8e\ -\x44\x92\x69\xe6\xdb\x7b\x31\xfc\x6c\x9a\x1c\xb9\x12\x3f\xd5\xa7\ -\x1e\x10\xaa\x39\xe9\xe3\x24\xea\x30\xd9\xba\x68\xd6\xdd\x37\x2b\ -\x7b\x9e\xc3\x04\x89\x88\xca\x1e\x8f\x4b\x14\xde\xcc\xa4\xc0\x35\ -\x8b\x32\x35\xe6\x57\xf2\x83\x14\x49\x1f\x64\x1e\xaf\xa5\x7b\x6e\ -\x9c\x38\x06\x13\xec\x75\xa6\xab\x9c\xba\x6e\xfe\x77\x4b\xba\x42\ -\x46\x54\x13\xd1\xd7\x80\x34\x95\xd7\xd9\xa4\x48\xf3\x35\x37\x57\ -\x79\x53\xf5\x57\xc5\x6d\xb6\x16\xa7\x2a\xb2\x9a\x54\xa6\xce\x8a\ -\x79\x7c\x9c\x9c\xc7\x02\x33\x99\x31\x97\x2a\x11\xe6\xcf\x27\x23\ -\x78\xbc\x20\xc1\xc2\xac\x26\x91\xf2\x99\x76\x58\x98\xc2\x44\xb3\ -\xa1\x36\x0d\x8d\xfb\xd3\x3c\xcf\x49\xb4\xc0\xc0\xc2\x80\x92\x81\ -\x11\xa5\x47\x21\x2b\x61\x65\xaa\x8c\xc4\xd8\x3e\x48\x95\x9f\x4a\ -\x51\xee\x39\xd3\x30\xbe\xea\xab\x64\xdd\x6b\x11\x75\x44\x0e\xf8\ -\x3d\xec\xe8\x43\x87\x87\x1d\x1d\xe8\x98\x39\x2d\x21\xc2\x3b\xde\ -\xaf\x9e\xd9\x5d\xc0\x15\x81\x3f\x1d\x30\x02\x6e\x2e\x10\x3e\xf1\ -\x02\x21\x14\xf3\xd1\x44\x08\x37\x13\x87\x81\x04\x1e\xb4\xa4\xb1\ -\x0a\xa9\x79\x44\x1b\x12\x9d\x3f\xc1\x6f\x11\x4f\x84\x38\x32\xd6\ -\x82\xdc\x4a\xc6\xae\xdf\xdd\x1c\x91\x83\x4f\x5d\xd7\x1e\xd1\x7e\ -\x1f\x5f\x00\x1e\x8e\xf0\x21\x01\xc0\x91\x28\x51\xda\xb5\x10\x5a\ -\x1a\xdb\xe5\x21\x83\xa6\x58\x53\x1e\xe3\x33\xcd\x58\x8b\x98\x68\ -\xda\x81\x6e\x1d\x80\xf9\x0e\x78\x18\xe2\x40\xd8\x31\x9c\x1c\xca\ -\x0a\x12\xf2\x98\x19\xcf\xab\x8e\x0e\x16\x5e\xb0\x09\xcd\x79\x89\ -\x94\x2c\xd6\x9f\x62\x9f\x0d\x4b\xea\x9b\x8e\xd7\x45\x89\xe3\xfa\ -\xfd\x12\xe3\xc6\x02\xb8\xf2\x15\xd3\x57\xb5\xe3\x12\x13\xcf\x09\ -\xee\x0f\xbb\x0e\x7a\xde\xaa\x53\x41\x6e\x5f\xa9\x0e\xe6\x33\xfb\ -\x22\xfc\x7a\xba\xa5\x2e\xcc\xad\x04\xe4\x45\x6c\x6b\x0c\xc1\xff\ -\x88\x98\x91\x57\x5d\xaa\x34\x53\xfa\x87\xaa\xd5\x9a\xc6\xb5\x5e\ -\x66\xbb\x96\x1c\xbf\x03\x12\x7d\xd6\xa5\x49\x98\x62\x9a\xc6\x7e\ -\x86\xa4\xdd\x09\xf6\xab\xe4\xe0\x2e\x69\xf8\xbc\xa4\xba\x1e\x9b\ -\x2c\xf8\x8a\xbc\xc9\xed\x50\x24\xc9\xa8\x66\xa4\x4f\x25\xc5\x90\ -\x8d\x7b\xce\x45\x95\xf7\xf7\xed\x8b\xd4\x7e\x60\xda\x0b\xd8\x5a\ -\x82\xcc\xdd\x4f\x9a\x75\xbb\xbd\x67\xd1\x40\xbe\x7b\xe1\x48\xc0\ -\x4d\x2a\x10\x92\xff\x8d\x3e\x38\x9c\x8c\x10\x96\xd9\x7e\x43\x7c\ -\xb8\xbf\x5c\x71\xe7\xfd\x42\x87\xa4\xdd\x47\x6c\x91\x36\xeb\x45\ -\xe0\x8d\x77\xb0\xff\xb6\x61\x57\xaa\xda\x7e\x15\xb4\xc3\xee\x7b\ -\x7f\x32\x73\x72\x11\x1d\xf2\x28\x89\xda\xfc\x6f\x56\x9e\x23\x34\ -\x95\x60\x63\x8f\x0b\x17\xc7\x85\x83\xc3\xb8\xd7\x1d\x1a\x1a\x17\ -\x97\x97\x97\x27\x8d\xf3\xc2\x29\x22\x9b\x64\x99\xec\x62\x3b\xc4\ -\xcc\x30\xe1\x8f\x80\xc5\x84\x0d\xd3\x60\x40\x99\x15\x51\x68\xf6\ -\x10\x08\x1c\x62\xf4\x30\x22\x54\x32\xbb\x4f\x63\x6c\x0d\x3e\x81\ -\xc7\xa4\x2f\xc2\x91\x19\x79\x44\x4c\xa0\xf1\x48\xc3\x84\x8d\xc3\ -\x0d\xab\x17\x12\xb2\xb8\xa7\x03\x22\xba\x84\x51\xcf\x7c\x62\x6f\ -\xfa\x2a\x51\x76\xd9\x81\x04\xc4\x14\xc7\x86\x57\x6c\x46\x0c\x02\ -\x01\x71\x80\x15\xc5\xd0\x34\xa6\xe6\x13\xaa\x20\x60\x00\xb9\x29\ -\xaa\x26\x7d\xfd\x68\xf5\x28\xc0\x08\x5d\xbd\xfd\x9f\x6f\x65\xfb\ -\x07\x45\x39\x85\xa7\x16\xf0\x3c\xc3\x80\x1d\x3b\xa8\x42\x74\xbf\ -\xbc\x8b\x5a\xd1\x41\x5d\x4f\x44\xae\x3b\x70\x50\xb7\xc0\xf6\xda\ -\xc4\xd2\x72\xc2\x49\xa1\x48\x9e\xeb\x9b\xe9\xa6\x20\xd6\x5e\xd2\ -\x4d\x9d\x1e\xcf\xf6\x53\xc7\xdb\x73\x50\x77\x01\xab\x3a\x44\x74\ -\x4b\xc7\x16\x88\xa4\xa7\x9c\x13\x56\xf7\x0f\xcb\x05\xf2\x4e\x3c\ -\x0b\x94\xbd\x1d\x57\xd9\xf1\xe5\xe2\x76\x9c\x1d\x91\x03\xe6\x3d\ -\x54\x1e\x91\xb1\x63\xfe\x26\x3d\x13\x5c\x1c\xb7\x24\x7b\x4e\x4e\ -\x62\x43\x10\x4f\xb1\xe8\x13\x54\x3d\x32\x1f\x64\x20\xe2\x7f\x6a\ -\xd2\x61\xee\xc4\xcc\xfc\xd5\xf1\x34\x37\x0d\x61\x39\xe2\x31\xc0\ -\xe7\xb0\x1f\xa8\x8a\x0c\xd6\x92\x50\x5a\x1c\xbe\xc8\x7b\x8f\xdb\ -\x6a\xdc\x9e\x6c\x04\xb7\x73\x72\x56\x0b\xe2\x76\x8c\xda\x3e\x85\ -\xd7\x09\xe6\xf4\x58\x7a\x3a\xb2\x69\x94\x1c\x76\x21\xae\x13\x1b\ -\xc4\xaf\xd5\xec\xd6\x20\x6b\xd9\xed\x41\x5b\x0d\xda\xb3\x8d\x80\ -\x76\xce\x71\x6f\x16\x68\x0d\x71\x87\xdb\xae\x49\x15\x0e\x68\xac\ -\x4d\xc4\x1f\x8b\xf8\x27\xa4\xe0\x93\x4e\x28\xbc\x07\x45\x5e\x75\ -\x58\x8f\xc7\x26\x47\x38\xe0\x70\x86\xa0\xe4\xc7\x1f\xf0\x50\xb2\ -\x3d\x2c\xff\x68\x25\xd9\x16\x96\x95\xa6\x32\xe5\xb8\xc7\x73\x15\ -\x9e\x5f\x6f\x04\xcf\xe7\x4f\xeb\x84\x53\xc7\xdb\x95\x22\x32\xc8\ -\x56\x40\x07\xfd\x22\x93\x99\x37\xfe\x53\x40\x70\xea\xdb\x38\xd5\ -\x2c\x02\x79\x6f\x56\x1e\x22\x8f\x44\x1a\xcc\xe3\x9b\x3e\x87\xb3\ -\x21\x1d\x11\x93\x3f\x95\x87\xa4\x03\xea\x8a\xe8\x83\xeb\xc6\xd3\ -\xb5\x52\x70\xb0\x56\x3c\x1c\x11\xe6\x73\x93\x3c\xdf\x84\x3d\x98\ -\xcb\xb8\x74\x0a\x46\xe6\x2d\x5a\x46\x0f\x99\x7f\x36\xbc\xf7\x76\ -\x51\x6d\x17\xe7\x1b\xb1\x8b\x37\xab\xdb\x05\xde\x10\xa5\xf6\xd0\ -\x95\x8c\x79\xd4\xb7\xd0\x87\x15\x47\x1f\x8e\xf0\xc7\x44\x3c\x8f\ -\x3d\xee\x33\xf8\x9a\x1a\x8d\x01\xd7\x80\x4b\xcc\x2a\xbd\x67\x03\ -\x2a\xd9\xa1\xb5\x30\x8f\xe2\xe5\xd0\x03\xde\x27\x0d\x02\x38\x5f\ -\x1d\x1d\xad\x91\xf5\x99\x8e\xf4\x7f\x83\x48\x24\xad\x0a\xd8\x0a\ -\xbc\x51\x15\x19\xc3\x3d\xbe\xab\xf0\x7d\xb1\x09\x7c\xaf\x85\xee\ -\x09\xaf\x4f\x01\xdc\x29\x88\x73\xb7\x9b\x5d\x08\xc5\x33\xaf\x6f\ -\x93\xac\x36\x8d\x79\xea\x9b\x34\xa8\x19\xb0\x09\x24\xdb\x82\x11\ -\x72\x7a\x33\x16\x0b\x98\xa6\x1c\x49\xc4\xd4\x94\x1b\x8b\x8d\xe4\ -\x45\x80\xdb\x1e\xdb\xd5\xd8\x6e\x34\x36\xe2\xbc\x5f\x3f\x2d\xbc\ -\xb3\x88\xdb\x66\x44\x10\xd0\x28\x98\x89\x6f\x34\x8d\x7d\x2a\x7d\ -\x17\xc8\xe0\x08\x82\x59\x40\x78\x2b\x86\xb8\x05\x5c\xbf\x4b\xfb\ -\x63\xa3\xbd\x4e\x08\xe8\x23\xc3\x3b\x04\x6c\xc5\x6a\x03\x5f\x78\ -\xc9\x52\xf7\x3f\x4b\x18\x02\x5e\xfd\x8e\x45\xec\x82\xea\xad\x1c\ -\x26\x7b\x88\x93\xd9\x96\x11\xb4\xb5\x8f\xf9\xd7\xbd\x1d\x4c\xb1\ -\x83\xcd\x64\x58\x1a\xc7\x4f\x6b\x08\x01\x35\x77\xbd\x63\x97\xee\ -\x0a\x54\xd2\x58\x5e\x81\xa1\x84\xcc\x46\x30\x1b\x3c\x99\x1a\x29\ -\x48\x47\x24\x88\x6a\xce\x8c\x6f\x5f\x93\xe7\x12\x60\xb6\xce\xe0\ -\x66\xd8\xfd\x48\xdd\xc5\xf7\x4b\x84\x74\xb1\xb3\x40\x2b\x37\x6e\ -\xa5\x92\xc6\xfb\x25\x8b\x1a\xdb\xdf\x3e\x3c\x5d\x51\xa3\xe3\x94\ -\xcb\x3d\x7e\xef\xe5\x8d\xe9\x8c\x0a\xe9\xae\x97\x5b\xe8\x38\x27\ -\x5f\xb1\xf3\x42\x47\x93\x7f\x96\x13\x7e\xbe\x6d\x9a\x0b\xb1\xfc\ -\xa4\xf4\x30\x1a\xc2\x00\x53\x0b\x58\x9a\x04\x03\x95\xb6\x7e\xd3\ -\x6f\xdf\x7e\x1c\x53\x6c\xd6\x4d\xe3\xd2\x4e\x07\xf7\xff\x8f\xe0\ -\xae\xa7\x3b\x9d\xa9\xb7\xa2\x67\xb3\x2f\x45\x4f\xd6\xba\x15\x85\ -\x61\x46\x47\x4b\xe8\x7a\xd5\xa2\xd2\x75\x6e\x1e\x16\x2e\x2b\x45\ -\xb7\x35\xbd\x8e\xf4\xfb\x2f\xdd\x54\x8f\xbd\x7d\xe9\xe6\xbe\x74\ -\xf3\xa9\xa5\xda\x75\x24\xfe\x66\xf1\x40\xbc\xaa\x1a\x70\xce\x5d\ -\xfc\xbc\x84\x45\xfb\x99\xd4\xe1\x83\x71\xdf\xdb\x7c\xcd\xbd\x31\ -\xf2\xfb\xf5\xeb\xf1\xcd\xd4\xf0\x30\x6c\xe2\x39\x2c\x61\xc1\x64\ -\xa7\x04\x01\xc9\xa0\x58\x83\x47\x5d\x51\xe9\xcb\x70\x92\x05\x3d\ -\xbe\x4c\x67\x79\xe7\xea\x90\x60\x0f\x7c\x85\x9b\x60\x5f\x62\x82\ -\xfb\x1f\x34\xea\xff\x2b\xbd\xc5\xd9\xa1\x0b\xfd\x2f\x1d\x58\xb1\ -\xae\xdf\x7d\x59\x4b\x8c\x5d\xbb\xa6\xc2\x69\xfe\xe9\x92\x04\xb3\ -\x63\xd2\x65\x8a\x67\xd1\xb2\x1f\x39\x1b\xa8\x43\xbc\xa8\x63\x26\ -\x2d\x3c\x08\xd0\xc2\xcd\xd6\x20\xe4\x03\xc1\xa2\x7a\x8a\xb1\x10\ -\xe9\x84\xd4\x7b\x38\x34\x41\x53\x87\x69\x0d\x31\xb3\x64\xd4\xa7\ -\x1d\x1e\x72\x60\x4e\x7b\x14\xf3\x67\xee\xf5\x0e\x0c\xc5\x9b\xb0\ -\xd8\xdf\x48\x5e\x61\x8c\xdf\x9c\xb4\x6e\x5f\x33\xb7\x7d\xc0\x7d\ -\x0d\x57\x64\x93\x27\x25\xce\x1d\x50\x6b\x4b\xcb\x04\x3c\x82\xf9\ -\xba\x49\x27\xd4\x7e\xec\x7d\xc6\x1a\xdb\xf7\x76\x22\xcf\xd3\x03\ -\x3d\xdf\x74\xc5\xf8\xb0\xb0\x58\xba\xe2\xd7\xeb\x77\x4f\x9f\xae\ -\xc8\x6c\xf4\xa5\xa4\x2b\x0a\xa5\x90\xdf\x7d\xba\x62\x09\x77\x7b\ -\xb6\xba\xbb\x9d\x51\x40\x44\xc1\x79\x2a\xf2\xea\xf4\xc6\x5e\xba\ -\x55\xd5\x0a\x6d\xe4\xca\xd8\xa5\x55\x10\xf4\x46\x84\xad\xa4\x60\ -\x85\x47\x1d\xb3\xbd\x2f\x33\x6b\x91\xcf\x39\x61\x42\x9e\x7b\x69\ -\xc6\x69\x9a\xef\xaa\x4a\x35\x65\x59\xa6\x6f\x8e\x46\x21\xc7\x34\ -\xe9\xb7\x96\xc8\x2c\x15\x93\x4a\x2e\x9f\x74\x32\x91\x4f\x4a\x53\ -\x49\x67\x13\xa9\xa4\x42\x16\xa9\x2c\x4a\x21\x77\x94\x29\x29\xa7\ -\xc9\x9c\x1a\x9d\x73\x4a\x4f\xd5\xce\xd9\x5c\xd5\x2e\x6a\xc4\xba\ -\x89\xab\x5a\xa3\x51\xab\xe3\xc8\x3e\x1f\x46\xb4\xdf\x4d\x62\x0f\ -\x15\xd5\xfa\xeb\xab\x79\xbe\x95\x22\xfa\xc2\x23\xd6\x16\x89\xf4\ -\x60\x03\x2f\x8d\xc2\x9f\x75\x48\x94\x16\x91\xe5\xa8\x8c\x24\xf9\ -\x16\x2b\x65\xee\xa7\x1f\x72\xff\xe4\x90\xfd\xda\x03\xae\xc7\x50\ -\x33\x08\x79\x5a\xee\x97\x1e\x60\x35\x5c\xc3\x81\x55\x15\xf5\x61\ -\xca\x40\xa1\x8e\x04\xec\x4f\x3f\x1c\x05\xa8\x38\xd3\x61\x14\x50\ -\xe6\x3b\x5b\x90\xd2\x7f\x5c\x54\x0a\x33\x29\xf1\x34\xa9\x90\x9a\ -\x95\x5c\xad\x2f\x96\xfb\x4f\xb5\x6a\xfd\x8c\x3b\xb7\x22\x4a\xea\ -\xe3\xab\x65\xc9\x7a\xb7\x23\x8c\x3b\xb9\x4f\x11\x66\xdc\xbb\xbe\ -\x30\xc5\x06\xf3\x83\x24\x92\x29\x63\x03\xca\x58\x8b\x27\xe2\x98\ -\x19\x1b\xc0\xe7\x66\x3d\xe1\xad\x83\xff\x03\xad\x19\x30\x45\ -\x00\x00\x0e\x86\ +\x00\x48\x24\x78\x9c\xed\x5c\x5b\x73\xdb\xb6\x12\x7e\xf7\xaf\xc0\ +\xe8\xe1\x9c\xb4\xe3\x5a\x92\xaf\x49\x8e\xac\x4e\x62\xd7\x49\x3a\ +\xc9\x69\x5a\xb9\x49\xdf\x3c\x10\x09\x89\xa8\x49\x42\x05\x40\x4b\ +\xea\xaf\xef\x2e\x00\x8a\x14\x45\xdd\x2d\xc9\x71\x35\xe3\x19\x8b\ +\x00\x88\x5d\x2c\xbe\x5d\xec\x2e\x56\x6a\xfc\x38\x88\x42\xf2\xc0\ +\xa4\xe2\x22\xbe\xac\xd4\x8f\x6a\x15\xc2\x62\x4f\xf8\x3c\xee\x5e\ +\x56\x7e\xbf\xbd\xf9\xe1\x65\xe5\xc7\xe6\x41\x23\xe1\xd9\xa0\x53\ +\x18\xd4\x3c\x20\x0d\x2f\xa4\x4a\x35\xdf\x25\xfc\xf5\xeb\x6b\x4e\ +\x43\xd1\x85\xff\x61\xb7\xc5\xb4\x86\x97\xd5\xb5\xa4\x1d\xdd\xa8\ +\xda\x41\x30\xba\xcf\xfd\x2e\xd3\xc4\x3c\x5f\x56\x7e\xfd\x6a\x1e\ +\x2b\x24\xa6\x11\xbb\xac\xcc\x9c\x04\x89\x91\x46\x4f\x8a\x1e\x93\ +\x7a\xe8\xde\xe8\x32\x11\x31\x2d\x87\xa6\x93\x34\x24\xf3\xb4\xf9\ +\x44\x1a\x83\x66\xad\x51\x1d\xb8\x87\x21\x3e\x0c\xdd\x03\xb0\xa0\ +\x83\xe6\xd9\xc5\x59\xa3\x6a\x3f\xda\xe6\x80\xf1\x6e\xa0\x9b\xe7\ +\xc7\xaf\x1a\x55\xf7\xd9\xcc\x59\x4d\x27\x6d\x54\x53\xe2\x65\x9c\ +\xf4\x79\xec\x8b\xfe\x2d\xd7\x21\x73\xcc\x28\x2d\x81\xf9\xe6\x87\ +\xa8\x27\xa4\xae\xfe\x34\xc0\x7f\x8d\xaa\x6b\x9d\x9c\x2f\xa4\x43\ +\x91\x64\x92\xf9\xf2\x56\x0c\x3e\x9a\x26\x37\x5d\x81\x9e\xea\x51\ +\x0f\x26\xaa\x38\xee\xe3\x24\x6a\x33\xd9\x3c\x6f\x54\xdd\x27\xcb\ +\x7b\x9e\xc2\xc4\x14\x11\x95\x5d\x1e\x17\x66\x78\x35\x73\x06\xae\ +\x59\x94\x89\x31\xbf\x93\xef\xa4\x48\x7a\xc0\xf3\x68\x2f\xdd\x73\ +\xfd\xd8\x11\x98\x20\xaf\x33\x59\xe5\xc4\x75\xfd\xc7\x0d\xe9\x08\ +\x19\x51\x4d\x44\x4f\x03\xd2\x54\x5e\x66\x93\x2c\xcd\x97\xdc\x5c\ +\xe1\x4d\x95\x5f\x19\xb5\xd9\x52\x9c\x2a\xc8\xf2\xa9\x32\x71\x96\ +\xac\xe3\xfd\xe4\x3a\x16\x58\xc9\x8c\xb5\x94\xb1\x30\x7f\x3d\xd9\ +\x84\xb5\x05\x27\x1c\x5b\xd5\x24\x52\x3e\xd2\x36\x0b\x53\x98\x68\ +\x36\xd0\xa6\xa1\x7e\x77\x92\xa7\x39\x89\x16\x18\x38\x36\xa0\xa0\ +\x60\x44\xe9\x61\xc8\x0a\x58\x99\xca\x23\x31\xba\x0f\x5c\xe5\x97\ +\x32\xce\xf7\x9c\x65\x18\x5b\xf5\x59\xb2\xce\x95\x88\xda\x22\x07\ +\xfc\x2e\x76\xf4\xa0\xc3\xc3\x8e\x36\x74\xcc\x5c\x96\x10\xe1\x2d\ +\xef\x95\xaf\xec\x36\xe0\x8a\xc0\x9f\x0e\x18\x01\x33\x17\x08\x9f\ +\x78\x81\x10\x8a\xf9\xa8\x22\x84\x9b\x85\xc3\x40\x02\x0f\x5a\xd2\ +\x58\x85\xd4\x3c\xa2\x0e\x89\xf6\x9f\x60\xb7\x88\x27\x42\x1c\x19\ +\x6b\x41\x6e\x24\x63\x57\x6f\xae\x8f\xc8\xc1\x87\x8e\x6b\x8f\x68\ +\xaf\x87\x2f\x00\x0d\x37\xf1\x21\x01\xc0\x91\x28\x51\xda\xb5\x10\ +\x5a\x18\xdb\xe1\x21\x83\xa6\x58\x53\x1e\xe3\x33\xcd\x48\x8b\x98\ +\x68\xda\x86\x6e\x1d\x80\xfa\xf6\x79\x18\xe2\x40\x38\x31\x1c\x1f\ +\xca\x32\x12\xf2\x98\x19\xcb\xab\x8e\x0e\x16\xde\xb0\x09\xc9\x79\ +\x89\x94\x2c\xd6\x1f\x62\x9f\x0d\x0a\xe2\x9b\x8e\xd7\x45\x27\xc7\ +\xfd\xfb\x29\xc6\x83\x05\x70\xe5\x2b\xa6\x2f\x2b\xb5\x02\x11\xcf\ +\x31\xee\x0f\x3a\x0e\x7a\xde\xaa\x4b\x41\x6a\x9f\xa9\x0e\xe6\x13\ +\xfb\x24\xfc\x6a\x7a\xa4\x2e\x4c\xad\x00\xe4\x45\x74\x6b\x04\xc1\ +\xff\x8b\x98\x91\x17\x1d\xaa\x34\x53\xfa\xbb\xb2\xdd\x9a\x46\xb5\ +\x5a\x24\xbb\x16\x1f\xbf\x03\x12\x7d\xd6\xa1\x49\x98\x62\x9a\xc6\ +\x7e\x86\xa4\xdd\x31\xf6\x8b\xe4\x60\x2e\x69\xf8\xb4\xb8\xba\x1a\ +\xa9\x2c\xd8\x8a\xbc\xca\xed\x90\x25\xc9\xa8\x66\xa4\x47\x25\x45\ +\x97\x8d\x7b\xce\x44\x15\xcf\xf7\xed\xb3\xd4\xba\x67\xda\x0b\xd8\ +\x5a\x8c\xcc\x3d\x4f\x1a\x55\x7b\xbc\x67\xde\x40\xbe\x7b\x61\x4f\ +\xc0\x2d\x2a\x10\x92\xff\x8d\x36\x38\x9c\xf4\x10\x96\x39\x7e\x43\ +\x7c\xb8\xbb\x58\xf1\xe4\xfd\x44\x07\xa4\xd5\x43\x6c\x91\x16\xeb\ +\x46\x60\x8d\x77\x70\xfe\xb6\xe0\x54\x2a\x3b\x7e\x15\xb4\xc3\xe9\ +\x7b\x77\x3c\x73\x71\x11\x1d\xf0\x28\x89\x5a\xfc\x6f\x56\x5c\x23\ +\x34\x15\x60\x63\xc3\x85\xf3\xda\x58\xe0\x30\xea\x75\x41\x43\xfd\ +\xfc\xe2\xe2\xe2\xb8\x7e\x36\x16\x45\x64\x8b\x2c\x4e\xbb\xd8\x09\ +\x31\xd3\x4d\xf8\x1a\xb0\x98\xb0\x41\xea\x0c\x28\xb3\x23\x0a\xd5\ +\x1e\x1c\x81\x43\xf4\x1e\x86\x84\x4a\x66\xcf\x69\xf4\xad\xc1\x26\ +\xf0\x98\xf4\x44\x38\x34\x23\x8f\x88\x71\x34\x1e\x68\x98\xb0\x91\ +\xbb\x61\xe5\x42\x42\x16\x77\x75\x40\x44\x87\x30\xea\x99\xff\xd8\ +\x9b\xbe\x4a\x94\xdd\x76\x98\x02\x7c\x8a\x9a\xa1\x15\x9b\x11\xfd\ +\x40\x80\x1f\x60\x59\x31\x73\x1a\x55\xf3\x09\x55\xe0\x30\x00\xdf\ +\x14\x45\x93\xbe\x7e\xb4\xba\x17\x60\x98\x2e\x3f\xfe\xcf\xb6\x72\ +\xfc\x83\xa0\x9c\xc0\x53\x0d\x78\x9a\x6e\xc0\x8e\x0d\xd4\x98\x77\ +\xbf\xbc\x89\x5a\xd1\x40\x5d\x4d\x78\xae\x3b\x30\x50\x37\x40\xf6\ +\xca\xf8\xd2\x72\xc2\x48\x21\x4b\x9e\xeb\x9b\x69\xa6\xc0\xd7\x5e\ +\xd2\x4c\x9d\xd4\x66\xdb\xa9\xda\xf6\x0c\xd4\x6d\xc0\xca\x82\x88\ +\x4e\x21\x6c\x01\x4f\x7a\x4a\x9c\xb0\xba\x7d\x58\xce\x91\x77\xec\ +\x59\xa0\xec\xf5\xb8\x4c\x8f\x2f\x16\xd7\xe3\x2c\x44\x0e\x98\x77\ +\x5f\x1a\x22\x63\xc7\xfc\x43\x7a\x26\xb8\x38\x1e\x49\x36\x4e\x4e\ +\x62\x33\x21\x46\xb1\x68\x13\x54\x35\x32\xff\x48\x5f\xc4\xff\xd5\ +\xa4\xcd\x5c\xc4\xcc\xfc\xd5\xf1\x34\x37\x0d\x61\x29\x62\x18\xe0\ +\x73\x38\x0f\x54\x49\x06\x6b\x49\x28\x2d\x0e\x5f\xa4\xbd\xc7\x6d\ +\x39\x6e\x8f\x37\x82\xdb\x39\x39\xab\x05\x71\x3b\x42\x6d\x8f\xc2\ +\xeb\x04\x73\x7a\x2c\x8d\x8e\x6c\x1a\x25\x87\x5d\xf0\xeb\xc4\x06\ +\xf1\x6b\x25\xbb\x35\xc8\x5a\x72\x7b\xd0\x96\x83\xf6\x74\x23\xa0\ +\x9d\x13\xee\xcd\x02\xad\x99\xdc\xe1\xb6\x63\x52\x85\x7d\x1a\x6b\ +\xe3\xf1\xc7\x22\xfe\x01\x67\xf0\x49\x3b\x14\xde\xbd\x22\x2f\xda\ +\xac\xcb\x63\x93\x23\xec\x73\x88\x21\x28\xf9\xfe\x3b\x0c\x4a\xb6\ +\x87\xe5\xef\x2d\x27\xdb\xc2\xb2\xd2\x54\xa6\x14\xf7\x78\x2e\xc3\ +\xf3\xcb\x8d\xe0\xf9\xec\x71\x8d\x70\x6a\x78\x3b\x52\x44\x06\xd9\ +\x0a\xe6\x41\xbb\xc8\x64\x66\x8d\xff\x14\xe0\x9c\xfa\xd6\x4f\x35\ +\x9b\x40\xde\x9a\x9d\x07\xcf\x23\x91\x06\xf3\xf8\xa6\xcf\x21\x36\ +\xa4\x43\x62\xf2\xa7\xf2\x90\xb4\x41\x5c\x11\xbd\x77\xdd\x18\x5d\ +\x2b\x05\x81\xb5\xe2\xe1\x90\x30\x9f\x9b\xe4\xf9\x26\xf4\xc1\x5c\ +\xc6\xa5\x4b\x30\x3c\x6f\x51\x33\xba\x48\xfc\xa3\xa1\xbd\xd7\x8b\ +\x72\xbd\x38\xdb\x88\x5e\xbc\x5a\x5d\x2f\xf0\x86\x28\xd5\x87\x8e\ +\x64\xcc\xa3\xbe\x85\x3e\xec\x38\xda\x70\x84\x3f\x26\xe2\x79\xec\ +\x71\x9f\xc1\xc7\x54\x69\x0c\xb8\xfa\x5c\x62\x56\xe9\x2d\xeb\x53\ +\xc9\x0e\xad\x86\x79\x14\x2f\x87\xee\xf1\x3e\xa9\x1f\x40\x7c\x75\ +\x74\xb4\x46\xd6\x67\x3a\xd2\x7f\x06\x96\x48\x5a\x15\xb0\x15\x78\ +\xa3\x28\x32\x82\x7b\x7c\x97\xe1\xfb\x7c\x13\xf8\x5e\x0b\xdd\x13\ +\x56\x9f\x02\xb8\x53\x10\xe7\x6e\x37\x3b\xe0\x8a\x67\x56\xdf\x26\ +\x59\x6d\x1a\xf3\xc4\x37\x69\x50\x33\x60\x13\x48\xb6\x05\x23\xe4\ +\xe4\x7a\xc4\x16\x10\x4d\x29\x92\x88\xa9\x29\x37\x16\x1b\xc9\x8b\ +\x00\xb5\x3d\xb6\xcb\xb1\x5d\xaf\x6f\xc4\x78\xbf\x7c\x5c\x78\x67\ +\x1e\xb7\xcd\x88\x20\xa0\x91\x31\xe3\xdf\x68\x1a\xfb\x54\xfa\xce\ +\x91\xc1\x11\x04\xb3\x80\xf0\x56\x0c\x7e\x0b\x98\x7e\x97\xf6\xc7\ +\x46\x7b\x9d\x10\xd0\x07\x86\x77\x08\xd8\x8a\xd5\x06\xbe\xf0\x92\ +\xa5\xee\x7f\x96\x50\x04\xbc\xfa\x1d\xb1\xd8\x01\xd1\x5b\x3e\x4c\ +\xf6\x10\x17\xb3\x2d\x25\x68\x69\x1f\xf3\xaf\x7b\x3d\x98\xa2\x07\ +\x9b\xc9\xb0\xd4\x6b\x8f\xab\x08\x01\x35\x77\xbd\x23\x93\xee\x0a\ +\x54\x52\x5f\x5e\x81\xa2\x84\xcc\x7a\x30\x1b\x8c\x4c\x0d\x17\xa4\ +\x2d\x12\x44\x35\x67\xc6\xb6\xaf\x49\x73\x09\x30\x5b\x63\x70\x3d\ +\xe8\xbc\xa7\xee\xe2\x7b\x0f\xe9\x52\x48\x2f\x71\x69\xb5\x0c\xa4\ +\xeb\x8f\x0b\xe9\x3e\x5e\xba\x8e\x6e\x73\xad\x6d\x06\x2f\x1b\x6f\ +\x4e\xb0\x66\x06\x03\x55\x77\x0b\x9c\x82\x5e\xb2\xd8\x67\xd2\xfa\ +\x31\x5e\x68\x0a\xca\x0c\xfa\x6c\xa2\x46\x9b\xeb\x1a\x89\x75\xaf\ +\x64\x6a\xd1\xc8\xba\x8a\xf0\x9b\x61\x21\xc7\xb6\x21\xbd\x26\xb9\ +\x25\x74\xc0\x8a\xe0\xb3\x23\xff\xd5\xd2\x7d\x8e\x6a\x30\xde\x39\ +\x36\x57\x6e\xdc\x4a\x95\xbd\x77\x4b\xd6\xf6\xb6\xbe\xbc\x7b\xbc\ +\xda\x5e\x47\x29\x97\x82\xff\xd6\xab\x7c\xd3\x15\x8d\x65\x7d\x9f\ +\x6f\xbd\xef\x9c\xb4\xdd\xce\xeb\x7d\xcd\x35\x8c\x9c\x38\x1b\x5a\ +\xa6\x79\x2c\xa4\x9d\xe4\x1e\x46\x83\x37\x6c\x4a\x62\x0b\x8b\x60\ +\x20\xd2\xe6\xaf\xfa\xf5\xeb\xf7\xa3\x19\x1b\x55\xd3\xb8\xb4\xd1\ +\x41\x37\xf8\x3d\x78\x2d\xd3\x8d\xce\xd4\xe2\x80\xd3\xd9\xb5\x01\ +\xc7\x6b\x15\x07\xc0\x30\x23\xa3\x25\x64\xbd\x6a\x6d\xf5\x3a\x17\ +\x70\x0b\x57\x57\xa3\xd9\x9a\x5e\x4e\xfd\xed\x57\x30\xab\x87\xee\ +\xbe\x82\x79\xe3\xc5\xa6\xff\xba\x0a\xe6\x5d\x7b\xef\xaf\x16\x77\ +\xde\xcb\x8a\x62\xe7\x94\xa4\xcc\xcb\xdb\xb5\x9e\xc8\xd7\x51\x40\ +\xb9\xef\x6c\xda\xf2\xce\x28\xf9\xdd\xfa\x5f\x4b\x31\x4b\xc3\x9c\ +\x90\xf1\xe7\xb0\x92\x0b\x73\xfe\x12\x18\xb4\xa1\x48\x56\x8a\x4a\ +\x5d\x6d\xf5\xf3\x30\x92\x63\x72\x7c\x9e\xc6\xf2\xd6\x95\xe3\xc1\ +\x19\xf8\x02\x0f\xc1\x9e\xc4\x7b\x9e\xff\xd0\xa8\xf7\xbf\xf4\x32\ +\x73\x87\x26\xf4\x37\xda\xb7\x6c\x5d\xbd\xf9\xb4\x16\x1b\xbb\x36\ +\x4d\x63\x49\xad\xc7\x4b\x2c\xcc\xf6\x49\x97\xa9\x21\x47\xcd\x7e\ +\xe0\xac\xaf\x0e\xf1\xbe\x9a\x99\xdb\x91\x7e\x80\x1a\x6e\x8e\x06\ +\x21\xef\x09\x7e\xb7\x84\xa2\x2f\x44\xda\x21\xf5\xee\x0f\x8d\xd3\ +\xd4\x66\x5a\x83\xcf\x2c\x19\xf5\x69\x9b\x87\x1c\x88\xd3\x2e\xc5\ +\x34\xb2\x7b\xbd\x0d\x43\xf1\x42\x38\xf6\x37\x92\x5e\x1b\xe1\x37\ +\xc7\xad\x3b\xd7\xcc\xa5\x37\x50\x5f\xc3\x14\xd9\x84\x4b\x81\x72\ +\x1b\xc4\xda\xd4\x32\x01\x8b\x60\x3e\x6e\xd2\x08\xb5\x1e\xba\x1f\ +\x31\x59\xf2\xd6\x2e\xe4\x69\x5a\xa0\xa7\x9b\xae\x18\x05\x0b\x8b\ +\xa5\x2b\x7e\xb9\x7a\xf3\xf8\xe9\x8a\x4c\x47\x9f\x4b\xba\x62\xac\ +\x22\xf8\x9b\x4f\x57\x2c\x61\x6e\x4f\x57\x37\xb7\x33\xea\xe8\x28\ +\x18\x4f\x45\x5e\x9c\x5c\xdb\xbb\xe7\xb2\x92\xb9\x8d\x54\x4e\xb8\ +\xb4\x0a\x82\xde\xb0\xb0\x95\x2c\xac\xf0\xa8\x23\xb6\xb7\x65\x66\ +\x2f\xf2\x39\x27\xbc\x97\xe2\x5e\x9a\x71\x9a\x66\xbb\xca\x52\x4d\ +\x59\x96\xe9\x8b\x9b\x63\x2c\xc7\x34\x69\xb7\x96\xc8\x2c\x8d\x27\ +\x95\x5c\x3e\xe9\x78\x22\x9f\x94\xa6\x92\x4e\x27\x52\x49\x63\x59\ +\xa4\x22\x2b\x63\xb9\xa3\x4c\x48\x39\x49\xe6\xc4\xe8\x8c\x53\x1a\ +\x55\x3b\x63\x73\x59\x39\xaf\x10\x6b\x26\x2e\x2b\xf5\x7a\xa5\x8a\ +\x23\x7b\x7c\x10\xd1\x5e\x27\x89\x3d\x14\x54\xf3\xaf\xcf\xe6\xf9\ +\x46\x8a\xe8\x13\x8f\x58\x4b\x24\xd2\x83\x03\xbc\x30\x0a\x7f\xdd\ +\x24\x51\x5a\x44\x96\xa2\x32\x9c\xe4\x5b\x2c\x97\xb9\x5f\x40\xc9\ +\x7d\xd7\x27\xfb\xd1\x13\xdc\x8f\x81\x66\xe0\xf2\x34\xdd\x0f\x9e\ +\xc0\x6e\xb8\x86\x03\x2b\x2a\xea\xc3\x92\x61\x86\x2a\x4e\x60\x7f\ +\x01\xe5\x28\x40\xc1\x99\x0e\x23\x80\x22\xdd\xd9\x8c\x14\xbe\x78\ +\x54\xca\xcc\x24\xc7\xd3\xb8\xc2\xd9\x2c\xe7\x6a\x7d\xb6\xdc\x17\ +\x36\xcb\xe5\x33\xea\xdc\x0a\x2b\xa9\x8d\x2f\xe7\x25\xeb\xdd\x0e\ +\x33\x2e\x72\x9f\xc2\xcc\xa8\x77\x7d\x66\xc6\x1b\xcc\xef\xf2\x48\ +\xa6\x8c\x0e\x28\xa3\x2d\x9e\x88\x63\x66\x74\x00\x9f\x1b\xd5\x84\ +\x37\x0f\xfe\x01\xbd\x89\x17\xfc\ +\x00\x00\x0f\xe1\ \x00\ -\x00\x94\xbb\x78\x9c\xed\x1d\xfd\x73\xda\xb8\xf2\xf7\xfc\x15\x9a\ -\xfc\xd0\xe9\x9b\xc9\x85\x90\xe6\xa3\x69\x09\x37\xfd\x6e\x67\x7a\ -\x77\xbd\x92\xf6\xde\xbd\x5f\x6e\x84\x2d\x40\xaf\xc6\xa2\x92\x08\ -\xe1\xe6\xfd\xf1\x6f\x57\x92\xc1\x36\xc6\x04\x04\x98\x5c\xe9\x74\ -\x26\x58\xb2\x57\xab\xd5\x7e\x69\x77\x2d\x37\x7e\xbe\xeb\x47\xe4\ -\x96\x49\xc5\x45\x7c\x7d\x58\x3f\x3e\x39\x24\x2c\x0e\x44\xc8\xe3\ -\xee\xf5\xe1\x97\x9b\xb7\x3f\x3d\x3d\xfc\xb9\x79\xd0\x18\xf2\xe9\ -\x4d\x67\x70\x53\xf3\x80\x34\x82\x88\x2a\xd5\x7c\x37\xe4\xcf\x9e\ -\xbd\xe6\x34\x12\x5d\xf8\x1b\x75\x5b\x4c\x6b\x78\x58\xbd\x96\xb4\ -\xa3\x1b\x35\x7b\x13\xdc\x3d\xe2\x61\x97\x69\x62\xae\xaf\x0f\x7f\ -\xff\xc3\x5c\x1e\x92\x98\xf6\xd9\xf5\x61\x29\x10\x1c\x8c\x34\x06\ -\x52\x0c\x98\xd4\x63\xf7\x44\x97\x89\x3e\xd3\x72\x6c\x3a\x49\x43\ -\xb2\x40\x9b\x5f\xa4\x71\xd7\x3c\x69\xd4\xee\xdc\xc5\x18\x2f\xc6\ -\xee\x02\x50\xd0\xbd\xe6\xf9\x15\x34\xd9\x9f\xb6\xb9\xc7\x78\xb7\ -\xa7\x9b\x17\xa7\x57\x8d\x9a\xfb\x6d\x60\xd6\x12\xa0\x8d\x5a\x32\ -\x78\x11\x26\x23\x1e\x87\x62\x74\xc3\x75\xc4\x1c\x32\x4a\x4b\x40\ -\xbe\xf9\x8e\xc5\x4c\xd2\x88\x28\x37\x99\x46\xcd\x75\xcc\x82\x8c\ -\xe8\x58\x0c\xa7\xc4\xf9\xfa\x52\xdc\x7d\x34\x4d\x0e\x62\x6e\x48\ -\x35\xa0\x01\x00\x3a\x74\x13\x88\x87\xfd\x36\x93\xcd\x8b\x46\xcd\ -\xfd\xb2\xe8\xa7\x47\x98\x01\xd1\xa7\xb2\xcb\xe3\x1c\x84\xab\x52\ -\x08\x5c\xb3\xfe\x94\x92\xe9\xc5\x7c\x27\xc5\x70\x00\x38\x27\xcb\ -\xd9\x4d\xae\xed\xed\x33\x83\xeb\x29\xb1\x0a\xe8\x65\x16\x9d\xb4\ -\x0a\xa8\x36\x8b\x54\x29\xed\xdc\x68\xc0\xb8\x9a\x07\x34\xb2\xad\ -\x7f\x9d\x4e\x07\x9e\xce\xa8\x00\xd0\xfb\x19\x40\x3d\x21\xf9\xdf\ -\x22\xd6\x13\x50\xf5\xab\x09\xac\x3c\xb4\x59\x22\x7d\xa4\x6d\x16\ -\x25\xa0\x22\xbc\xc8\x3e\x5f\x40\x26\x76\xa7\x33\x37\x4c\x48\x65\ -\x49\xc4\x63\xcd\x64\x87\x06\x8c\xf4\x45\xc8\x72\x84\x2a\xa6\x96\ -\x6d\xb4\x98\xa5\x50\xaf\x65\x71\x5f\x30\x15\x23\xad\x9f\x24\xeb\ -\xbc\x12\xfd\xb6\x48\xaf\x3b\x76\x0c\xa0\x23\xc0\x8e\xb6\xb8\xfb\ -\xeb\xac\x7c\x82\x42\x44\x37\x7c\x50\x3c\xc7\x9b\x1e\x57\x04\xfe\ -\xeb\x1e\x23\x5f\x3e\x98\x29\xc2\x8c\xc9\xa8\xc7\x83\x9e\x69\xb4\ -\x44\x80\xf6\x61\xc4\xc8\x88\x47\x11\x19\x09\xf9\xed\x19\xb9\x01\ -\xa8\x6d\x2a\xed\x13\xa6\x7d\x10\x21\x91\x68\x94\xf0\x56\x22\x91\ -\x08\x8f\xc2\xd5\x80\x4a\xaa\x19\xd1\xf6\xc1\x23\x1c\x03\x40\x6a\ -\xaa\xbe\x65\xe1\x0c\x15\x33\x23\xbf\x95\x8c\xbd\x7a\xf1\x9a\xdc\ -\xc0\x1d\xb7\x9c\x8d\x88\x1a\x2b\xa0\x18\xe9\x08\x69\x46\xe1\x5a\ -\xe1\xbd\xd2\xae\x10\x0d\x34\xe8\xcd\x7b\x2f\xcf\x0c\x95\x90\xa0\ -\x6f\x62\xd4\x75\x44\xe9\x10\x70\xbf\x3e\x3c\xc9\x91\x2c\x70\xb0\ -\xbf\xf0\x5f\x0c\x27\x04\x3e\x63\x7d\xa2\xba\xb7\x78\x28\x18\xa8\ -\x96\xe8\xf8\x7b\x8f\x96\xe3\xab\xfb\xb0\xfc\x94\x1f\xec\xea\x14\ -\xd1\x71\xde\x70\xb5\xfc\x78\x7e\x08\xb8\xd5\xf6\xc1\x60\xa1\xec\ -\x35\x6a\x56\x0d\x4d\x74\x54\xa6\xdb\x5b\x63\x9d\xfa\x29\xac\xd3\ -\x55\xf5\x15\xeb\xd0\x61\x04\xa0\x45\x24\x0a\x57\x70\xe3\x8a\x0a\ -\xc6\x7d\x39\xd4\x5a\xc4\x05\xba\x0a\xfa\xda\xb6\x6f\x65\x65\x85\ -\x5a\x21\x4c\x4f\xd2\xe8\x82\x18\x54\x83\x68\xff\x17\xdc\x88\xbc\ -\x19\x2b\xe3\x99\xdc\xb8\x06\x5c\x5e\x08\xb1\x2d\xc7\xa5\x92\x85\ -\xe8\xec\xe0\x9f\x6c\x47\x17\xb4\x55\x8c\x5d\xf6\x47\xb6\xb3\x1d\ -\x0d\x19\xf6\x99\xbf\x59\x86\x9e\x19\x64\xed\xea\xca\xb1\xc3\x6e\ -\x6a\x2b\x6f\xee\x2b\x12\xa0\x05\xf6\x70\xae\x00\xb5\x62\x3a\xd8\ -\x75\xe9\x59\xa4\x1d\x96\x97\x1f\x85\xb3\x56\x63\xf0\x25\xa2\xbd\ -\x00\x65\xd0\x77\xb4\x40\x02\xfd\x78\x42\xb4\xaa\xd7\xfc\x4a\xc4\ -\xf0\x6b\x68\xdc\xb1\x9d\x17\xa6\x27\xeb\xf1\x9c\x67\x85\xca\x19\ -\x24\xd2\x66\x70\x2f\x09\x25\x1d\xc5\xce\xe1\xe5\x48\x95\x14\x89\ -\xd0\xf1\x3d\xde\x8e\xdc\x9d\x9d\xcd\x17\xbc\xfa\xe9\x79\x89\xe8\ -\x9d\x9e\x9f\x57\x66\xbd\xa6\xb4\xfa\xf1\x84\x70\x01\x7f\x2e\x74\ -\x05\x23\x0e\xde\x11\x46\x61\x2a\x90\xc1\xd6\x80\xc7\x45\xdb\x56\ -\x05\xed\xed\x69\xd8\xa2\x78\x66\xf7\x35\x63\x93\x09\xae\xcf\x15\ -\xbc\xa5\xc0\xe7\xb9\x91\x5d\xc0\xe6\x34\x13\xba\x59\x0a\xea\x12\ -\x2c\x9f\x5a\xb4\x07\xca\xea\x1b\xde\x5f\x3d\xf1\xdc\x5f\x9d\x78\ -\x99\x36\xca\x8d\xd2\xde\xc9\x48\xd0\xb9\x8f\x3d\x63\x64\x32\x41\ -\x34\x5a\x30\x47\xde\xe1\x4c\x92\x6f\x6c\xbc\x95\xb8\x0a\x0c\x18\ -\x24\x08\xec\x2a\xeb\xfb\x05\x37\x54\x8f\xe3\x60\x55\xc5\x56\x02\ -\x2d\xa3\xea\x46\xa7\x91\xd7\xd4\x57\x10\x23\x8c\xe0\x03\xff\xe6\ -\xb5\x48\xcb\x34\x2f\x90\x15\xb8\x9b\xc1\xcd\xe8\x76\xe4\xb8\x87\ -\x81\x09\x68\xfe\xae\x9f\x3d\x7b\x3f\x81\xd8\xa8\x99\xc6\xa5\x59\ -\x55\xf1\xbf\xd9\x7b\x1e\xeb\xf9\xac\x8a\x77\xe4\xc8\x69\xb3\x2a\ -\x67\xd9\xfc\xca\xa4\xd7\xe5\x56\x4e\x4f\x32\x69\x96\x29\x5a\x79\ -\x80\x73\x54\x96\x25\xdd\x5a\x7d\x99\xd3\xba\xcf\xb6\x7c\x57\x35\ -\xee\x85\x9f\xc6\x55\x6e\x6e\x6b\xd0\xb4\xc1\x50\x4a\x60\xd9\x0f\ -\x71\xc8\xee\x8a\xdd\x97\xfa\x56\xdc\x17\x98\x0d\xce\x6a\xaf\xc1\ -\x6d\xeb\x5e\x83\x4f\x1b\xd6\xac\xc1\xcb\x65\x6f\xaf\xc1\xd7\xae\ -\xc1\x57\xcd\x4c\xbc\x88\xf4\xce\x2a\xf0\x4b\x3f\x05\x4e\xed\xd4\ -\xb6\xa2\xbf\xb7\xb3\xfd\x84\xd9\x18\x41\xdf\xab\xef\xbd\xfa\xde\ -\xa5\xac\x6a\x3d\xcd\x45\xab\xd4\x81\xf8\x6d\xfb\x5d\xb8\xd6\x54\ -\xdd\x98\x47\x2a\xd0\x66\x1f\x79\xcc\xde\x84\x5c\xcf\x68\x33\x0c\ -\x19\x31\xe8\xf0\xc9\x0e\x15\x05\xb4\xa7\xb3\x35\xf1\xb5\x4c\xe0\ -\x3a\x29\x0e\x5b\x5d\xe3\xdd\x8f\xe4\x5b\x89\x3d\xa4\x67\x66\x26\ -\x6d\x57\x78\x37\x75\x60\xd5\x92\x78\x76\x7f\x41\x9c\x1a\xe2\x1e\ -\x0b\xbe\x15\x1a\x62\xec\xf0\x8a\x07\x1b\x08\xc0\xb6\xc8\xbe\x1d\ -\x02\x18\x92\x11\x8d\x35\xd1\x62\x52\x4a\x64\x12\x07\xb5\x54\xac\ -\x58\x8a\xbe\xe9\x70\xc5\x48\x84\xaa\x84\xe5\x37\xc1\xcd\x2d\x7a\ -\x0b\x38\x58\xf3\xee\x72\x44\x34\x0e\x53\xb1\x6b\x1a\x48\xa1\x14\ -\x51\x4c\x61\xf1\xa7\x47\xec\x7a\x99\xac\x26\x20\x25\x62\x76\xc7\ -\x77\xd6\xd4\x57\xcd\xe6\x97\x9b\x60\x73\x9f\x10\xed\x87\x8e\xe3\ -\x72\x45\x0c\x38\x16\x1e\x01\x3b\x0d\xc6\xa9\xe2\xb9\x36\x03\x27\ -\x74\xa0\x13\x8e\x02\x2f\xb7\x0f\xac\x76\x44\x04\x70\xbb\x1c\x71\ -\xc5\x92\x26\x65\xef\xa7\xd1\x88\x8e\x81\xf3\x34\x95\x58\xea\x48\ -\x62\xf1\xd3\x04\xe2\x26\x44\xe1\x5d\x24\xda\x34\x22\x6b\x18\xc3\ -\x51\x20\x37\x4c\x1b\xe8\xd7\x04\x45\x0e\x80\xcd\xcf\xcd\xda\x8c\ -\xc1\xb8\xbf\xc3\x95\x80\x55\xcb\x4f\xfd\xe9\x46\x04\xc8\x23\x67\ -\xff\xab\x90\x7d\x1a\x45\xe3\x23\x02\x84\x64\xd2\xb0\x21\xa6\x3a\ -\x5c\xce\xf0\xc8\x19\x8b\x01\x67\x8a\x20\x72\x8a\x45\xd0\xce\xc2\ -\x63\x92\x88\x9e\x18\x18\xdf\x27\x2d\x81\xf8\x4c\x9b\x82\x64\x25\ -\x39\xff\x44\x10\x93\xa7\x41\xae\x94\x66\x34\xf4\xc8\xf2\x97\xd8\ -\x16\x33\x48\x16\x81\xcc\xe4\xb6\x63\x4c\x0c\x16\x2f\x01\x89\xdf\ -\x92\xf4\xeb\x5e\x26\x8a\x64\xe2\x7c\x23\x22\xf1\x74\xbd\x36\xc5\ -\xb8\x50\x69\xeb\x80\x41\x6a\x70\xa7\xc0\x59\x50\x3a\x25\x2f\xae\ -\xa2\x05\xab\x5b\xa0\xd5\x08\x49\x2c\x74\xea\xf9\xb6\x0d\x70\x0f\ -\xcc\x33\x71\x34\x86\x07\x58\x4c\x00\x75\xf0\x73\xa0\xe9\xd5\xcd\ -\xe7\x8f\x1b\x11\x8a\x17\x59\xbc\x13\x74\x1f\x87\x5c\xd1\x76\x34\ -\x8d\xba\x63\xc0\xe6\x5f\x0f\xd9\x04\xd9\x05\x6a\xed\x70\xb8\x7d\ -\xed\x41\xdf\xf2\x1d\xee\x3e\xe8\xbb\xee\xa0\x6f\xdd\x33\x40\x2a\ -\x69\xc8\x87\x6a\x52\x69\x6a\x74\x01\xc8\xa4\x1a\xb0\x80\x83\x27\ -\x38\x10\x40\x48\x75\x8c\x6f\x22\x61\xf3\x89\xad\xe3\x11\x04\x44\ -\x55\xd3\x38\x60\xe4\x31\x8f\x3b\x3c\x06\xbc\x3d\x04\x75\x41\x6e\ -\x51\xd2\xb8\x5b\x45\x38\x67\x41\x85\xd4\x02\x56\x57\xc3\x4e\x87\ -\xe7\x23\xc5\x6e\x0e\x83\xbb\xed\x98\x7d\xa0\xde\x67\x4b\xbc\x07\ -\xaa\x7d\x36\xfd\x26\xc8\x12\x31\xcb\x25\xec\xbd\xc7\x0b\x5f\x45\ -\xf6\x7e\x22\x97\xc6\x68\x83\x09\x27\x22\x08\x86\x92\xd0\x2e\x45\ -\xd7\x35\xe5\xd8\xea\x1e\x98\x4d\x89\x41\x15\x1a\x1b\xc7\x97\xc7\ -\x21\x0f\x28\x3a\xb9\x36\x33\x41\x44\x87\x30\x98\x95\x47\x0c\x63\ -\x51\x21\x00\xbd\xe3\xfd\x61\xff\x21\x5b\x6d\x98\xc2\x8f\x64\xb2\ -\xf7\x06\x7b\x3e\xa5\x37\x91\xa5\xf5\xd8\x20\xff\x62\x85\x2b\x2f\ -\xcc\x68\x99\xdb\xcc\x84\xff\x79\xc8\x24\x48\x7b\xda\x9c\x6f\x42\ -\xd4\xe7\x20\xb2\x83\x46\xba\xbc\x08\xc1\x69\xab\xe2\x7c\xee\xd5\ -\xd5\xd5\xea\x19\xdd\xb2\x32\xe5\xb3\xed\x24\x8a\xad\x1a\x7b\x63\ -\x17\xe6\x81\xea\xb2\x0d\x3b\x00\x9b\x09\x81\x79\x14\x9d\x15\xd9\ -\xff\x4c\xe0\x0a\x64\x9a\xd9\x8c\x48\x07\x2e\x41\xd4\xa7\xb9\x91\ -\x63\xf2\x5b\x12\x46\x36\x61\xaf\x71\xfe\x89\x11\x07\x2c\xe5\x32\ -\xb9\xd1\x25\x54\xc2\x5b\x1c\x6b\xf2\x5e\xcd\xd8\x3f\x61\xb3\x04\ -\xab\x23\x29\xf6\xa1\xde\xf9\x6c\xee\x7b\x44\x83\xef\x2b\xcf\x78\ -\x26\x01\x3a\xb0\x83\x88\xc6\xbb\x79\x46\x43\xf9\x0c\x97\x60\x45\ -\xc7\xf6\x7f\x7c\xda\x55\x5e\xf4\x2b\x52\xf9\x55\x14\x2f\xe0\x76\ -\x4a\x64\xfe\xfd\x27\x79\x7c\x23\x06\x85\xa1\x86\x2d\x61\xf0\x1f\ -\xf2\xf8\xad\x04\xd9\xaa\x10\x87\x3f\x01\x87\x16\x38\x7a\x5e\x28\ -\x54\xad\x92\xea\x9b\x49\xdf\x7a\x14\xd8\x80\xe9\x9d\x98\x5c\x4a\ -\xba\x92\x87\x19\xfb\x69\x62\xe3\x2e\x96\xbe\x09\xfb\xf9\x45\x31\ -\x33\xe8\x43\xde\x39\x5b\xfc\x77\x53\xef\xad\x3d\xd2\x5d\x1e\x78\ -\xdd\x6f\x9c\xd7\x1e\xe9\x5e\x50\x9a\x31\xbf\xa8\x01\x45\xd9\x1d\ -\x17\x56\x81\xf3\xf1\x5a\x0c\xdb\x11\x9b\xb7\x4f\x0d\x4d\x6f\xb2\ -\x5b\xf5\x7a\xe1\x9d\x25\x93\x24\x6d\xa6\x47\x0c\xd4\x15\xa3\x41\ -\xcf\x6a\x32\x2c\x66\x5a\xef\x3b\xb7\x16\xf1\x66\xfd\xf8\x24\xfb\ -\xaf\x51\x73\x3d\x9b\x56\x34\xad\x64\x45\xff\x31\xfa\xe6\x1e\x32\ -\xb0\x60\x6b\x59\x12\xb0\xe1\xb1\x61\x02\x45\xd8\x2d\x5b\xa2\x2a\ -\x74\x7b\x91\x1a\x8f\xa8\x39\xce\xce\x4e\x2e\xc9\x6b\xdb\x23\x1d\ -\x60\x2b\x0d\x16\x51\x1e\x93\x16\xa6\xb3\x3a\x63\x02\xdb\x63\x46\ -\x7a\x62\x44\xfa\x34\x1e\x13\xf5\x7d\x48\x25\x53\x13\x71\xe9\x27\ -\x60\x3c\xb2\xde\x25\x71\x9f\xfa\xc9\x56\xe2\x3e\x28\x1b\x6f\xec\ -\x1a\x3f\x50\xc9\xd8\xb4\xeb\xe9\xf9\x82\xfa\x82\x72\x8e\xb9\x32\ -\xf8\x01\x0f\xc2\x8b\x31\xa9\x2a\x81\x1b\xb1\x94\x94\x44\x20\x8c\ -\x85\xaf\x1c\x54\x2c\x8b\xe5\x76\xc8\x45\x4d\x5b\xe0\x0a\xdc\xd7\ -\xdd\xb8\x28\x77\x37\xea\x17\x97\x97\x97\xa7\xf5\x73\x1f\xa7\x63\ -\x79\x73\x39\x8d\x5e\x87\xb0\x20\x7d\x1a\x99\xc3\x10\x79\xb2\x4c\ -\x81\x10\x32\xe4\x31\xd5\x0c\x0b\xcb\x98\x34\xce\x9c\x22\x8f\x31\ -\xb8\xce\xee\x8e\xc9\x13\x72\x4d\x4e\xc0\xfc\xd5\x3d\x52\xdf\x25\ -\xea\xe2\x62\x2b\xda\x62\xc2\x8b\x0f\x56\x5b\x2c\xeb\xb7\x97\xdb\ -\x99\xbd\xdf\xbe\x76\xbf\x7d\x55\x7d\xf9\x9a\xf7\x59\x6c\x2a\xee\ -\x1f\x80\xc6\x2c\xdf\x9c\x94\xe6\x99\x9e\x6e\x26\xcb\xb4\x15\xf5\ -\x11\xf2\xfe\xa7\x07\xaf\x41\x36\xed\x6f\x2c\x51\x55\x5a\x24\x40\ -\x0b\x2a\xbc\xe6\xca\xcf\x8d\x88\xc0\x68\xc5\xc1\x46\x23\xee\xe5\ -\xba\xb6\x5c\xf4\xf7\xba\xd6\x47\xd7\xae\x12\x60\xf8\x01\xdc\xba\ -\xe9\x5b\x92\x46\x39\xe2\x4b\x66\x21\xe6\x23\x3b\xc3\x38\xb0\x0e\ -\x9c\xee\x51\x6d\xde\x3d\xa3\x44\x27\x22\x72\x7c\xf0\x15\xef\x76\ -\x45\x54\x21\xef\x74\x60\xa7\x08\xed\xb8\x39\x8c\x60\xbf\x68\x92\ -\xb2\x16\x60\xb2\xc5\xd4\x92\x99\xca\x2a\xaa\x88\x02\xc4\x3c\xf6\ -\x8c\x25\xa5\x82\xb5\x55\x18\x3e\xee\x02\x3b\x68\x96\x27\x91\x8b\ -\xcb\x80\xcb\x5a\x5f\x53\xc4\xa6\x24\x2e\x04\xa3\x9c\x6f\x3f\x2e\ -\xa4\xa7\x2a\x6f\x6f\x8b\x8a\x6c\xd1\x85\x9f\x29\x5a\x35\xfc\x94\ -\x24\x82\xf1\x0e\x62\x75\x41\x75\x46\xa9\xfc\xe8\xd4\xbd\x51\xda\ -\xb6\x51\x5a\x90\xb4\xfb\x27\x98\xa5\x84\xff\xed\x78\xa6\x3c\x0f\ -\x45\x41\x99\x17\x8d\xc3\xc9\x3e\x67\x23\x11\xfa\x93\xe3\xd3\x0a\ -\x22\xf4\x38\xbd\x44\xd0\xf7\xaa\xb8\x70\x5b\xe0\xf9\x1d\x82\x55\ -\xd3\x61\x19\x5d\xdc\x01\x8c\xaa\xd3\xc4\xe5\x61\xc6\xbd\x26\x5e\ -\x8b\x26\x5e\x78\x2a\x89\x4f\xce\x71\xf6\x4c\x12\xe4\x28\xf3\xec\ -\xe4\x4b\x30\xf6\x7b\x33\x45\xfa\xee\xf8\xe0\x03\xe0\x4b\x63\x74\ -\xa7\x69\xea\x49\x35\x0c\x7a\xe8\x57\x3f\xfa\x3e\x14\xfa\xf9\x0b\ -\xc9\x69\x64\x7f\x62\x65\x46\x32\x90\xd2\xe3\x28\x7f\xab\xa2\xb1\ -\x4a\xee\x74\x2d\x4c\xf2\x8e\xfd\x79\x00\xf8\xd8\x5f\x7d\x11\x8b\ -\xe4\x36\x44\x92\x74\x68\x9f\x47\xe3\xa2\x71\x8f\xde\xb3\xe8\x96\ -\xe1\xb7\x93\x8e\xa6\xc0\xed\x43\x06\x55\xb3\x5f\xa0\x16\x99\x83\ -\x82\xe7\x9f\xbd\x14\x51\x68\xaf\x37\xf2\x2a\x25\x8e\xb1\x3a\x60\ -\x1a\xf1\x6e\x0c\xab\x31\x03\x1d\x84\x1c\xe5\xeb\x05\xf6\x7f\x46\ -\x1e\xfe\xdf\xe4\xf2\x46\x52\x0e\xac\xd3\x9d\xb6\x7c\x7d\xc5\x30\ -\x66\x0e\x68\x30\xbd\x3c\x0e\x4b\x1a\x15\xab\xb1\xf6\x26\xa5\xd0\ -\xa4\xd4\xfd\x4c\x4a\x7d\xd5\x33\x40\xa7\x36\xa5\x3f\x88\xf0\x33\ -\x52\xaa\xc7\x58\x85\x86\x65\xc1\x44\xf6\x96\x65\x2d\x96\xe5\x2d\ -\x8f\xd8\xab\x9e\x10\xa0\x63\x67\x8c\x4b\x07\xfa\x02\xdb\xb7\xc8\ -\xbf\xe7\xf1\xb2\xfe\xfd\x93\x93\x72\x02\x79\xd1\x67\xf9\x3c\x62\ -\x98\xe7\x7e\x77\xb6\x91\x29\x19\x0c\x30\x4c\x84\x45\x39\xd4\x9c\ -\x7f\xef\x2a\x08\x97\x14\x10\x3f\xa5\x69\xb1\xda\x2b\xcd\x39\x4a\ -\x73\x89\xf3\xb2\x0a\x94\xa6\x7f\x72\xeb\x11\xed\x0f\x9e\x93\x8f\ -\x8c\x86\xa0\xd0\xa8\x94\x62\x64\xdd\x89\x5d\x2c\x94\x5f\x5b\x99\ -\x3c\xef\xdb\x6f\x1a\xed\x2a\x57\xfa\x95\x68\xbf\x16\x9a\x9c\x57\ -\x57\x21\x8e\xc3\x5f\x56\x3b\xfc\x55\x75\xc3\xbf\xe2\x32\x80\x9d\ -\x41\x85\xf4\x77\x18\x54\xb8\x04\x0e\x83\x0a\x57\xa1\x05\xaa\xa5\ -\x57\xe5\x22\x58\x04\x2a\x5c\x03\x8b\x40\x85\x4b\xf0\x92\x06\xdf\ -\x54\xd5\xcb\x30\x45\xa2\xc2\xa5\x98\x22\xe1\xb5\x1c\x95\xbb\x2a\ -\x9e\xe9\x9b\xfa\x82\x1a\xdb\xb9\xde\xca\x57\x66\x3f\x1f\x9d\x8a\ -\xdd\xd8\xf8\x61\x6a\x27\xb5\x8b\xee\xca\xba\xbe\x20\x97\x9a\x26\ -\x96\x0b\x9a\x78\x57\x42\x09\x17\xd9\x32\xce\xbe\xee\xc1\x86\x27\ -\x4d\x24\x2a\x19\x49\xbe\xbd\x7d\x4c\x92\x6d\x32\x40\x8d\x58\x47\ -\x1f\xb9\x0f\x39\xbb\x41\x3e\xb4\x7e\xc3\x93\x1e\xe3\x90\x4a\x9f\ -\xc3\xe8\x96\xf3\xc2\x32\x0b\xf8\x4f\x74\xc5\x3e\x02\xa1\xc9\xe3\ -\x34\x6d\x2b\x7c\x75\xef\xf3\xbc\xcc\xe7\x03\xd1\x40\x9e\xea\x67\ -\xd5\xef\xe5\xbd\x88\x4c\x49\x2e\xec\xac\x5b\x5f\xdf\x11\x60\x34\ -\xbc\x04\x19\x12\xc1\xc6\x35\xcf\x82\x38\x53\xf9\xa1\xe5\xfb\x38\ -\xd3\x56\xe3\x4c\x0b\xaa\xd6\x1f\x74\x9c\xe9\x3d\xbe\xb9\x82\x27\ -\x37\x62\xba\x44\xb9\xd7\x59\x28\x98\x1a\xc9\x02\x2d\xe4\x18\x4f\ -\x7f\xd1\xee\xd3\x70\x28\x24\x48\x17\x95\x6e\x7c\x14\xe9\xe7\x03\ -\x2b\x39\x8f\xba\xfa\x39\x06\xad\xf0\xdc\xb6\x69\x45\x54\x92\x87\ -\x09\x43\x16\x62\x04\x0b\x4d\x52\xa2\x32\x5d\x0e\x07\x6e\x03\x73\ -\xe5\xa0\x6c\xe7\x1c\x6c\x37\x18\xb2\xc0\xae\xda\x27\x3f\x9d\x9c\ -\xed\xcc\xc0\x9a\xde\x97\xba\x29\x75\x87\xd3\xdf\x93\x84\x98\x7d\ -\x21\xee\xfa\xf0\xe2\x90\xf4\xa9\xec\xf2\xf8\xfa\xb0\x5e\x3f\xc4\ -\x12\xb2\xc6\x80\xdf\xf5\xe9\x20\xa9\x81\x6b\x7e\xff\x64\xae\xdf\ -\x4a\xd1\xff\x05\x9c\x95\x96\x18\x4a\xac\x99\xca\xdd\x05\xcf\x05\ -\x43\xa5\x45\xdf\x8e\xa8\x0c\x26\xe9\x16\x8b\xa5\x11\xd7\xa6\x91\ -\xd6\x94\xa4\x02\xfd\x4c\xbb\xb9\x05\x34\x3b\x8b\x43\xd5\xfc\xfd\ -\x0f\xf3\x1c\xa8\x3a\xd7\x70\x60\xa5\x09\x43\x5f\x08\xa1\x86\x00\ -\x5e\x73\x1a\x89\xee\x71\x0f\x85\xcb\x74\x18\x02\xe4\xc7\x2d\x47\ -\x24\xf5\x85\xe1\x62\x44\x3e\x0d\x55\x2f\xe9\x9f\x87\x8c\x45\x56\ -\xf9\x61\x92\x53\x60\x85\xd8\xcc\xd2\x6e\x1e\x4a\x08\x6d\x6d\x68\ -\xb9\xea\x9c\x62\x02\x4d\x3a\xb7\x82\xca\xa2\xf5\x9a\x5d\xd4\xed\ -\xa0\xe5\x0e\x1c\x28\x26\xd1\xb4\x77\x4b\x34\xb2\xbb\x9d\x39\xc8\ -\x4c\x7a\xb7\x82\x4c\x52\x55\x50\x8c\xcc\xb4\x77\x2b\xc8\x64\x8a\ -\xcd\x8a\x31\xca\xdd\xe2\x8f\x56\xb6\x01\x21\x35\x24\x53\x46\x91\ -\x2a\xa3\x72\xc1\xf6\xc6\xcc\x96\x1c\xdb\x59\x4c\xae\xed\xa8\x0a\ -\x10\x00\xd8\x05\x67\x58\x60\x22\x3d\x76\xe3\xa2\x77\xd2\x8d\x69\ -\xd4\x0c\x22\x7c\x97\x35\x7c\x8c\x87\x38\xe0\x0e\xc6\xb6\x9a\x3b\ -\xc0\x05\x60\xfc\x36\x0d\x2b\xf7\x56\x39\x7e\x57\xdc\xdd\x62\x41\ -\x46\x42\x37\xc1\x0c\xbe\x89\xf1\xbc\xe5\x29\x4c\x6c\xb6\x14\xc1\ -\x53\x5f\x9d\x45\xc2\xdf\x44\x8f\x07\xe8\x6a\x9a\xe9\x65\xd2\x1e\ -\x8d\xbb\x66\xfd\x04\x06\xb8\x4b\xae\xc7\xcd\x27\x97\x70\x3d\x4e\ -\xec\x19\x3e\x3e\x0b\x29\x64\x78\x54\xb5\xf1\x8c\xf3\xe0\x9e\x9c\ -\x5d\xe6\xc0\x9d\x15\x81\xb3\x3f\x95\x5b\x9b\x0c\x6d\xb7\x4a\xea\ -\xc9\xeb\xcb\x9b\x25\xf2\xe5\xd5\x3a\x69\x7c\x7e\x59\xdf\x1a\x8d\ -\xcf\xd6\x47\xe3\x8b\xcd\xd2\xf8\x2c\x4b\xe3\xd3\xcb\x73\x2f\x1a\ -\x9f\x9f\xe4\xc0\x5d\xee\x20\x8d\x93\x43\x29\x37\x4c\xd9\xb3\x75\ -\x52\xf6\xec\xe4\x3c\x0b\xee\x69\xa1\x30\x54\xac\x21\x92\x53\x4b\ -\x36\x4b\xd9\xf3\xa7\x59\x41\xbe\xf0\xa2\x6c\xfd\x22\xa7\xca\x2f\ -\xae\x76\x97\xb2\x1b\xd6\x06\x4f\xf2\xa4\x28\x14\xdf\x7b\x5b\xb5\ -\xab\x3c\xb8\xa7\xcb\x51\x36\x7d\x09\xfd\x8d\xda\x90\x37\x0f\xfe\ -\x0f\x44\xe6\x40\x56\ +\x00\xa3\x4a\x78\x9c\xed\x1d\x6b\x6f\xdb\x38\xf2\x7b\x7e\x05\x91\ +\x0f\x45\x0f\xc8\xc6\xb1\xf3\x6e\x1d\x2f\xda\xf4\x09\x74\x77\xbb\ +\x75\xda\xde\xde\x97\x05\x2d\xd1\x36\xaf\xb2\xe8\x8a\x74\x12\x2f\ +\xee\xc7\xdf\x0c\x49\x59\x8f\xc8\x72\x64\x59\x96\xdd\xba\x28\x10\ +\x89\xa4\xc8\xe1\x70\x5e\x9c\x19\xd2\xed\x5f\xef\x47\x1e\xb9\x65\ +\x81\xe4\xc2\xbf\xda\x6f\x1e\x1e\xed\x13\xe6\x3b\xc2\xe5\xfe\xe0\ +\x6a\xff\xf3\xcd\x9b\x5f\x2e\xf6\x7f\xed\xec\xb5\x27\x3c\x6a\x74\ +\x02\x8d\x3a\x7b\xa4\xed\x78\x54\xca\xce\xdb\x09\x7f\xf6\xec\x15\ +\xa7\x9e\x18\xc0\x5f\x6f\xd0\x65\x4a\xc1\xc7\xf2\x55\x40\xfb\xaa\ +\xdd\x30\x8d\xa0\xf5\x1d\x77\x07\x4c\x11\xfd\x7e\xb5\xff\xe7\x57\ +\xfd\xba\x4f\x7c\x3a\x62\x57\xfb\xb9\x9d\xe0\x60\xa4\x3d\x0e\xc4\ +\x98\x05\x6a\x6a\xbf\x18\x30\x31\x62\x2a\x98\xea\x4a\xd2\x0e\x98\ +\xa3\xf4\x13\x69\xdf\x77\x8e\xda\x8d\x7b\xfb\x32\xc5\x97\xa9\x7d\ +\x01\x10\xd4\xb0\x73\x7a\x09\x45\xe6\xd1\x14\x0f\x19\x1f\x0c\x55\ +\xe7\xec\xb8\xd5\x6e\xd8\x67\xdd\x67\x23\xec\xb4\xdd\x08\x07\xcf\ +\x82\xe4\x8e\xfb\xae\xb8\xbb\xe1\xca\x63\x16\x18\xa9\x02\x00\xbe\ +\xf3\x96\xf9\x2c\xa0\x1e\x91\x76\x32\xed\x86\xad\x78\xd8\xa5\x47\ +\xa7\x62\x12\x21\xe7\xcb\x4b\x71\xff\x41\x17\xd9\x1e\x53\x43\xca\ +\x31\x75\xa0\xa3\x7d\x3b\x01\x7f\x32\xea\xb1\xa0\x73\xd6\x6e\xd8\ +\x27\x03\x7e\x7c\x84\x07\x5d\x8c\x68\x30\xe0\x7e\xaa\x87\xcb\xdc\ +\x1e\xb8\x62\xa3\x08\x93\xf1\xc5\x7c\x1b\x88\xc9\x18\x60\x0e\x97\ +\x73\x10\xbe\x9b\xe6\x0f\x06\x57\x11\xb2\x32\xf0\xa5\x17\x9d\x74\ +\x33\xb0\xf6\x10\xa8\x5c\xdc\xd9\xd1\x80\x70\x15\x77\xa8\x67\x4a\ +\xff\x6e\x45\x03\x47\x33\xca\xe8\xe8\xdd\x83\x8e\x86\x22\xe0\xff\ +\x08\x5f\xcd\xba\x6a\x5e\xce\xfa\x4a\xf7\xf6\x10\x49\x1f\x68\x8f\ +\x79\x61\x57\x1e\xbe\x24\xbf\xcf\x40\x13\xbb\x57\x89\x06\x33\x54\ +\x19\x14\x71\x5f\xb1\xa0\x4f\x1d\x46\x46\xc2\x65\x29\x44\x65\x63\ +\xcb\x14\x1a\xc8\x62\xa0\x37\x92\xb0\x2f\x98\x8a\xe6\xd6\x8f\x01\ +\xeb\x5f\x8b\x51\x4f\xc4\xd7\x1d\x2b\xc6\x50\xe1\x60\x45\x4f\xdc\ +\xff\x7d\x92\x3f\x41\x21\xbc\x1b\x3e\xce\x9e\xe3\xcd\x90\x4b\x02\ +\xff\xd5\x90\x91\xcf\xef\xf5\x14\x61\xc6\xe4\x6e\xc8\x9d\xa1\x2e\ +\x34\x48\x80\xf2\x89\xc7\xc8\x1d\xf7\x3c\x72\x27\x82\x6f\xcf\xc8\ +\x0d\xf4\xda\xa3\x81\xf9\x42\x97\x8f\x3d\x44\x12\xf5\x42\xda\x0a\ +\x39\x12\xfb\xa3\xf0\x36\xa6\x01\x55\x8c\x28\xf3\xe1\x01\x8e\x01\ +\x5d\x2a\x2a\xbf\x25\xfb\x99\x48\xa6\x47\x7e\x13\x30\x76\xfd\xe2\ +\x15\xb9\x81\x16\xb7\x9c\xdd\x11\x39\x95\x80\x31\xd2\x17\x81\x1e\ +\x85\x2b\x89\x6d\x03\xb3\x42\xd4\x51\x20\x37\x1f\xbd\x3c\x0f\xb0\ +\x84\x08\x7d\xed\xa3\xac\x23\x52\xb9\x00\xfb\xd5\xfe\x51\x0a\x65\ +\x8e\xed\xfb\x33\xff\x4d\x53\x82\x53\x66\xac\x8f\x54\x0d\x17\x0f\ +\x05\x03\x35\x42\x19\xff\xe8\xd1\x52\x74\xf5\x18\x92\x8f\xe8\xc1\ +\xac\x4e\x16\x1e\xe7\x0d\xd7\x48\x8f\x57\x0e\x00\xbb\xda\x65\x20\ +\x58\xc8\x7b\xed\x86\x11\x43\x33\x19\x95\xa8\x2e\x2d\xb1\x5a\xe5\ +\x04\x56\x6b\x59\x79\xc5\xfa\x74\xe2\x41\xd7\xc2\x13\x99\x2b\x58\ +\xb9\xa0\x82\x71\x5f\x4e\x94\x12\x7e\x86\xac\x82\xba\x9e\xa9\x5b\ +\x5a\x58\xa1\x54\x70\xe3\x93\xd4\xb2\xc0\x07\xd1\x20\x7a\xff\x05\ +\x33\x22\xad\xc6\xf2\x68\x26\x35\xae\xee\x2e\xcd\x84\x58\x96\xa2\ +\xd2\x80\xb9\x68\xec\xe0\x9f\x64\xc5\x00\xa4\x95\x8f\x55\xe6\x21\ +\x59\xd9\xf3\x26\x0c\xeb\xf4\xdf\x24\x41\x3f\x18\x64\xe5\xe2\xca\ +\x92\xc3\x66\x4a\xab\xd2\xd4\x97\xc5\x40\x0b\xf4\xe1\x5c\x06\xea\ +\xfa\x74\xbc\xe9\xdc\xb3\x48\x3a\x14\xe7\x1f\x89\xb3\x96\x53\xb0\ +\x25\xbc\x1d\x03\x25\xc0\xb7\xb8\x40\x04\xfd\x7c\x4c\xb4\xac\xd5\ +\x7c\x2d\x7c\x78\x9a\x68\x73\x6c\xe3\x99\xe9\x78\x35\x96\xf3\x43\ +\xa6\xb2\x0a\x89\xf4\x18\xb4\x25\x6e\x40\xef\x7c\x6b\xf0\x72\xc4\ +\x4a\x0c\x45\x68\xf8\x1e\xae\x87\xef\x4e\x4e\xe6\x33\x5e\xb3\x75\ +\x9a\xc3\x7a\xad\xd3\xd3\xda\xb4\x57\x84\xab\x9f\x8f\x09\x17\xd0\ +\xe7\x42\x53\xd0\xe3\x60\x1d\xa1\x17\xa6\x06\x1e\xec\x8e\xb9\x9f\ +\xb5\x6d\x95\x50\xde\x8b\xdc\x16\xd9\x33\x7b\xac\x1a\x9b\x4d\x70\ +\x75\xa6\xe0\x2d\x05\x3a\x4f\x8d\x6c\x1d\x36\xad\x84\xeb\xa6\x50\ +\xaf\x05\x48\x3e\xb6\x68\x5b\x4a\xea\x15\xef\xaf\x8e\x4b\xee\xaf\ +\x8e\x4a\xa9\x36\xca\xb5\xd0\xde\x48\x4f\xd0\x69\x19\x7d\xc6\xc8\ +\x6c\x82\xa8\xb4\x60\x8e\xbc\xcf\x59\x40\xbe\xb1\xe9\x5a\xfc\x2a\ +\x30\xa0\x13\x02\xb0\xa9\xa4\x5f\xce\xb9\x21\x87\x1c\x07\xab\xcb\ +\xb7\xe2\xa8\xc0\xab\x6f\x74\xea\x95\x9a\xfa\x12\x6c\x84\x1e\x7c\ +\xa0\xdf\xb4\x14\xe9\xea\xe2\x05\xbc\x02\xad\x19\x34\x46\xb3\x23\ +\x45\x3d\x0c\x54\x40\xe7\x4f\xf5\xec\xd9\xbb\x59\x8f\xed\x86\x2e\ +\x2c\x4c\xaa\x92\xff\xc3\xde\x71\x5f\xcd\x27\x55\x6c\x91\x42\xa7\ +\x89\xaa\x9c\x24\xe3\x2b\xb3\x5a\x1b\x5b\x69\x1d\x25\xc2\x2c\x11\ +\x58\xe9\x0e\xe7\x88\x2c\x83\xba\x95\xda\x32\xad\x66\x99\x6d\xf9\ +\xa6\x4a\xdc\xb3\x72\x12\x57\xda\xb9\xad\x40\xd2\x3a\x93\x20\x00\ +\x92\x7d\xef\xbb\xec\x3e\xdb\x7c\x69\xae\xc5\x7c\x81\xd9\xe0\xac\ +\x76\x12\xdc\x94\xee\x24\x78\x54\xb0\x62\x09\x9e\xcf\x7b\x3b\x09\ +\xbe\x72\x09\xbe\x6c\x64\xe2\x85\xa7\x36\x56\x80\x9f\x97\x13\xe0\ +\xd4\x4c\x6d\x2d\xf2\x7b\x3d\xdb\x4f\x98\x8d\x66\xf4\x9d\xf8\xde\ +\x89\xef\x4d\x8a\xaa\x36\xe3\x54\xb4\x4c\x1e\x48\xb9\x6d\xbf\x75\ +\xd7\xea\xac\x1b\xfd\x49\x0d\xd2\xec\x03\xf7\xd9\x6b\x97\xab\x07\ +\xd2\x0c\x5d\x46\x0c\x2a\xca\x44\x87\xb2\x1c\xda\xd1\x6c\xb5\x7f\ +\x2d\xe1\xb8\x0e\x93\xc3\x96\x97\x78\x8f\x43\xf9\x5a\x7c\x0f\xf1\ +\x99\xe9\x49\x9b\x15\xde\x4c\x19\x58\x37\x27\x9e\x3c\x9e\x11\x23\ +\x45\x3c\x64\xce\xb7\x4c\x45\x8c\x15\xa5\xfc\xc1\xba\x07\x20\x5b\ +\x24\xdf\x3e\x01\x08\xc9\x1d\xf5\x15\x51\x62\x96\x4a\xa4\x03\x07\ +\x8d\x98\xaf\x38\x10\x23\x5d\x61\x93\x91\x08\x95\x21\xc9\x57\x41\ +\xcd\x5d\x7a\x0b\x30\x18\xf5\x6e\x63\x44\xd4\x77\x63\xbe\x6b\xea\ +\x04\x42\x4a\x22\x99\xc4\xe4\xcf\x12\xbe\xeb\x22\x51\x4d\x00\x4a\ +\xf8\xec\x9e\x6f\xac\xaa\xaf\x9b\xcc\xcf\xab\x20\xf3\x32\x2e\xda\ +\xf7\x7d\x4b\xe5\x92\xe8\xee\x98\x7b\x00\xe4\x34\x9e\xc6\x92\xe7\ +\x7a\x0c\x8c\xd0\xb1\x0a\x29\x0a\xac\xdc\x11\x90\xda\x01\x11\x40\ +\xed\xc1\x1d\x97\x2c\x2c\x92\xa6\x3d\xf5\xee\xe8\x14\x28\x4f\xd1\ +\x00\x53\x1d\x89\x2f\x7e\x99\xf5\x58\x05\x2b\xbc\xf5\x44\x8f\x7a\ +\x64\x05\x63\x58\x0c\xa4\x86\xe9\x01\xfe\x3a\x20\xc8\xa1\x63\xfd\ +\x58\xad\xce\x18\x4f\x47\x1b\x9c\x09\x58\x37\xff\x34\x2f\x2a\x61\ +\xa0\x12\x31\xfb\xdf\x45\x30\xa2\x9e\x37\x3d\x20\x80\x48\x16\x68\ +\x32\xc4\x50\x87\x8d\x19\x1e\x58\x65\x31\xe6\x4c\x12\x04\x4e\x32\ +\x0f\xca\x99\x7b\x48\x42\xd6\x13\x63\x6d\xfb\xc4\x39\x10\xbf\xe9\ +\x51\xe0\xac\x30\xe6\x1f\x32\x62\xf8\x35\xf0\x95\x54\x8c\xba\x25\ +\xa2\xfc\x39\xba\x45\x0f\x92\x04\x20\x31\xb9\xf5\x28\x13\x0d\xc5\ +\x4b\x00\xe2\x8f\x30\xfc\xba\xe3\x89\x2c\x9e\x38\xad\x84\x25\x2e\ +\x56\xab\x53\xb4\x09\x15\xd7\x0e\xe8\xa4\x06\x73\x0a\x8c\x05\xa9\ +\x62\xfc\x62\x33\x5a\x30\xbb\x05\x4a\x35\x93\xf8\x42\xc5\xbe\xef\ +\x19\x07\xf7\x58\x7f\xe3\x7b\x53\xf8\x80\xf9\x04\x40\x07\x3b\x07\ +\x8a\xae\x6f\x3e\x7d\xa8\x84\x29\x5e\x24\xe1\x0e\xc1\x7d\xea\x72\ +\x49\x7b\x5e\xe4\x75\x47\x87\xcd\xbf\xb6\x59\x05\x99\x05\xea\x6e\ +\xb0\xbb\x7d\xe5\x4e\xdf\xfc\x1d\xee\xce\xe9\xbb\x6a\xa7\x6f\xb3\ +\xa4\x83\x34\xa0\x2e\x9f\xc8\x59\xa6\xa9\x96\x05\xc0\x93\x72\xcc\ +\x1c\x0e\x96\xe0\x58\x00\x22\xe5\x21\x9e\x44\xc2\xe2\x23\x93\xc7\ +\x23\x08\xb0\xaa\xa2\xbe\xc3\xc8\x53\xee\xf7\xb9\x0f\x70\x97\x60\ +\xd4\x05\xb1\xc5\x80\xfa\x83\x3a\xdc\x39\x0b\x32\xa4\x16\x90\xba\ +\x9c\xf4\xfb\x3c\xed\x29\xb6\x73\x18\xdf\xaf\x47\xed\x03\xf6\x3e\ +\x19\xe4\x6d\xa9\xf4\xa9\xfa\x24\x48\x01\x9f\x65\x01\x7d\x5f\xe2\ +\xc0\x57\x96\xbe\x9f\xf1\xa5\x56\xda\xa0\xc2\x89\x70\x9c\x49\x40\ +\xe8\x80\xa2\xe9\x1a\x33\x6c\xd5\x10\xd4\x66\x80\x4e\x15\xea\x6b\ +\xc3\x97\xfb\x2e\x77\x28\x1a\xb9\x26\x32\x41\x44\x9f\x30\x98\x55\ +\x09\x1f\xc6\xa2\x44\x00\x7a\xcf\x47\x93\x51\x25\x5a\xbb\x4f\x3d\ +\xb9\x0e\xb5\x0d\x73\xf8\x99\x74\xf6\x4e\x63\xcf\xc7\x74\x15\x61\ +\xda\xfc\x1d\x32\xf3\xd1\x06\x5e\x3d\xfd\xe7\x8a\x9d\xdf\x0c\xd7\ +\xa6\xa5\x04\xaa\xfc\x1e\xd3\x71\x05\xee\xb2\x00\xc4\x48\xdc\x4e\ +\xa8\x42\x86\xcc\x01\x64\x03\xb5\x7f\x7e\x76\x43\x55\xab\x68\xc5\ +\x6b\x76\x00\xfa\xf2\xf2\x72\xf9\x10\x74\x5e\x5e\xf5\xc9\x7a\x22\ +\xdb\x46\xec\xbe\x36\x0b\xbe\xa5\xb2\xb7\x6a\x8b\xa5\x59\x89\xc5\ +\x52\x62\x13\x01\x16\x4b\xc2\xd7\xd6\x35\xbb\x7a\x13\xb8\x99\xb9\ +\x19\x86\x42\x9f\xb0\x61\x3e\xbb\x05\xb6\x46\x0f\x04\x06\x7f\xaa\ +\x94\x24\x5d\x18\x32\xbc\x46\x21\x06\xd2\x36\xbb\x13\x10\x8b\x38\ +\x97\x97\xf4\xc7\x3d\x66\x53\x80\x68\x97\x3d\x02\xf7\x0e\x74\x59\ +\x78\x09\x42\x9c\x58\x8d\x5f\x76\x22\x4b\x44\x3d\x0a\x2c\xe6\x10\ +\xa0\xd8\xf6\xc5\xac\x3a\x42\x51\xe0\xa4\x7e\x01\xba\x69\x2e\xc8\ +\x74\xce\x93\x76\x3c\x26\xed\x28\xb1\x20\xd8\x5d\x96\x76\x9d\x0c\ +\xa3\x50\x32\xde\xc4\x81\x65\x63\x8f\xfa\x8c\xc4\x0c\x69\x02\x52\ +\x8f\xd1\x40\x12\x77\x82\x9d\x86\x1e\x5a\x82\x60\xe8\x06\xd5\x6c\ +\xcf\x50\x20\x7e\xb5\x30\x7d\xd4\x30\xa9\x80\xc2\x54\x4a\xc8\xc4\ +\x82\xc2\x4b\x8f\x7a\x13\x0e\xba\x23\xfa\x2c\xa2\xaf\x26\x2a\x57\ +\x22\x0f\x3e\xcb\x25\x91\x88\xa5\x19\x6a\xc6\x24\x8d\x3e\xbc\xc2\ +\x26\x21\x4a\xd7\x38\x24\x7f\x84\x91\x6d\x6d\x1d\x4c\xd3\x5f\xdc\ +\x71\x80\x32\x28\x92\xae\x55\x80\xe2\xdf\xe0\x58\xb3\xa3\xbe\xd3\ +\xf2\x39\x24\x05\xc8\x1d\x51\xb1\x8b\x3e\xcf\x27\xf3\xb2\xb7\x46\ +\x95\xbd\x85\x25\x21\x9c\x37\x32\xf3\x39\x7f\x86\x05\x48\xd1\x92\ +\xfd\xd7\x8f\x9b\x4a\x8b\xe5\xf2\x66\x7f\x17\xd9\x0b\xb8\x9e\xac\ +\xdd\x7f\xff\x45\x9e\xde\x88\x71\x66\xf4\x63\x4d\x10\xfc\x87\x3c\ +\x7d\x13\x00\x6f\xd5\x08\xc3\x5f\x00\x43\x17\x0c\xda\x52\x20\xd4\ +\x2d\x92\x9a\xd5\x64\x94\x95\xc8\xf9\x7d\x9f\xb0\x36\x07\x01\x77\ +\x13\xfa\x53\x87\xeb\xad\xf1\x58\x85\xfe\xfc\x0c\x5b\x74\x1c\x74\ +\xab\x9d\xf9\x66\x02\x9b\x29\xf8\x56\x1e\x7d\xcf\xf7\xe3\xec\x7c\ +\xf9\x65\x7c\xf9\x45\x76\x98\xf9\x67\x19\x6a\x71\xf1\xa7\xfd\x74\ +\xc6\x01\x12\x93\x29\x26\x29\xa7\xc7\xc8\x2d\x97\x1c\xd3\x70\xb4\ +\x78\x89\x9a\xa2\xc5\xd4\x63\xbe\x33\xc4\x9d\x00\xde\xe7\x78\xcb\ +\x62\xe6\x7d\x2c\x81\x68\xa2\xb3\x87\x68\x98\xca\x5a\x65\x06\x11\ +\xec\x29\xd7\x62\xcd\xdb\x44\x1e\x18\xee\xed\x8f\x25\x4e\x1e\x61\ +\x69\xe7\x67\x44\x57\x46\xcb\xf3\x73\x94\x91\x64\xed\xed\xbf\x35\ +\x18\xee\xaf\xc4\x04\x26\x3c\x2f\x3a\xe4\xea\xda\x30\x46\xb4\x81\ +\x91\x3e\x7d\xaa\xdd\x20\x0f\x78\x5d\xdd\x31\x60\x58\x46\x81\xa9\ +\xb5\x24\xc0\x33\x0f\xcb\x33\x94\xcb\x1c\x3e\x02\xc8\xb3\xa3\x48\ +\x25\x82\x48\xd9\x51\x2f\x83\x6b\x8c\x7a\x5d\x1e\x5e\x5e\x5c\xce\ +\xfe\x9d\x5f\xb4\xda\x0d\x5b\x59\x78\xa8\xac\x30\x98\xed\xab\x79\ +\x78\x94\xfc\xb7\xfc\x28\x05\xed\x97\x6e\x48\xed\x3f\x93\xdc\xa9\ +\x27\xc0\x9a\x17\x9a\xe6\xbe\x66\x10\x49\x30\x88\xf5\xf8\x83\x75\ +\xeb\x8b\x49\xe7\x27\x1e\xd5\x94\x59\xc0\x7d\x83\xb4\x30\x16\x68\ +\x6e\xdb\x53\x43\x8e\x5e\xe0\x43\xd2\xc5\x4c\xc3\xfe\x94\x80\x1d\ +\xc1\x08\xba\xa8\xc1\x66\x98\x12\xf9\x7d\x42\x03\x26\x67\x22\x6a\ +\x14\x76\x53\x22\x21\x39\x27\xc2\xdd\x3c\x5a\x4b\x84\x1b\x79\xf9\ +\xb5\xa1\x9d\x2d\xe5\xe4\xaa\xb7\xe0\x25\xef\x0e\x5b\x90\x69\x3f\ +\x97\xb7\xdf\xe3\x1d\xe5\x3e\xe6\xbb\x06\x40\x8d\x78\xca\x8f\x78\ +\xc0\xe4\x99\xa7\xc1\x6b\xe6\xf1\x7c\x9b\xc2\x6a\xca\x2e\xec\x88\ +\x1e\xbb\xeb\x3a\xcb\xdf\x75\x35\xcf\xce\xcf\xcf\x5b\xcd\xd3\x32\ +\x7b\xaf\xe2\x26\x4a\x94\xff\x13\x1a\x15\x78\xfc\x8d\x87\xcb\xe4\ +\x08\x11\xb8\xdc\xa7\x8a\xc9\x58\xd4\x8c\x3c\xc5\xf4\x24\x76\x7f\ +\x48\x8e\xc9\x15\x39\x02\x75\xdd\x2c\x91\x95\x9c\x23\x2e\xce\xd6\ +\x22\x2d\x66\xb4\xb8\xb5\xd2\xa2\xa8\xfb\x22\x5f\x7f\xed\xdc\x17\ +\x2b\x3f\x3c\xb0\xac\xbc\x7c\xc5\x47\xcc\xd7\x87\xa1\xb7\x40\x62\ +\xe6\x6f\x60\x73\x33\xea\x2e\xaa\xc9\xa7\x5b\x8b\xf8\x70\xf9\xe8\ +\xe3\xd6\x4b\x90\xaa\xed\x8d\x02\x07\xfe\xb2\x18\x68\x41\xde\xdc\ +\x5c\xfe\xb9\x11\x1e\x28\x2d\xdf\xa9\x34\xf2\x98\x2f\x6b\xf3\x59\ +\x7f\x27\x6b\x57\xe2\x2a\x2e\xe0\x2c\xfa\x09\xcc\xba\xe8\x02\x1b\ +\x2d\x1c\x31\xd5\xce\xc5\xbc\x8c\xfe\xc4\x77\x8c\x01\xa7\x86\x54\ +\xe9\xcc\x50\x4a\x54\xc8\x22\x87\x7b\x5f\xb0\xb5\x3d\xdf\xe2\xf2\ +\x7e\x1f\x76\x8a\x50\x8e\x9b\x43\x0f\xf6\x8b\x3a\x39\xc5\x74\x18\ +\x6e\x31\x55\xc0\xf4\xa1\x17\x2a\x89\x04\xc0\x4a\xec\x19\x73\x4e\ +\x71\x35\x96\x21\x78\x7f\x00\xe4\xa0\x58\x1a\x45\xd6\x8f\x04\x26\ +\x6b\x73\x45\x1e\xa6\x1c\x3f\x16\x8c\x72\xba\x7e\x3f\x96\x8a\x44\ +\xde\x4e\x17\x65\xe9\xa2\xb3\x72\xaa\x68\x41\x86\xd7\xc2\x84\x18\ +\x6c\x41\x8c\x2c\xd8\x70\xaf\x7a\x7e\x40\xfd\x47\x10\x95\xe1\x9a\ +\x98\xf1\xf4\xa1\x1b\x5c\x1e\xa9\xef\x25\x72\x67\xb6\xf7\x6a\xf7\ +\xb6\x33\xe9\xd0\xaa\xc1\xcb\x8d\xd3\x0b\x89\x6f\x4b\xc5\x43\x51\ +\x03\x2c\xdf\x91\xb3\x33\xc0\x56\xbd\xd9\x5d\x70\xb3\xd3\xe3\x04\ +\x64\x1f\xf0\xbd\x89\x37\x0b\x2e\x9f\x63\x94\x75\xaf\x20\xce\x52\ +\x7f\x3b\xfb\x35\x47\x93\x02\x90\x25\x84\x0e\xf7\xde\x03\xbc\xd4\ +\x47\xbb\x8b\xc6\xbe\x94\x13\x67\x88\x06\xd8\x93\xef\x13\xa1\x9e\ +\xbf\x08\x38\xf5\xcc\x23\xa6\x32\x85\x03\x49\x35\xf5\xd2\x4d\x25\ +\xf5\x65\xd8\xd2\x96\xb0\x80\xf7\xcd\xe3\x1e\xc0\x63\x9e\x46\xc2\ +\x17\x61\x33\x04\x92\xf4\xe9\x88\x7b\xd3\xac\x71\x0f\xde\x31\xef\ +\x96\xe1\xef\x9f\x1e\x44\x9d\x9b\x8f\x34\xa8\xda\xb0\xa4\x06\x98\ +\xbd\x8c\xef\x9f\xbd\x14\x9e\x6b\xde\x2b\x49\x66\xc0\x31\x96\xef\ +\x98\x7a\x7c\xe0\xc3\x6a\x3c\xe8\x1d\x08\x0f\xc5\xc4\x0b\xac\xff\ +\x84\xac\xf8\xbf\xd9\xeb\x4d\x40\x39\x90\xce\x20\x2a\xf9\x72\xcd\ +\xd0\xb9\x0a\x60\x30\x55\x1c\x86\x82\x92\xde\x70\xd1\x96\xca\xf9\ +\xaa\x5d\x12\x05\x4e\xf8\x65\xfa\xf4\x96\xbd\xc7\x3f\x92\x73\xa3\ +\xb1\x87\x3f\x05\x2b\x87\x8c\x55\x2a\xec\xf2\xf5\xe3\x82\x89\xec\ +\x14\xe4\x4a\x3c\x14\x6f\xb8\xc7\xae\x87\x42\x80\x8c\x7d\xa0\x5c\ +\xfa\x50\xe7\x98\xba\x45\x46\x37\xf7\x8b\x1a\xdd\xc7\x47\xf9\x08\ +\x2a\x85\x9f\xe2\x01\x27\x37\x4d\xfd\xf6\x7e\x52\x9d\xd1\xe6\xa0\ +\x3f\xc1\x24\xb5\xe1\x6f\x58\x85\xe7\xb5\x8a\x31\x48\x39\xa1\x69\ +\xa0\xda\x09\xcd\x39\x42\xb3\xc0\x9d\xb7\x19\x42\xb3\x7c\x14\xe4\ +\x09\x1d\x8d\x9f\x93\x0f\x8c\xba\x20\xd0\x68\x10\x88\x3b\x63\x4e\ +\x6c\xe2\xc9\x92\x95\x9d\x2b\xe1\x23\xf3\xbb\xa4\x9b\x4a\x95\xe5\ +\xce\x34\xbc\x12\x8a\x9c\xd6\x77\xa4\x02\x87\x3f\xaf\x77\xf8\xcb\ +\xfa\x86\xbf\xe6\x81\x03\x3b\x83\x1a\xf1\x6f\x21\xa8\x71\x09\x2c\ +\x04\x35\xae\x42\x17\x44\xcb\xb0\xce\x45\x30\x00\xd4\xb8\x06\x06\ +\x80\x1a\x97\xe0\x25\x75\xbe\xc9\xba\x97\x21\x02\xa2\xc6\xa5\x88\ +\x80\x28\xb5\x1c\xb5\x9b\x2a\x25\xfd\xfc\xcd\xfc\x24\x99\xf9\xd6\ +\xca\x17\x68\xc5\x1d\xea\xc5\x7c\x37\xc6\xa7\x15\xdb\x49\x6d\xa2\ +\xb9\xb2\xaa\x5f\x81\x8e\x5f\xc0\x20\xfa\xc6\xdf\x15\x62\xc2\x7a\ +\xb6\xec\x89\x17\xd8\xf0\xc4\x91\x44\x03\x46\x6e\x2d\xf2\x0e\x49\ +\xb8\x4d\x86\x5e\x3d\xd6\x57\x07\x78\xcb\xae\x39\x13\x83\x3d\xbe\ +\xef\xfe\x81\xb7\xb5\xfb\x2e\x0d\xca\x5c\x28\x5d\xcc\x0a\x4b\x2c\ +\xe0\x8f\x68\x8a\x7d\x00\x44\x93\xa7\x71\xdc\xd6\x78\xd6\xf5\xd3\ +\xbc\x10\xd9\x96\x48\xa0\x92\xe2\x67\xd9\xdf\xbc\x7e\xe1\xe9\xdc\ +\x4d\xd8\x59\x77\xbf\xbc\x25\x40\x68\xf8\x0a\x3c\x24\x9c\xca\x25\ +\xcf\x02\x3f\x53\xfe\x61\xbd\x9d\x9f\x69\xad\x7e\xa6\x05\xe9\xcd\ +\x5b\xed\x67\x7a\x87\x47\x1c\xf0\xee\x33\x0c\x97\x48\x7b\xee\x81\ +\x82\xaa\x09\x98\xa3\x44\x30\xc5\x8b\x16\x95\xfd\x79\x67\x64\x12\ +\xc4\x8b\x8c\x17\x3e\xf1\xd4\xf3\xb1\xe1\x9c\x27\x03\xf5\x1c\x9d\ +\x56\x78\xf7\x72\x94\x3a\x13\xc6\x61\x5c\x97\xb9\xe8\xc1\x42\x95\ +\x14\x8a\x4c\x1b\xc3\x81\x66\xa0\xae\x6c\x2f\xeb\xf9\x2d\x1b\x3b\ +\x18\x92\xc0\xa6\xea\xa7\x72\x32\x39\x59\x99\xe8\x2b\x6a\x17\x6b\ +\x14\x6b\x61\xe5\xf7\x2c\x20\x66\x4e\x7a\x5d\xed\x9f\xed\x93\x11\ +\x0d\x06\xdc\xbf\xda\x6f\x36\xf7\x31\xd7\xa8\x3d\xe6\xf7\x23\x3a\ +\x0e\x93\xa5\x3a\xdf\x3f\xea\xf7\x37\x81\x18\xfd\x06\xc6\x4a\x57\ +\x4c\x02\x4c\xae\x49\xb5\x82\xef\x9c\x89\x54\x62\x64\x46\x94\x1a\ +\x92\x78\x89\x81\x52\xb3\x6b\x47\x73\x6b\x8c\x53\x01\x7f\xba\x5c\ +\x37\x01\xc9\xce\x7c\x57\x76\xfe\xfc\xaa\xbf\x03\x51\x67\x0b\xf6\ +\x0c\x37\xa1\xeb\x0b\x7b\x68\x60\x07\xaf\x38\xf5\xc4\xe0\x70\x88\ +\xcc\xa5\x2b\x34\x02\xd2\xe3\xe6\x03\x72\x8d\x3f\xc5\xf4\x72\xa2\ +\x94\x36\x6b\x32\x00\xf9\x38\x91\xc3\xb0\x7e\x1e\x30\x06\x58\x59\ +\x0e\x92\x94\x00\xcb\x84\xe6\x21\xee\xe6\x81\x84\xbd\xad\x0c\x2c\ +\x9b\x32\x93\x8d\xa0\x59\xe5\x5a\x40\x59\xb4\x5e\x0f\x17\x75\x3d\ +\x60\xd9\xe3\xfa\xd9\x28\x8a\x6a\xd7\x84\x23\xb3\xdb\x99\x03\xcc\ +\xac\x76\x2d\xc0\x84\x59\x05\xd9\xc0\x44\xb5\x6b\x01\x26\x91\x01\ +\x96\x0d\x51\xaa\x49\x79\xb0\x92\x05\xd8\x53\x3b\x60\x52\x0b\x52\ +\xa9\x45\x2e\xe8\x5e\x9f\x99\xdc\x54\x33\x8b\xd9\xbb\x19\x55\x02\ +\x00\xd0\x77\xc6\xa5\x2f\x18\x48\xf7\xed\xb8\x68\x9d\x0c\x7c\xea\ +\x75\x1c\x0f\x0f\x3d\xba\x4f\xf1\x9c\x25\xee\x60\x4c\xa9\x6e\x01\ +\x26\x00\xe3\xb7\xf1\xbe\x52\x47\xc9\xdb\x8d\x59\x13\xd3\xa5\x27\ +\x54\x07\xd4\xe0\x6b\x73\xaa\x73\xd6\x27\x16\x1b\x8c\xe0\x2f\x37\ +\x58\x8d\x84\xcf\x44\x4d\xc7\x68\x6a\xea\xe9\x25\xc2\x1e\xed\xfb\ +\xce\x25\x00\x7c\x1f\xbe\x4e\x3b\xc7\xe7\x97\xed\xc6\x34\x54\x67\ +\xf8\xf5\xc3\x8e\x5c\x86\xbf\x36\xa3\x0d\xe3\x74\x6f\x27\xcd\xf3\ +\x64\x77\x17\xcd\xac\xee\xcc\xa3\xb4\x4b\x93\x40\xed\x5a\x31\x3d\ +\x3b\x3e\x5b\x2d\x8e\x11\xa7\x09\x1c\x1f\x97\xc1\xf1\xe9\x79\x33\ +\xd5\xdd\x49\x65\x38\x3e\x59\x1d\x8e\xcf\xaa\xc5\xf1\x59\x92\xf0\ +\x5a\xe7\x47\xab\xc4\x71\xeb\xbc\xb5\x81\x38\x0e\xaf\x95\xaf\x18\ +\xb3\xad\x95\x62\xb6\x79\xb6\x36\xcc\x2e\x2f\x21\xc2\x1b\x50\xaa\ +\xc5\xec\xe9\x45\x92\x91\xcf\x4e\xcb\x60\xf6\xf8\xf4\x64\x0b\x64\ +\x6f\x78\xc7\x43\xb5\x98\x3d\x3e\x4e\x61\xf6\x7c\x95\x34\x5b\x25\ +\x66\xcf\xcb\x4b\xdc\xe8\x9e\xec\x6a\x91\xdc\x4c\xd1\x6f\xeb\xb2\ +\x94\x64\x38\x41\x7f\x4d\xa2\xbb\x4c\x35\xb9\x29\xb6\x43\xec\xce\ +\xaf\x8a\xad\x87\xb4\x85\x56\x4a\x4a\xb4\x5a\x67\x8f\x31\x46\xe6\ +\x63\x39\xfe\x0a\xf5\xed\xc6\x84\x77\xf6\xfe\x0f\x9b\x41\x85\x54\ +\ \x00\x00\x07\xb5\ \x00\ \x00\x1a\x6e\x78\x9c\xed\x58\x5d\x6f\xe3\xb8\x15\x7d\xcf\xaf\x50\ @@ -24441,6 +27281,346 @@ qt_resource_data = "\ \x4b\xa7\xa0\xf2\x0f\xed\x14\xf4\x17\x26\x82\x6f\x9d\xc2\x5c\xbf\ \x47\xa7\x68\x1f\xea\xdb\xa3\xf9\x69\xef\xe9\xc3\x7f\x00\xa5\x17\ \x49\xdb\ +\x00\x00\x15\x1c\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x43\x65\x6e\x74\x65\ +\x72\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\x5f\x65\x78\x74\x65\x6e\x73\ +\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\x73\x76\x67\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\ +\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\x32\x37\ +\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\ +\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\ +\x65\x6e\x74\x33\x31\x34\x34\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\ +\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\ +\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\x70\ +\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\ +\x31\x34\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\ +\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\ +\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\ +\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\ +\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\ +\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\ +\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x20\x20\ +\x3c\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x65\ +\x63\x74\x69\x76\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\ +\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\x3d\x22\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x33\x64\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\ +\x5f\x78\x3d\x22\x30\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x76\x70\x5f\x79\x3d\x22\x30\x20\x3a\x20\x31\x30\x30\x30\x20\x3a\ +\x20\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x76\x70\x5f\x7a\x3d\x22\x36\x34\x20\x3a\x20\x33\ +\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x33\x64\x2d\x6f\ +\x72\x69\x67\x69\x6e\x3d\x22\x33\x32\x20\x3a\x20\x32\x31\x2e\x33\ +\x33\x33\x33\x33\x33\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\ +\x65\x32\x37\x33\x34\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x72\ +\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\ +\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\ +\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x33\x31\x34\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\ +\x33\x38\x35\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\ +\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\ +\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\ +\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\ +\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\ +\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\ +\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\ +\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\ +\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\ +\x33\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ +\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\ +\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\ +\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x33\x31\x34\x34\x2d\x37\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\ +\x65\x6e\x74\x33\x38\x35\x30\x2d\x32\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\ +\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ +\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\ +\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\ +\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\ +\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\ +\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\ +\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\ +\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\ +\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\ +\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\ +\x34\x34\x2d\x37\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\ +\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\ +\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\ +\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\ +\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x36\ +\x2d\x34\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\ +\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\ +\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\ +\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\ +\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x38\ +\x2d\x34\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\ +\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x20\ +\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\ +\x35\x31\x38\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\ +\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\ +\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\ +\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\ +\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\ +\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\x34\x2c\x30\ +\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\ +\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x61\ +\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x34\x34\x33\x37\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\ +\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x37\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\ +\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x20\x2f\x3e\x0a\ +\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\x6f\x64\ +\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\ +\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\ +\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\ +\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\ +\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\ +\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\ +\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\ +\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x33\x2e\x38\ +\x38\x39\x30\x38\x37\x33\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x32\x38\x2e\x31\x31\x37\ +\x31\x32\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x63\x79\x3d\x22\x35\x33\x2e\x36\x36\x35\x37\x37\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x67\ +\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\ +\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\ +\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\x64\x2d\ +\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\ +\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\ +\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\x35\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\ +\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\ +\x79\x3d\x22\x32\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\ +\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\ +\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x37\x33\x31\x22\x3e\ +\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\ +\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\ +\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\ +\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\ +\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\ +\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\ +\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\ +\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\ +\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\ +\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\ +\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\ +\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\x3e\x0a\x20\x20\x20\x20\ +\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\ +\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\ +\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\ +\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\ +\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x74\ +\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\ +\x28\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x30\x2c\x30\x2c\x30\ +\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x36\x2e\x33\x36\x30\x35\x39\ +\x38\x36\x2c\x2d\x36\x36\x2e\x31\x30\x38\x38\x30\x36\x29\x22\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\ +\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\ +\x23\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\ +\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\ +\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\ +\x23\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\ +\x69\x64\x74\x68\x3a\x35\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\ +\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\ +\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\ +\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\ +\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\ +\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\ +\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\ +\x6b\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\ +\x6d\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\ +\x62\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\ +\x69\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\ +\x65\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\ +\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\ +\x3a\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x20\x33\x31\x2e\x37\x35\ +\x20\x34\x2e\x33\x31\x32\x35\x20\x43\x20\x31\x36\x2e\x38\x39\x33\ +\x39\x37\x34\x20\x34\x2e\x33\x31\x32\x35\x20\x34\x2e\x38\x37\x35\ +\x20\x31\x36\x2e\x33\x36\x32\x37\x32\x34\x20\x34\x2e\x38\x37\x35\ +\x20\x33\x31\x2e\x32\x31\x38\x37\x35\x20\x43\x20\x34\x2e\x38\x37\ +\x35\x20\x34\x36\x2e\x30\x37\x34\x37\x37\x37\x20\x31\x36\x2e\x38\ +\x39\x33\x39\x37\x34\x20\x35\x38\x2e\x30\x39\x33\x37\x35\x20\x33\ +\x31\x2e\x37\x35\x20\x35\x38\x2e\x30\x39\x33\x37\x35\x20\x43\x20\ +\x34\x36\x2e\x36\x30\x36\x30\x32\x36\x20\x35\x38\x2e\x30\x39\x33\ +\x37\x35\x20\x35\x38\x2e\x36\x35\x36\x32\x35\x20\x34\x36\x2e\x30\ +\x37\x34\x37\x37\x37\x20\x35\x38\x2e\x36\x35\x36\x32\x35\x20\x33\ +\x31\x2e\x32\x31\x38\x37\x35\x20\x43\x20\x35\x38\x2e\x36\x35\x36\ +\x32\x35\x20\x31\x36\x2e\x33\x36\x32\x37\x32\x34\x20\x34\x36\x2e\ +\x36\x30\x36\x30\x32\x36\x20\x34\x2e\x33\x31\x32\x35\x20\x33\x31\ +\x2e\x37\x35\x20\x34\x2e\x33\x31\x32\x35\x20\x7a\x20\x4d\x20\x33\ +\x31\x2e\x37\x35\x20\x31\x33\x2e\x34\x36\x38\x37\x35\x20\x43\x20\ +\x34\x31\x2e\x35\x33\x38\x39\x35\x31\x20\x31\x33\x2e\x34\x36\x38\ +\x37\x35\x20\x34\x39\x2e\x35\x20\x32\x31\x2e\x34\x32\x39\x38\x30\ +\x31\x20\x34\x39\x2e\x35\x20\x33\x31\x2e\x32\x31\x38\x37\x35\x20\ +\x43\x20\x34\x39\x2e\x35\x20\x34\x31\x2e\x30\x30\x37\x37\x30\x32\ +\x20\x34\x31\x2e\x35\x33\x38\x39\x35\x31\x20\x34\x38\x2e\x39\x33\ +\x37\x35\x20\x33\x31\x2e\x37\x35\x20\x34\x38\x2e\x39\x33\x37\x35\ +\x20\x43\x20\x32\x31\x2e\x39\x36\x31\x30\x34\x39\x20\x34\x38\x2e\ +\x39\x33\x37\x35\x20\x31\x34\x2e\x30\x33\x31\x32\x35\x20\x34\x31\ +\x2e\x30\x30\x37\x37\x30\x32\x20\x31\x34\x2e\x30\x33\x31\x32\x35\ +\x20\x33\x31\x2e\x32\x31\x38\x37\x35\x20\x43\x20\x31\x34\x2e\x30\ +\x33\x31\x32\x35\x20\x32\x31\x2e\x34\x32\x39\x38\x30\x31\x20\x32\ +\x31\x2e\x39\x36\x31\x30\x34\x39\x20\x31\x33\x2e\x34\x36\x38\x37\ +\x35\x20\x33\x31\x2e\x37\x35\x20\x31\x33\x2e\x34\x36\x38\x37\x35\ +\x20\x7a\x20\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x74\x72\ +\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\ +\x36\x2e\x31\x36\x37\x39\x35\x38\x34\x2c\x30\x2c\x30\x2c\x36\x2e\ +\x31\x36\x37\x39\x35\x38\x34\x2c\x2d\x33\x39\x2e\x32\x33\x31\x39\ +\x30\x38\x2c\x34\x30\x37\x2e\x37\x35\x36\x33\x37\x29\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\ +\x34\x33\x36\x34\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\ +\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\x3d\ +\x22\x6d\x20\x32\x34\x35\x2e\x37\x31\x34\x32\x38\x2c\x36\x35\x35\ +\x2e\x32\x31\x39\x33\x20\x61\x20\x34\x38\x2e\x35\x37\x31\x34\x33\ +\x2c\x34\x38\x2e\x35\x37\x31\x34\x33\x20\x30\x20\x31\x20\x31\x20\ +\x2d\x39\x37\x2e\x31\x34\x32\x38\x36\x2c\x30\x20\x34\x38\x2e\x35\ +\x37\x31\x34\x33\x2c\x34\x38\x2e\x35\x37\x31\x34\x33\x20\x30\x20\ +\x31\x20\x31\x20\x39\x37\x2e\x31\x34\x32\x38\x36\x2c\x30\x20\x7a\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\ +\x6f\x64\x69\x3a\x72\x79\x3d\x22\x34\x38\x2e\x35\x37\x31\x34\x33\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\ +\x6f\x64\x69\x3a\x72\x78\x3d\x22\x34\x38\x2e\x35\x37\x31\x34\x33\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\ +\x6f\x64\x69\x3a\x63\x79\x3d\x22\x36\x35\x35\x2e\x32\x31\x39\x33\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\ +\x6f\x64\x69\x3a\x63\x78\x3d\x22\x31\x39\x37\x2e\x31\x34\x32\x38\ +\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x70\x61\x74\x68\x33\x31\x36\x32\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x66\x69\x6c\x6c\x3a\x23\ +\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\ +\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\ +\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\ +\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\ +\x64\x74\x68\x3a\x33\x30\x2e\x38\x33\x39\x37\x39\x32\x37\x36\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\ +\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\ +\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\ +\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\ +\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\ +\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\ +\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\ +\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\ +\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\ +\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\ +\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\ +\x6c\x61\x74\x65\x3b\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\ +\x30\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\ +\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\x3d\x22\x61\x72\x63\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\ +\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x2d\x30\x2e\x39\ +\x38\x30\x39\x30\x35\x30\x35\x2c\x30\x2e\x31\x39\x34\x34\x38\x37\ +\x31\x34\x2c\x2d\x30\x2e\x31\x39\x34\x34\x38\x37\x31\x34\x2c\x2d\ +\x30\x2e\x39\x38\x30\x39\x30\x35\x30\x35\x2c\x34\x37\x38\x2e\x31\ +\x33\x32\x30\x32\x2c\x31\x32\x30\x33\x2e\x34\x34\x30\x39\x29\x22\ +\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\ +\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ \x00\x00\x08\x8b\ \x00\ \x00\x1c\x9e\x78\x9c\xed\x58\xdf\x8f\x9b\x48\x12\x7e\xcf\x5f\xe1\ @@ -26893,6 +30073,300 @@ qt_resource_data = "\ \x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x20\x2f\x3e\x0a\x20\x20\ \x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\ \x73\x76\x67\x3e\x0a\ +\x00\x00\x12\x3b\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x4d\x69\x64\x70\x6f\ +\x69\x6e\x74\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\x5f\x65\x78\x74\x65\ +\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\x73\x76\x67\x2e\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x64\x65\ +\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\ +\x32\x37\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\ +\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\ +\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\ +\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\ +\x34\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\ +\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x34\x32\x37\ +\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\ +\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\ +\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\ +\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\ +\x30\x2e\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\ +\x38\x32\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\ +\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\ +\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\x3d\x22\x32\ +\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x66\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\ +\x31\x38\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\ +\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\ +\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\ +\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\ +\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\ +\x6f\x70\x33\x31\x34\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\ +\x33\x31\x34\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\ +\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\ +\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\ +\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\ +\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\x61\ +\x64\x69\x65\x6e\x74\x34\x32\x37\x32\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\ +\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ +\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\ +\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\ +\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\ +\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\ +\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\ +\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\ +\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\ +\x72\x73\x70\x65\x63\x74\x69\x76\x65\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\x3d\x22\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x33\x64\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x76\x70\x5f\x78\x3d\x22\x30\x20\x3a\x20\x33\x32\x20\x3a\ +\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x76\x70\x5f\x79\x3d\x22\x30\x20\x3a\x20\x31\x30\ +\x30\x30\x20\x3a\x20\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x7a\x3d\x22\x36\x34\ +\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\ +\x33\x64\x2d\x6f\x72\x69\x67\x69\x6e\x3d\x22\x33\x32\x20\x3a\x20\ +\x32\x31\x2e\x33\x33\x33\x33\x33\x33\x20\x3a\x20\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x65\x72\x73\x70\x65\ +\x63\x74\x69\x76\x65\x32\x37\x33\x34\x22\x20\x2f\x3e\x0a\x20\x20\ +\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\ +\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\ +\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ +\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x37\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x33\x38\x35\x30\x2d\x39\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\ +\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\ +\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\ +\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\ +\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\ +\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\ +\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\ +\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\ +\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\ +\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\ +\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\ +\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\ +\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x33\x31\x34\x34\x2d\x37\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\ +\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\ +\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\x70\ +\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\ +\x31\x34\x36\x2d\x30\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\ +\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\ +\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\x72\ +\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\x70\ +\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\x33\ +\x31\x34\x38\x2d\x33\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\ +\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\ +\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\x6f\x64\ +\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\ +\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\ +\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\ +\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\ +\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\ +\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\ +\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\ +\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x33\x2e\x38\ +\x38\x39\x30\x38\x37\x33\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x2d\x32\x35\x2e\x32\x31\ +\x36\x30\x32\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x63\x79\x3d\x22\x32\x35\x2e\x38\x30\x36\x38\x37\ +\x34\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\ +\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\ +\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\ +\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\x64\ +\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\ +\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\ +\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\x35\x22\ +\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\ +\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\ +\x2d\x79\x3d\x22\x32\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\ +\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\x20\ +\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\ +\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x37\x33\x31\x22\ +\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\ +\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\ +\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\ +\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\ +\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\ +\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\ +\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\ +\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\ +\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\ +\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\ +\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\ +\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\ +\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\ +\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\ +\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\ +\x78\x28\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x30\x2c\x30\x2c\ +\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x36\x2e\x33\x36\x30\x35\ +\x39\x38\x36\x2c\x2d\x36\x36\x2e\x31\x30\x38\x38\x30\x36\x29\x22\ +\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\ +\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\ +\x3a\x23\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\ +\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\ +\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\ +\x3a\x23\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x77\x69\x64\x74\x68\x3a\x32\x39\x2e\x34\x39\x34\x33\x34\x36\x36\ +\x32\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\ +\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\ +\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\ +\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\ +\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\ +\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\ +\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\ +\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\ +\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\ +\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\ +\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\ +\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\ +\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x64\x3d\x22\x6d\x20\x32\x38\x32\x2e\x31\x31\x33\x38\x37\x2c\ +\x34\x34\x39\x2e\x36\x37\x34\x35\x35\x20\x2d\x39\x34\x2e\x37\x30\ +\x34\x38\x39\x2c\x38\x36\x2e\x39\x36\x35\x39\x38\x20\x63\x20\x2d\ +\x39\x2e\x32\x32\x34\x38\x32\x2c\x2d\x33\x2e\x39\x31\x32\x33\x35\ +\x20\x2d\x31\x39\x2e\x33\x33\x37\x38\x34\x2c\x2d\x36\x2e\x32\x37\ +\x32\x33\x20\x2d\x32\x39\x2e\x39\x32\x36\x30\x32\x2c\x2d\x36\x2e\ +\x35\x31\x37\x37\x39\x20\x2d\x34\x35\x2e\x37\x32\x38\x36\x38\x2c\ +\x2d\x31\x2e\x30\x36\x30\x32\x37\x20\x2d\x38\x33\x2e\x36\x32\x39\ +\x38\x31\x33\x2c\x33\x36\x2e\x30\x31\x35\x31\x39\x20\x2d\x38\x34\ +\x2e\x36\x36\x38\x37\x33\x39\x2c\x38\x32\x2e\x36\x38\x32\x38\x35\ +\x20\x2d\x30\x2e\x32\x30\x31\x32\x36\x2c\x39\x2e\x30\x34\x30\x35\ +\x34\x20\x31\x2e\x30\x37\x33\x30\x33\x33\x2c\x31\x37\x2e\x36\x35\ +\x38\x36\x38\x20\x33\x2e\x34\x36\x37\x30\x33\x38\x2c\x32\x35\x2e\ +\x38\x38\x34\x39\x35\x20\x6c\x20\x2d\x39\x32\x2e\x38\x38\x30\x31\ +\x34\x32\x2c\x38\x35\x2e\x32\x38\x39\x39\x37\x20\x34\x33\x2e\x34\ +\x32\x39\x32\x32\x31\x2c\x34\x39\x2e\x33\x34\x39\x20\x39\x31\x2e\ +\x30\x35\x35\x33\x38\x32\x2c\x2d\x38\x33\x2e\x36\x31\x33\x39\x37\ +\x20\x63\x20\x31\x30\x2e\x37\x39\x33\x36\x35\x2c\x35\x2e\x36\x36\ +\x30\x31\x34\x20\x32\x32\x2e\x38\x31\x38\x33\x31\x2c\x39\x2e\x31\ +\x39\x37\x31\x37\x20\x33\x35\x2e\x37\x36\x35\x32\x35\x2c\x39\x2e\ +\x34\x39\x37\x33\x36\x20\x34\x35\x2e\x37\x32\x38\x36\x38\x2c\x31\ +\x2e\x30\x36\x30\x32\x36\x20\x38\x33\x2e\x38\x31\x32\x32\x38\x2c\ +\x2d\x33\x36\x2e\x30\x31\x35\x31\x39\x20\x38\x34\x2e\x38\x35\x31\ +\x32\x2c\x2d\x38\x32\x2e\x36\x38\x32\x38\x36\x20\x30\x2e\x32\x35\ +\x33\x37\x31\x2c\x2d\x31\x31\x2e\x33\x39\x36\x30\x37\x20\x2d\x31\ +\x2e\x38\x37\x30\x31\x36\x2c\x2d\x32\x32\x2e\x32\x30\x33\x35\x37\ +\x20\x2d\x35\x2e\x36\x35\x36\x37\x34\x2c\x2d\x33\x32\x2e\x32\x31\ +\x36\x35\x31\x20\x6c\x20\x39\x32\x2e\x38\x38\x30\x31\x34\x2c\x2d\ +\x38\x35\x2e\x32\x38\x39\x39\x37\x20\x2d\x34\x33\x2e\x36\x31\x31\ +\x37\x2c\x2d\x34\x39\x2e\x33\x34\x39\x30\x31\x20\x7a\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x65\x63\x74\ +\x32\x32\x36\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\ +\x72\x2d\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\ +\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x2f\ +\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ \x00\x00\x0d\x5b\ \x00\ \x00\x43\x5b\x78\x9c\xed\x5b\x59\x6f\xe3\x46\x12\x7e\x9f\x5f\xc1\ @@ -28257,6 +31731,215 @@ qt_resource_data = "\ \x1d\xf9\xce\x6b\x06\xfa\x4c\x06\x12\xcf\xe8\xb8\xe7\x33\x90\xb0\ \xbf\xf3\x0c\xd4\x7f\x6c\x3f\x84\x5f\x17\xf4\x27\xb6\xef\xbe\xf9\ \x6f\x78\x95\xb1\x1d\ +\x00\x00\x0c\xed\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x50\x65\x72\x70\x65\ +\x6e\x64\x69\x63\x75\x6c\x61\x72\x2e\x73\x76\x67\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\ +\x5f\x65\x78\x74\x65\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\ +\x73\x76\x67\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\ +\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\ +\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x64\x65\x66\x73\x32\x37\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\ +\x3c\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\ +\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x36\x22\x20\x2f\x3e\x0a\x20\ +\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\ +\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\ +\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\ +\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x73\x74\x6f\x70\x33\x31\x34\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\ +\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x3e\x0a\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\x65\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\ +\x65\x3d\x22\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\ +\x70\x33\x64\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x76\x70\x5f\x78\x3d\x22\x30\x20\x3a\x20\x33\ +\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x79\x3d\x22\x30\x20\x3a\ +\x20\x31\x30\x30\x30\x20\x3a\x20\x30\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x7a\x3d\ +\x22\x36\x34\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\ +\x72\x73\x70\x33\x64\x2d\x6f\x72\x69\x67\x69\x6e\x3d\x22\x33\x32\ +\x20\x3a\x20\x32\x31\x2e\x33\x33\x33\x33\x33\x33\x20\x3a\x20\x31\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x65\x72\ +\x73\x70\x65\x63\x74\x69\x76\x65\x32\x37\x33\x34\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\ +\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\ +\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\ +\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x35\x30\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\ +\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\ +\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\ +\x72\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\ +\x32\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\x35\ +\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\ +\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\ +\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\x36\ +\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\x2f\ +\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\ +\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\ +\x77\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\ +\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\ +\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\ +\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\ +\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\ +\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\ +\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\ +\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x33\ +\x2e\x38\x38\x39\x30\x38\x37\x33\x22\x0a\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x32\x31\x2e\x38\ +\x35\x32\x31\x37\x38\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x31\x36\x2e\x32\x37\x33\x32\ +\x31\x33\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\ +\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\ +\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\ +\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\ +\x64\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\ +\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\ +\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\x35\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\ +\x77\x2d\x79\x3d\x22\x32\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\ +\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\ +\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\ +\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x37\x33\x31\ +\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\ +\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\ +\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\ +\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\ +\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\ +\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\ +\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\ +\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\ +\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\ +\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\ +\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\ +\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\ +\x0a\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x20\x20\x69\ +\x64\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\ +\x69\x78\x28\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x30\x2c\x30\ +\x2c\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x36\x2e\x33\x36\x30\ +\x35\x39\x38\x36\x2c\x2d\x36\x36\x2e\x31\x30\x38\x38\x30\x36\x29\ +\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\ +\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\ +\x6c\x3a\x23\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\ +\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\ +\x65\x3a\x23\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\ +\x2d\x77\x69\x64\x74\x68\x3a\x32\x39\x2e\x38\x37\x37\x35\x37\x33\ +\x30\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\ +\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\ +\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\ +\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\ +\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\ +\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\ +\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\ +\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\ +\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\ +\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\ +\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\ +\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\ +\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x64\x3d\x22\x6d\x20\x31\x32\x36\x2e\x33\x31\x34\x39\x36\ +\x2c\x34\x33\x39\x2e\x35\x35\x32\x32\x34\x20\x30\x2c\x32\x35\x34\ +\x2e\x37\x31\x39\x38\x33\x20\x2d\x31\x33\x37\x2e\x30\x38\x38\x35\ +\x34\x31\x2c\x30\x20\x30\x2c\x36\x39\x2e\x31\x35\x37\x32\x38\x20\ +\x33\x34\x30\x2e\x32\x35\x30\x34\x36\x31\x2c\x30\x20\x30\x2c\x2d\ +\x36\x39\x2e\x31\x35\x37\x32\x38\x20\x2d\x31\x33\x32\x2e\x35\x31\ +\x32\x38\x32\x2c\x30\x20\x30\x2c\x2d\x32\x35\x34\x2e\x37\x31\x39\ +\x38\x33\x20\x2d\x37\x30\x2e\x36\x34\x39\x31\x2c\x30\x20\x7a\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x65\ +\x63\x74\x33\x39\x34\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\ +\x74\x6f\x72\x2d\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\ +\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\ +\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ \x00\x00\x09\xad\ \x00\ \x00\x21\x35\x78\x9c\xed\x58\xdb\x6e\xe3\xc8\x11\x7d\xf7\x57\x30\ @@ -28700,6 +32383,112 @@ qt_resource_data = "\ \x75\x6d\x75\x6c\x61\x74\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\ \x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\ \x67\x3e\x0a\ +\x00\x00\x06\x71\ +\x00\ +\x00\x16\x14\x78\x9c\xdd\x57\x5b\x6f\xdb\x36\x14\x7e\xcf\xaf\xd0\ +\xd4\x97\x16\xb3\x28\x92\xba\x2b\x76\x8a\x61\x45\x8b\x02\x2d\x06\ +\xac\x2d\xf6\x58\xd0\x12\x6d\x6b\x91\x25\x81\xa2\x63\x3b\xbf\x7e\ +\x87\xd4\x3d\x56\xb2\x74\x97\x0e\x98\x8d\x44\xe2\xb9\xf3\xf0\x3b\ +\x87\xc7\xcb\xd7\xa7\x7d\x6e\xdc\x71\x51\x67\x65\xb1\x32\x09\xc2\ +\xa6\xc1\x8b\xa4\x4c\xb3\x62\xbb\x32\xbf\x7c\x7e\x6b\x85\xa6\x51\ +\x4b\x56\xa4\x2c\x2f\x0b\xbe\x32\x8b\xd2\x7c\x7d\x73\xb5\xfc\xc1\ +\xb2\x8c\x9f\x05\x67\x92\xa7\xc6\x31\x93\x3b\xe3\x7d\x71\x5b\x27\ +\xac\xe2\xc6\xcb\x9d\x94\x55\x6c\xdb\xc7\xe3\x11\x65\x2d\x11\x95\ +\x62\x6b\xbf\x32\x2c\xeb\xe6\xea\x6a\x59\xdf\x6d\xaf\x0c\xc3\x00\ +\xbf\x45\x1d\xa7\xc9\xca\x6c\x15\xaa\x83\xc8\xb5\x60\x9a\xd8\x3c\ +\xe7\x7b\x5e\xc8\xda\x26\x88\xd8\xe6\x20\x9e\x0c\xe2\x89\xf2\x9e\ +\xdd\xf1\xa4\xdc\xef\xcb\xa2\xd6\x9a\x45\xfd\x62\x24\x2c\xd2\x4d\ +\x2f\xad\xa2\x39\x3a\x5a\x88\x44\x51\x64\x63\x6a\x53\x6a\x81\x84\ +\x55\x9f\x0b\xc9\x4e\xd6\x54\x15\x62\x9c\x53\xa5\x18\x63\x1b\x78\ +\x83\xe4\xf3\xa4\xe2\x53\x0e\xa9\x78\x34\x18\xcd\x1d\x7b\x87\xf4\ +\x57\xf0\xd7\x2b\x74\x04\x54\x97\x07\x91\xf0\x0d\x68\x72\x54\x70\ +\x69\xbf\xf9\xfc\xa6\x67\x5a\x18\xa5\x32\x1d\x99\xe9\xb2\x3f\xf1\ +\x3b\x39\x92\x82\xed\x79\x5d\xb1\x84\xd7\x76\x47\xd7\xfa\xc7\x2c\ +\x95\xbb\x95\xe9\xbb\xd5\x49\xaf\x77\x3c\xdb\xee\xe4\x88\x90\xa5\ +\x2b\x13\x76\x48\x03\xea\xeb\x75\x17\x43\xdc\x23\x09\x23\x87\x36\ +\xa2\xad\xe1\x31\xcb\x0d\x11\x31\x44\x14\xf8\x78\xaa\x9d\x96\x89\ +\x0a\x69\x65\x7e\x2a\x58\xf5\xf5\x9d\xc8\x52\xd4\xe5\xb1\x37\x53\ +\x1e\x64\x75\x90\x5f\xf9\x49\xf2\xa2\xb1\x07\x3b\x19\x6d\x4b\xb3\ +\x95\x1a\x9a\x6c\x69\x04\x71\x62\xde\x00\x65\x99\xf2\x4d\xad\x38\ +\xcd\x6e\xd4\x0a\xb6\x13\x6a\x1e\x70\xe1\x48\x38\x13\xef\x04\x4b\ +\x33\x00\x62\x23\x37\x8a\x22\x29\xf3\x9c\x27\x90\x12\x96\x1f\xd9\ +\xb9\x36\x7b\x01\x30\x35\x55\x75\x88\xeb\xb6\x46\xc1\x6c\x2d\xcb\ +\xaa\x93\x85\x8d\xcb\x73\x0e\xbb\x55\x44\x0b\x2c\x96\x22\x7e\xb1\ +\xd1\x9f\x6b\x4d\x2a\xe1\x68\x32\x79\x8e\xc9\xb5\x39\xe8\x94\x9b\ +\x4d\xcd\xc1\x31\x1e\xd1\xf4\x71\x80\x06\xf8\xf2\x4d\xc3\xfe\x7b\ +\xde\xf0\x9c\x37\x32\xef\x2d\xec\xbd\x2d\xed\xe9\xb6\x5b\x6a\x9f\ +\xb0\x0a\xf2\x5f\x41\xc6\xa0\x62\x3b\x4b\xfd\xb1\xcb\xb3\x02\xe9\ +\x54\xd4\x49\xcd\x8b\xa4\xdf\x55\x5f\x4f\xb0\x71\x23\x36\x1c\x0a\ +\xff\xc8\xac\xc4\xb9\x91\x20\x50\x84\xf0\xc0\xb3\x32\xf7\x0a\xca\ +\x4f\x98\x69\x23\xb0\x4a\x91\x6d\x33\xc0\x8c\x96\xa3\x04\x39\xfa\ +\x33\xd5\x81\x64\x8c\xf6\x46\x03\xc7\x1d\x72\xa2\x72\xc1\xf2\x6f\ +\x06\x91\xee\x07\xf1\x4e\x70\xe8\x5f\x2f\x66\xd0\x34\xf6\x3d\x75\ +\xe1\x84\xde\xb0\xe3\x6d\x4b\xfc\x52\x64\x12\x1a\xd5\xa1\xe6\xe2\ +\x93\x2a\xf6\x5f\x8a\x2f\x35\xbf\x90\xfa\x2c\x58\x51\x43\x67\xd9\ +\xaf\xcc\x3d\x93\x22\x3b\xbd\x24\x0b\xac\xbe\xc8\x8f\x42\x8f\x46\ +\x2e\xbc\x53\x4c\x51\x48\x43\xdf\x79\xd5\xab\x27\x70\x22\x94\x7a\ +\x88\xfa\x2e\xa6\x03\x15\x4e\xc1\x0f\x28\x0a\xa2\xc0\xf1\x7b\xea\ +\x66\x56\x76\x33\x2b\x2b\x20\xeb\x2e\x72\x5c\x8f\x84\xe1\xbf\x9d\ +\x50\x8b\xfc\x49\x4a\x2d\xf7\xff\x9c\xd4\x7f\xb4\xd5\x59\xe4\x7b\ +\x36\x3b\x2b\xfa\xbe\xed\xce\x7a\xba\xe1\x2d\x6d\x75\x8d\xe8\xb7\ +\xbe\xb9\xa9\x0b\x2d\xbd\xcb\xf8\x71\xb8\x6b\xd6\xac\x87\x4a\xc5\ +\xb6\x5c\x07\x07\xc0\x6c\xa2\x6b\x19\xeb\x52\xa4\x5c\x74\x2c\x5f\ +\x7f\x26\xac\x36\xfe\x66\x66\xbb\x9a\x1e\x99\xb2\xda\xf3\xf1\x3c\ +\xbf\xde\xb1\xb4\x3c\x02\x76\x1e\x32\xef\xcb\x12\xe0\x1a\xa0\x20\ +\x08\x49\xe0\xfa\x0f\xd9\x0a\x9b\x8e\x8f\xdc\x88\x86\x0e\xb9\x60\ +\x82\x3f\x07\xa3\x30\xf2\x7d\xcf\xbb\x60\x1e\x84\x80\x44\x59\x39\ +\x3b\x73\xd8\xd4\xd6\xa5\x61\xd4\xca\xd4\xbb\xf2\xb8\x15\x2a\x37\ +\x52\x1c\xf8\x43\x45\x18\x0b\x0e\x6a\x1c\xb4\x0e\x4d\xd1\xb5\x43\ +\xc8\x48\x42\xe9\x5a\xeb\x75\x79\x9a\x37\x70\xcc\x0a\xd8\xab\xd5\ +\x8e\x35\x84\x86\x17\x19\x69\x25\xba\x41\x27\xb8\x8c\xbe\x95\x38\ +\x0d\x60\x7c\xc8\x3a\xab\x42\x7c\x84\xb7\x67\xa7\x6c\x9f\xdd\xf3\ +\x54\x61\xab\x81\xd0\x72\xcf\x25\x4b\x99\x64\x03\x30\x3a\x0a\xdc\ +\x22\x5d\x19\x2d\x61\x46\x8d\x7f\x7d\xf3\xb6\x07\x79\x92\xc4\xbf\ +\x95\xe2\x76\xc0\xa7\x12\x60\x6b\x98\x7b\x56\x66\x5f\x7a\x6a\xbc\ +\x49\x62\xd5\x78\x98\xbc\xc9\xf6\x70\xdc\x6a\x20\xfd\x11\xe6\x42\ +\x80\x68\xcf\x98\x08\xab\x4b\x78\x30\xda\x98\x15\xbc\x19\x38\x67\ +\x67\xf4\x34\xd9\x67\x4a\xc9\xfe\x24\xb3\x3c\x7f\xaf\x9c\x8c\x8a\ +\xb1\x35\x9a\xc9\x9c\x8f\x2a\xd4\x6e\xa3\xef\x4a\x68\xb4\xb9\xa5\ +\xdd\xed\x5e\xaf\xb6\x43\x56\x34\x5e\x2e\xa0\x96\xb3\x35\xcf\x57\ +\xe6\x07\xc5\x34\x2e\xb8\x5b\x51\x1e\xaa\x7d\x99\xf2\x56\xbd\xcb\ +\xe6\x76\xdc\xbd\xc6\x08\x34\x0c\x79\xd1\xab\x31\x22\x3e\x05\xb4\ +\xd0\xb6\x67\x77\x2b\x1f\x39\x3e\xf6\xa2\xd0\x5f\x58\xbe\x8f\x08\ +\x0e\x43\xec\xbf\x1a\xda\x5e\xc5\xe4\x6e\xd4\x86\x1e\x99\x72\x9a\ +\x56\x33\xee\x33\x1d\x47\x35\x94\x03\xc0\x5c\x5f\x0b\x2e\x0d\xc8\ +\x9c\x50\x33\x9a\x30\xc8\xc0\x47\x83\x50\x14\x61\x9f\x7a\x46\x80\ +\xb0\x43\xe0\xf9\x61\x20\x11\x1f\x56\x2e\x8a\x9c\x60\xfa\x0e\xd3\ +\x8c\xef\xf9\x53\xd9\x39\x9a\x3b\xd2\x19\xbf\x7b\x33\xb2\xb3\xb4\ +\x10\xb9\x7e\x18\x68\x5a\x88\xbc\xc7\x48\x83\xa6\x8b\x2f\xad\x0d\ +\xb4\x41\xd5\xf5\x2f\xac\xf5\xa4\x41\xd3\x83\xf3\x99\xa5\x34\x7b\ +\x69\x15\x26\x0b\x7a\x21\x7b\x49\x21\x63\x85\xc9\x62\x38\x82\x3e\ +\xe8\x19\x92\x56\xe9\x36\x3f\x59\xcc\x1c\x61\x47\xba\x37\x3e\xf6\ +\x62\x74\x26\x39\x73\x34\x77\x6c\x7b\xb2\xe8\xa5\xef\x8d\x11\xbe\ +\xda\x4b\xb3\xbd\x2f\xb1\xfe\x5c\x6f\xa0\xbe\xd5\x62\x0d\x53\x8a\ +\x5e\x8c\x2e\x6b\xbd\x14\x87\x9c\xc7\x45\x59\xdc\xc3\xb5\x04\xb7\ +\xab\x28\x6f\xb9\x92\xa7\x9c\xf2\x76\xd9\xf4\xde\xd8\x45\x8d\x49\ +\xec\x74\x74\x75\x89\x02\xa0\xe3\xf5\x41\xca\x31\xed\xf7\x32\x2b\ +\x62\x68\x30\x5c\x74\x54\xbd\xc8\xa1\x8b\xca\xd8\xed\x68\x43\x1c\ +\x2d\x21\x65\x70\xaf\x09\xc1\xce\x2a\x1c\x3e\xa6\x36\xf5\x06\xd7\ +\xfd\x9e\x89\x5b\x2e\x1a\xfe\x5d\x56\x67\xeb\x2c\x57\x26\xf4\x6b\ +\xce\xaf\xd3\xac\xae\xa0\x65\xc0\xaf\x67\x15\xc6\x75\x09\x3f\x1c\ +\x37\x79\x79\xec\xf9\xbc\x60\xf0\xb0\xd6\x2c\xb9\x55\x4d\xa6\x48\ +\x63\x96\xc0\xf5\x74\xc8\x99\xe4\x0f\xa6\x06\xd5\x08\x9c\x20\xf0\ +\x46\xe4\x74\x5c\xaf\x0b\x17\x11\x85\xdc\x9f\x0c\x5d\xea\x01\x8e\ +\xa2\x45\xff\x66\x60\xfd\x25\x70\x7d\x2b\xd1\x0e\x04\xb9\x81\x17\ +\x0d\x06\x2d\x4f\x3d\x16\xf8\x49\x75\x8a\xb0\x2a\xd7\x05\x60\x4c\ +\x69\x7a\xed\x99\x3f\xa5\xd2\x14\xf8\x82\xba\x48\x79\xeb\x9c\xe0\ +\x05\x00\xa7\x51\xfe\x26\xc7\xee\x37\x3b\xf6\x1e\x3a\x76\x50\xa4\ +\x0b\x9c\x3d\xe9\x2e\x74\x75\xd4\xcd\x53\xeb\x6b\x8f\x60\xe1\x39\ +\x7a\xd6\xa0\x88\x17\x56\xe7\x91\xf8\xbd\x91\xff\x32\x0c\x1f\x05\ +\x0a\x27\x7f\xc9\xc6\x73\x12\xdf\x34\xb5\x85\xeb\x20\xa2\x65\x73\ +\xc3\x1a\x5c\x82\x8d\xfe\xe4\xbf\x53\x20\xe4\xb1\x40\x1a\xe0\x3f\ +\x89\xa1\xa6\x0d\x77\x95\x95\x1b\xd6\x70\x00\x4f\xe9\x39\xe1\xa3\ +\x65\x36\x01\xc1\x33\x42\x68\x1b\xec\x6c\x08\xf7\xc6\xde\x00\x36\ +\xfc\xe6\x43\x4e\x73\x8f\x8c\x6c\x0f\x05\x36\x75\xd9\xd3\xef\x47\ +\x8d\xe4\x72\x5a\x81\xc8\xfc\x20\xf2\x42\x57\x4f\x2b\xc3\xca\xa2\ +\x21\x22\x0e\x26\x2e\x84\x84\x61\xac\xf7\x7c\x27\x78\x35\xfa\x19\ +\xb3\x6d\xa6\x2f\x78\x2c\xd5\x90\x78\x73\xf5\x07\xc6\xbb\xc6\xcf\ +\ \x00\x00\x05\xc0\ \x00\ \x00\x13\xbe\x78\x9c\xd5\x57\x59\x73\xdb\x36\x10\x7e\xf7\xaf\x60\ @@ -28794,6 +32583,354 @@ qt_resource_data = "\ \xe6\x77\x5b\x82\xcc\x0b\xcd\x22\xfc\x47\x30\x78\xae\xeb\xfd\xb4\ \x5a\x79\x11\x19\xe2\x7f\x1d\x32\xff\xd5\xf2\x39\xc2\x32\xee\xa7\ \xb5\xf5\xed\xd5\x5c\x4d\x4b\xb7\x57\x7f\x02\xb2\xe9\xd6\x37\ +\x00\x00\x05\xac\ +\x00\ +\x00\x1c\xdf\x78\x9c\xed\x59\x5b\x6f\x9b\x48\x14\x7e\xf7\xaf\x60\ +\xe9\x4b\xab\x0d\x30\x0c\x18\x03\xb1\xd3\x87\xad\xba\xaa\xb4\x52\ +\xa5\x4d\xab\x7d\xac\xc6\x30\xc6\xb3\x01\x06\x0d\x83\x2f\xf9\xf5\ +\x7b\x86\x3b\xb6\xb7\xb1\x56\x5a\xe7\x25\x44\x09\xcc\xb9\x9f\x33\ +\xdf\x39\xa0\xc9\xf2\xe3\x21\x4b\xb5\x1d\x15\x25\xe3\xf9\x4a\xb7\ +\x4d\xa4\x6b\x34\x8f\x78\xcc\xf2\x64\xa5\x7f\xff\xf6\xd9\xf0\x75\ +\xad\x94\x24\x8f\x49\xca\x73\xba\xd2\x73\xae\x7f\x7c\x98\x2d\x7f\ +\x31\x0c\xed\x37\x41\x89\xa4\xb1\xb6\x67\x72\xab\x7d\xc9\x9f\xca\ +\x88\x14\x54\x7b\xbf\x95\xb2\x08\x2d\x6b\xbf\xdf\x9b\xac\x25\x9a\ +\x5c\x24\xd6\x07\xcd\x30\x1e\x66\xb3\x65\xb9\x4b\x66\x9a\xa6\x81\ +\xdf\xbc\x0c\xe3\x68\xa5\xb7\x0a\x45\x25\xd2\x5a\x30\x8e\x2c\x9a\ +\xd2\x8c\xe6\xb2\xb4\x6c\xd3\xb6\xf4\x41\x3c\x1a\xc4\x23\xe5\x9d\ +\xed\x68\xc4\xb3\x8c\xe7\x65\xad\x99\x97\xef\x46\xc2\x22\xde\xf4\ +\xd2\x2a\x9a\xbd\x53\x0b\xd9\x41\x10\x58\x08\x5b\x18\x1b\x20\x61\ +\x94\xc7\x5c\x92\x83\x31\x55\x85\x18\x2f\xa9\x62\x84\x90\x05\xbc\ +\x41\xf2\x3a\xa9\xf0\x90\x42\x29\xfe\x35\x98\x9a\x3b\xf6\x0e\xe5\ +\x2f\xe0\xb7\x57\xe8\x08\x66\xc9\x2b\x11\xd1\x0d\x68\x52\x33\xa7\ +\xd2\xfa\xf4\xed\x53\xcf\x34\x90\x19\xcb\x78\x64\xa6\xab\xfe\xc4\ +\xef\x64\x4b\x72\x92\xd1\xb2\x20\x11\x2d\xad\x8e\x5e\xeb\xef\x59\ +\x2c\xb7\x2b\xdd\x73\x8b\x43\xbd\xde\x52\x96\x6c\xe5\x88\xc0\xe2\ +\x95\x0e\x19\xe2\x05\xf6\xea\x75\x17\x43\xd8\x23\x09\x99\x0e\x6e\ +\x44\x5b\xc3\x63\x96\xeb\x9b\xb6\x26\x82\x85\x87\xa6\xda\x31\x8f\ +\x54\x48\x2b\xfd\x31\x27\xc5\x8f\xaf\x42\x6e\xb9\xd9\x15\xb2\xb7\ +\xc3\x2b\x59\x54\xf2\x07\x3d\x48\x9a\x37\x06\x21\x95\x51\x5e\x35\ +\x5b\xa9\x99\x93\x9c\x46\x18\xb7\xf5\x07\xa0\x2c\x63\xba\x29\x15\ +\xa7\x49\x47\xad\x20\x1f\xbf\xe6\x01\xb7\xf7\x57\x80\x62\x41\x23\ +\x85\xb5\x46\x7a\x14\xb0\x3c\xaa\xf2\x4e\x45\x9d\x66\x0f\xb4\x49\ +\xee\xc5\x8f\x03\x24\xae\x85\x9a\x83\xe1\x8f\x7d\x51\xe2\xd8\x48\ +\xd8\x00\x1f\xb8\xa1\x8b\x32\xcf\x6a\x13\x7e\x62\xa6\x8d\xc0\xe0\ +\x82\x25\x0c\x92\xad\xe5\xb0\x6d\x3a\xf5\x35\xd5\x81\xa4\x47\xb9\ +\xe1\x85\xe3\xea\x9a\xd5\x66\x2f\x48\xcc\x48\xfa\xbb\xba\x41\x1f\ +\x9e\xb9\x89\x78\x9a\x82\xda\x4a\x27\xe9\x9e\x1c\xcb\xde\x66\x8d\ +\xe4\x70\x2b\x28\x74\xde\x3b\x78\xa6\x44\x74\x36\x1c\xdb\x75\x8d\ +\xc5\xc4\xfb\xd4\x89\xe3\xcf\x91\x81\x7b\x81\xa4\x25\x7f\xcf\x99\ +\x84\x36\xab\x4a\x2a\x1e\x15\x54\xbf\xe6\xdf\x4b\x7a\x26\xf5\x4d\ +\x90\xbc\x84\xbe\xc8\x56\x7a\x46\xa4\x60\x87\xf7\xf6\x1d\x52\x3f\ +\xa6\x17\xf8\x73\x1c\xb8\xf0\x8c\x11\x36\x7d\xec\x7b\xce\x87\x5e\ +\x3d\x82\x5d\xc1\x78\x6e\x62\xcf\x45\x83\xeb\x08\x76\xc2\x5b\x60\ +\x73\x11\x2c\x1c\xaf\xa7\x6e\x2e\xca\x6e\x2e\xca\x0a\xa8\xbc\x6b\ +\x3a\xee\xdc\xf6\xfd\xa1\xa8\xd3\x82\x5c\x5d\x54\x55\xaa\x8b\xb5\ +\x7c\x68\x25\x96\xa5\xe4\x45\x27\x0d\xe8\x94\xc7\x14\x50\xa9\x88\ +\x06\xd8\xe4\x22\x7c\xb7\xa9\xaf\xfb\x9a\xc4\xa1\x8a\x4c\x1e\x43\ +\xfb\x5e\x1f\x74\xf8\x66\x53\x52\x70\x8d\x46\xb4\xba\xc9\x41\x03\ +\xbc\x79\xc6\x80\x8d\xff\xea\x0f\x5d\xf2\x67\x5f\xf6\xe7\x8f\xfc\ +\x2d\xad\x69\xf2\xff\x2f\x42\xe7\x2f\x21\x74\xf1\x86\xd0\x6b\x11\ +\x3a\xbf\x29\x42\xbd\x1b\x23\x74\xfe\x4a\x08\x75\x5e\x44\x28\x7a\ +\x83\xe8\xb5\x10\x75\x6e\x0a\x51\x7c\x63\x88\x3a\xaf\x04\x51\xfb\ +\x25\x88\xce\xdf\x10\x7a\x2d\x42\xed\x9b\x22\x74\x7e\x63\x84\xda\ +\xaf\x84\xd0\xe0\x25\x84\x3a\x6f\x08\xbd\x16\xa1\xc1\x4d\x11\x1a\ +\xdc\x1a\xa1\xf8\x95\x20\x8a\x5f\x82\xa8\xf7\x06\xd1\x6b\x21\x8a\ +\x6f\x0a\x51\x74\x63\x88\xbe\x16\x42\xdd\x17\x11\xfa\x36\x45\xaf\ +\x86\xa8\x7b\x53\x88\x2e\x6e\x3d\x45\x7f\xfe\x29\xba\xb4\xd4\xf1\ +\x5b\xfd\xd4\x9f\xad\xa9\x93\xc0\x78\xc7\xe8\x7e\xd6\x9b\x5b\x93\ +\x1e\x2b\x05\x49\x68\x1d\x1d\x40\xb3\x09\xaf\x65\xac\xb9\x88\xa9\ +\xe8\x58\x5e\x7d\x4d\x58\x6d\x02\xcd\x61\xf7\x6c\xba\x67\xca\x6a\ +\xcf\x47\x97\xf9\xe5\x96\xc4\x7c\x0f\xe0\x39\x65\x3e\x73\x0e\x78\ +\x05\xec\xcc\x4f\x39\x0a\x97\x36\x36\x6d\xc7\x07\xfc\x9c\xf2\xc0\ +\x13\x56\xe0\x5a\xb8\xc1\x39\xb3\x12\x02\x4a\x64\xa4\xe4\x48\x21\ +\x9d\xc4\xc5\x7e\xf7\xe5\x52\x6e\xf9\x3e\x11\xaa\x2a\x52\x54\xf4\ +\x54\x31\xe6\x51\xa5\x4e\xd0\x8d\xaa\xe9\xb7\xf6\xdc\x76\x24\xa1\ +\x74\x8d\xf5\x9a\x1f\x2e\x1b\xd8\xb3\x1c\xb2\x34\xda\x93\x60\x1b\ +\xfb\x67\xb5\x68\x25\xba\xb3\xe1\xc5\xfc\x2c\xed\x56\xe2\x30\xe0\ +\xf0\x94\xa5\x72\x3f\xab\x63\xcb\xcb\xc8\x81\x65\xec\x99\xc6\x0a\ +\x56\x0d\x78\x96\x19\x95\x24\x26\x92\x0c\x90\xe8\x28\x78\xe1\x74\ +\x5f\xca\x4b\x11\x6f\xc2\x3f\x3f\x7d\xee\xf1\x1d\x45\xe1\x5f\x5c\ +\x3c\x0d\xd0\x54\x02\x64\xcd\x2b\x08\xbb\xef\x3a\x75\x20\x1c\x85\ +\x6a\xe6\x10\xf9\xc0\x32\xd8\x68\x75\x86\xff\xeb\x21\x4b\x01\x9c\ +\x3d\x63\x22\xac\x4e\x7f\x07\xa3\x8d\x59\x41\x9b\x33\xfa\x8b\xff\ +\xd6\x88\xa3\x8c\x29\x25\xeb\x51\xb2\x34\xfd\xa2\x9c\x8c\xfa\xb0\ +\x35\xca\x64\x4a\x47\xcd\x69\xb5\xd1\x77\xcd\x33\x4a\x6e\x69\x75\ +\xd9\xd7\xab\x64\xa8\x4a\x8d\x17\xfb\xb4\xb0\x29\x59\xd3\x74\xa5\ +\xff\xa1\x98\xda\x19\x37\x11\xbc\x2a\x32\x1e\xd3\x56\xbd\xab\x66\ +\x32\x1e\x5c\x63\x04\x6a\x9a\x3c\x1b\xd3\xc8\xb4\x3d\x0c\x68\xc1\ +\xed\xb8\xee\x56\x9e\xe9\x78\x68\x1e\xf8\xde\x9d\xe1\x79\xa6\x8d\ +\x7c\x1f\x79\x1f\x86\x89\x57\x10\xb9\x3d\x9b\x40\xed\xf0\x41\xf5\ +\x75\xbf\x81\x8a\xa9\xc5\x1a\x46\x7e\xbd\x18\x4d\xbe\x7a\x29\xaa\ +\x94\x86\x39\xcf\x9f\xa1\xc5\x61\x54\x09\xfe\x44\x95\x3c\xa6\x98\ +\xb6\xcb\x06\xcd\x21\x74\x9b\xed\x41\x2c\x01\xb2\x3b\x86\x9a\x48\ +\x50\x84\x70\x5d\x49\x39\xa6\xfd\xcd\x59\x1e\x42\x5d\xf2\xb8\xa3\ +\xc2\x06\x52\x91\x02\x30\x65\xe8\x76\xb4\x21\x90\x96\x10\x13\x18\ +\x12\x42\x90\xa3\x8a\x87\x8e\xa9\xcd\xa0\x84\xe1\x99\x11\xf1\x44\ +\x45\xc3\xdf\xb1\x92\xad\x59\xaa\x4c\xd4\x8f\x29\xbd\x8f\x59\x59\ +\xc0\x2e\x84\x2c\x57\x61\xdc\xf3\x1d\x15\x9b\x94\xef\x7b\x3e\xcd\ +\x09\xdc\x8c\x35\x89\x9e\x92\x3a\xbe\x90\x44\xd0\xf1\x55\x4a\x24\ +\x1d\xcd\x60\xd5\x20\x1a\x8c\x1d\x13\x05\x0e\x76\xee\xdc\x85\x67\ +\xe2\xc0\x77\x34\x74\x17\x04\xa6\xef\xb9\x76\xa0\x19\xdd\xd3\x1d\ +\x02\xb2\x1b\x98\xb0\x37\xb6\xaf\x4d\xa8\xed\xc2\xd7\x3a\x76\x4d\ +\x35\x7a\xf2\x44\xd8\xe8\x6d\x4c\x4d\x1b\x83\xcb\x91\x99\xe7\x93\ +\x37\x86\x80\x57\xa6\x87\x7c\x67\x4c\x1e\xde\xa8\x39\x6c\x93\xe4\ +\xc2\x80\xb9\xb8\x23\xb2\x12\x54\x8d\x96\xe1\xc5\x92\x34\x5d\x01\ +\xb7\xa5\x6a\xde\x87\xd9\x3f\xeb\x1f\x07\xd5\ +\x00\x00\x0f\xce\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x50\x61\x72\x61\x6c\ +\x6c\x65\x6c\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\x5f\x65\x78\x74\x65\ +\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\x73\x76\x67\x2e\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x64\x65\ +\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\ +\x32\x37\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\x65\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\ +\x3a\x74\x79\x70\x65\x3d\x22\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x70\x65\x72\x73\x70\x33\x64\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x78\x3d\x22\x30\ +\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x79\x3d\ +\x22\x30\x20\x3a\x20\x31\x30\x30\x30\x20\x3a\x20\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\ +\x70\x5f\x7a\x3d\x22\x36\x34\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x70\x65\x72\x73\x70\x33\x64\x2d\x6f\x72\x69\x67\x69\x6e\ +\x3d\x22\x33\x32\x20\x3a\x20\x32\x31\x2e\x33\x33\x33\x33\x33\x33\ +\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\x65\x32\x37\x33\x34\ +\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\ +\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\ +\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\ +\x2d\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\ +\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x35\ +\x30\x2d\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\ +\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\ +\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\ +\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\ +\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\ +\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\ +\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\x3d\ +\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\ +\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\ +\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\ +\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x34\x22\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x36\x2d\x32\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x38\x2d\x30\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ +\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\ +\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\ +\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x62\x61\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\ +\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\ +\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\ +\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\ +\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\ +\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\ +\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\ +\x6f\x6d\x3d\x22\x33\x2e\x38\x38\x39\x30\x38\x37\x33\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\ +\x22\x32\x38\x2e\x31\x31\x37\x31\x32\x36\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x35\x33\ +\x2e\x36\x36\x35\x37\x37\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\ +\x61\x79\x65\x72\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\ +\x20\x20\x73\x68\x6f\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\ +\x70\x78\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x67\x72\x69\x64\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\ +\x32\x38\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\ +\x3d\x22\x37\x35\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x32\x32\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\ +\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\ +\x20\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\ +\x61\x32\x37\x33\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\ +\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\ +\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\ +\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\ +\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\ +\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\ +\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\ +\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x3e\ +\x3c\x2f\x64\x63\x3a\x74\x69\x74\x6c\x65\x3e\x0a\x20\x20\x20\x20\ +\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\ +\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\ +\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\ +\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\ +\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\ +\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x74\ +\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\ +\x28\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x30\x2c\x30\x2c\x30\ +\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x36\x2e\x33\x36\x30\x35\x39\ +\x38\x36\x2c\x2d\x36\x36\x2e\x31\x30\x38\x38\x30\x36\x29\x22\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x72\x65\x63\x74\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\ +\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\ +\x23\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\ +\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\ +\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\ +\x23\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\ +\x69\x64\x74\x68\x3a\x32\x37\x2e\x38\x34\x35\x32\x33\x30\x31\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\ +\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\ +\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\ +\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\ +\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\ +\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\ +\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\ +\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\ +\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\ +\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\ +\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\ +\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\ +\x64\x3d\x22\x72\x65\x63\x74\x33\x39\x34\x32\x2d\x34\x2d\x39\x2d\ +\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x77\x69\x64\x74\ +\x68\x3d\x22\x32\x39\x33\x2e\x35\x32\x34\x39\x36\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\ +\x32\x2e\x33\x37\x32\x36\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x78\x3d\x22\x2d\x36\x31\x33\x2e\x39\x39\x39\x36\x39\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x2d\x35\x31\ +\x34\x2e\x31\x33\x39\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\ +\x69\x78\x28\x2d\x30\x2e\x38\x34\x31\x33\x32\x37\x36\x31\x2c\x2d\ +\x30\x2e\x35\x34\x30\x35\x32\x35\x35\x33\x2c\x30\x2e\x35\x33\x33\ +\x35\x39\x39\x30\x36\x2c\x2d\x30\x2e\x38\x34\x35\x37\x33\x37\x35\ +\x38\x2c\x30\x2c\x30\x29\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\x3d\x22\x61\ +\x72\x63\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\ +\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\ +\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x30\x30\x62\x32\x38\x36\x3b\x66\ +\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\ +\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\ +\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x32\x65\x32\x65\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x33\x2e\x39\x31\ +\x37\x39\x38\x38\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\ +\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\ +\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\ +\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\ +\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\ +\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\ +\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\ +\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\ +\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\ +\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\ +\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\ +\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\ +\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\x32\x39\x39\ +\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\ +\x70\x6f\x64\x69\x3a\x63\x78\x3d\x22\x33\x32\x2e\x30\x31\x32\x36\ +\x35\x33\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\ +\x69\x70\x6f\x64\x69\x3a\x63\x79\x3d\x22\x32\x36\x2e\x35\x38\x37\ +\x36\x32\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x6f\ +\x64\x69\x70\x6f\x64\x69\x3a\x72\x78\x3d\x22\x38\x2e\x38\x37\x30\ +\x39\x37\x36\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\ +\x6f\x64\x69\x70\x6f\x64\x69\x3a\x72\x79\x3d\x22\x38\x2e\x38\x37\ +\x30\x39\x37\x36\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x64\x3d\x22\x6d\x20\x34\x30\x2e\x38\x38\x33\x36\x33\x2c\x32\x36\ +\x2e\x35\x38\x37\x36\x32\x34\x20\x61\x20\x38\x2e\x38\x37\x30\x39\ +\x37\x36\x34\x2c\x38\x2e\x38\x37\x30\x39\x37\x36\x34\x20\x30\x20\ +\x31\x20\x31\x20\x2d\x31\x37\x2e\x37\x34\x31\x39\x35\x33\x2c\x30\ +\x20\x38\x2e\x38\x37\x30\x39\x37\x36\x34\x2c\x38\x2e\x38\x37\x30\ +\x39\x37\x36\x34\x20\x30\x20\x31\x20\x31\x20\x31\x37\x2e\x37\x34\ +\x31\x39\x35\x33\x2c\x30\x20\x7a\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\ +\x74\x72\x69\x78\x28\x36\x2e\x31\x36\x37\x39\x35\x38\x34\x2c\x30\ +\x2c\x30\x2c\x36\x2e\x31\x36\x37\x39\x35\x38\x34\x2c\x33\x33\x2e\ +\x37\x32\x32\x35\x30\x36\x2c\x33\x34\x35\x2e\x39\x30\x33\x37\x31\ +\x29\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\ +\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ \x00\x00\x0b\x6e\ \x00\ \x00\x2d\x39\x78\x9c\xed\x5a\x6d\x6f\xdb\xc8\x11\xfe\x9e\x5f\xc1\ @@ -28979,6 +33116,125 @@ qt_resource_data = "\ \x4b\x1e\x8f\xd8\x68\x55\x45\xac\x6f\x07\xcf\x23\x0b\x77\x08\x41\ \x2b\x25\x81\x15\x65\xa4\x15\xe6\xcb\xe5\xdb\xc5\x74\x15\xef\xe2\ \xf1\x75\x41\xbf\x1d\xbc\x7e\xf1\x1f\x62\x9b\x4c\x39\ +\x00\x00\x07\x50\ +\x00\ +\x00\x36\x1d\x78\x9c\xed\x5a\x5b\x6f\xe3\x36\x16\x7e\xcf\xaf\xd0\ +\x6a\x5e\x1a\xac\x45\xf3\xa2\x7b\xec\x14\xc5\x0e\x5a\x14\x28\xb0\ +\x40\x67\x06\x7d\x1c\xd0\x12\x6d\xab\x91\x25\x83\x92\x63\x3b\xbf\ +\xbe\x87\xb2\x2e\x74\x2c\x27\x99\x4c\x46\xdd\x9d\xda\xc1\x8c\xc5\ +\x73\x21\x79\x0e\xbf\xef\x48\xa2\x39\xf9\x71\xb7\x4a\x8d\x7b\x21\ +\x8b\x24\xcf\xa6\x26\x41\xd8\x34\x44\x16\xe5\x71\x92\x2d\xa6\xe6\ +\xa7\x8f\x3f\x5b\xbe\x69\x14\x25\xcf\x62\x9e\xe6\x99\x98\x9a\x59\ +\x6e\xfe\x78\x7b\x35\xf9\x97\x65\x19\xff\x91\x82\x97\x22\x36\xb6\ +\x49\xb9\x34\x7e\xcd\xee\x8a\x88\xaf\x85\xf1\xc3\xb2\x2c\xd7\xe1\ +\x78\xbc\xdd\x6e\x51\x52\x0b\x51\x2e\x17\xe3\x6b\xc3\xb2\x6e\xaf\ +\xae\x26\xc5\xfd\xe2\xca\x30\x0c\x18\x37\x2b\xc2\x38\x9a\x9a\xb5\ +\xc3\x7a\x23\xd3\xca\x30\x8e\xc6\x22\x15\x2b\x91\x95\xc5\x98\x20\ +\x32\x36\x3b\xf3\xa8\x33\x8f\xd4\xe8\xc9\xbd\x88\xf2\xd5\x2a\xcf\ +\x8a\xca\x33\x2b\xde\x69\xc6\x32\x9e\xb7\xd6\x6a\x36\x5b\x56\x19\ +\x91\x20\x08\xc6\x98\x8e\x29\xb5\xc0\xc2\x2a\xf6\x59\xc9\x77\xd6\ +\xb1\x2b\xcc\xb1\xcf\x95\x62\x8c\xc7\xa0\xeb\x2c\x5f\x66\x15\xee\ +\x52\x48\xc5\xd9\xc9\x54\x5a\x7d\x74\x48\xff\x1a\xfe\xb5\x0e\x8d\ +\x00\x15\xf9\x46\x46\x62\x0e\x9e\x02\x65\xa2\x1c\xbf\xff\xf8\xbe\ +\x55\x5a\x18\xc5\x65\xac\x75\xd3\x64\xff\x68\xdc\xa3\x25\xc9\xf8\ +\x4a\x14\x6b\x1e\x89\x62\xdc\xc8\x2b\xff\x6d\x12\x97\xcb\xa9\xe9\ +\xda\xeb\x5d\xd5\x5e\x8a\x64\xb1\x2c\x35\x41\x12\x4f\x4d\x88\x90\ +\x7a\xd4\xad\xda\xcd\x1c\xc2\x16\x49\x18\x31\x7a\x30\xad\x3b\xd6\ +\x55\xb6\x8f\x88\x21\x03\xcf\xc5\xc7\xde\x71\x1e\xa9\x29\x4d\xcd\ +\x0f\x19\x5f\x7f\xfe\x29\x5b\xa4\x02\x35\x89\x6c\xfb\xc9\x37\xe5\ +\x7a\x53\x7e\x16\xbb\x52\x64\x87\x0e\x21\x14\x2d\xae\x4a\xad\xdc\ +\xd0\x51\x4c\x1a\xc6\x89\x79\x0b\x92\x49\x2c\xe6\x85\xd2\x1c\xc2\ +\x51\x2d\x88\xc7\xaf\x74\xa0\x85\x35\x11\x5c\xfe\x22\x79\x9c\x00\ +\x12\x0f\x76\xda\x2c\xa2\x3c\x4d\x45\x04\x39\xe1\xe9\x96\xef\x0b\ +\xb3\x35\x80\xae\x8e\x5d\x19\xb1\xed\xba\x53\xe8\xb6\x28\xf3\x75\ +\x63\x0b\x91\x97\xfb\x14\xc2\x55\x42\x0b\x7a\xcc\x65\xf8\x6e\x5e\ +\x7d\x6e\x2a\x51\x0e\x6b\x93\x94\xfb\x90\xdc\x98\x9d\x4f\x3e\x9f\ +\x17\x02\x06\xc6\x9a\xac\x5a\x0f\xf0\x80\xb1\x5c\xd3\x18\x7f\xdd\ +\x68\xb8\x6f\x34\xd2\x3f\x9a\xdf\x8e\x36\x19\x1f\x87\x5d\x4b\xdb\ +\x84\xad\x21\xff\x6b\xc8\x18\x50\xb6\xe9\xa9\x5d\xf7\x72\xaf\x50\ +\x7a\x6c\xca\x62\xf3\x24\xe9\xf7\xeb\xcf\x3b\x08\xdc\x08\x0d\x46\ +\xe1\x3f\xd2\x6b\xb1\x3f\x58\x10\x60\x21\x7c\xe1\x5e\x9b\x07\x85\ +\xe5\x27\xba\xa9\x67\x60\xe5\x32\x59\x24\x80\x99\xca\x8e\x12\xc4\ +\xaa\xcf\xb1\x0f\x24\x43\x8b\x8d\x7a\xcc\xee\x72\xa2\x72\xc1\xd3\ +\x2f\x06\x51\x55\x10\xc2\xa5\x14\x50\xc0\xde\xf5\xa0\x49\x1f\xfb\ +\x78\x08\xe6\x3b\x5d\xc4\x8b\x5a\xf8\x29\x4b\x4a\xa8\x54\x9b\x42\ +\xc8\x0f\x8a\xed\xff\xcd\x3e\x15\xe2\xc4\xea\xa3\xe4\x59\x01\xa5\ +\x65\x35\x35\x57\xbc\x94\xc9\xee\x07\x32\xc2\xea\x0f\xb9\x81\xef\ +\xd0\xc0\x86\x6b\x8a\x29\xf2\xa9\xef\xb2\xeb\xd6\x3d\x82\x15\xa1\ +\xd4\x41\xd4\xb5\x31\xed\xa4\xb0\x0a\xae\x47\x91\x17\x78\xcc\x6d\ +\xa5\xf3\x5e\xdb\x79\xaf\xad\x84\xac\xdb\x88\xd9\x0e\xf1\xfd\x6f\ +\x9d\x50\xcb\x7b\x26\xa5\x16\xfd\x9e\x93\xfa\xa6\xa5\x0e\x72\x39\ +\x60\xb1\xb3\xec\x61\xcb\x9d\x36\xde\x99\x82\xf7\x8d\x10\xea\x3c\ +\x87\x50\xef\x82\xd0\x97\x22\xd4\x19\x14\xa1\x03\xdf\x90\x21\xba\ +\x57\x21\xf4\x28\xf1\x4f\xaf\x51\xff\x7a\xf6\xaf\x7d\x3f\x4e\xbe\ +\x12\x7c\x2f\x43\xf8\x29\x51\x6c\x07\x93\xd7\x30\xee\x1c\xce\xbe\ +\xf5\x6d\x89\x3d\x4b\xfa\xef\xfa\x66\xff\xb6\xac\x67\x83\xb2\x9e\ +\x0e\xcc\x7a\x76\x61\x7d\x97\x95\x53\xd6\x5b\xfe\x6b\x48\xf7\x77\ +\xf1\x9e\x3c\xc7\x7b\xe7\x42\xfb\x97\xd2\x9e\x0c\x4a\x7b\x67\x60\ +\xda\x93\x0b\xed\xbb\xac\xf4\xd0\xfe\xe5\xb7\xfb\x9e\x5d\x80\xa1\ +\x69\x1f\x3c\x47\x7b\x76\xa1\xfd\x4b\x69\x1f\x0c\x4a\xfb\x60\x68\ +\xda\xd3\x0b\xef\xbb\xb4\x3c\xe6\xbd\xcf\x5e\x43\xb9\x57\xb2\xfe\ +\x9f\x91\x52\x55\x4a\x2d\xf7\xe5\xc5\xf4\x8b\x9e\xa2\xde\xf8\x86\ +\x3f\xf0\x93\xbe\x33\xf8\x1e\x14\xb1\x2e\xf4\x7f\x1a\xab\xbe\x85\ +\x5f\x8c\x55\xf6\x45\x6f\xfa\x6f\xfc\x4e\x3a\xf0\x5e\x14\x1d\xfc\ +\x4e\xc5\x5e\xbb\x63\xfa\x8f\xc1\xaa\xfd\x62\xa4\x3a\x5f\x74\xbb\ +\x7a\xe3\x3d\xd3\x81\x9f\xa8\x5c\xed\xd5\x66\xa0\x7d\x53\x8d\x1b\ +\xc3\xee\xed\xb3\xe7\x7e\xd1\xd3\xd6\xfd\xf2\xe0\xff\x5c\x49\x1d\ +\xf4\xc7\xf6\xc1\x51\xfa\xf4\x9d\x7f\x32\x56\xc7\x18\xaa\xab\xf6\ +\xc7\x75\x75\xa2\x22\xbe\x4f\xc4\xf6\xaa\xed\x6d\xc6\x5b\xac\xac\ +\xf9\x42\x54\x93\x03\x68\x1e\x66\x57\x2b\x66\xb9\x8c\x85\x6c\x54\ +\x6e\xf5\x39\x52\xd5\xf3\x3f\x1c\x1a\xba\x3a\x5e\x33\xd5\x6b\xab\ +\xc7\xfd\xfa\x62\xc9\xe3\x7c\x0b\xe0\x79\xac\x7c\xc8\x73\xc0\x2b\ +\x43\xbe\x1f\x60\xdf\x63\x8f\xd5\x15\x38\x5d\xe4\x61\x1a\x90\x13\ +\x5f\x85\x51\x86\x01\x8c\x6e\xe0\x9d\xe8\x36\x52\x42\x9e\xac\x94\ +\xef\x05\xc4\xb4\xb0\xa9\xdf\xf0\xaa\x58\xe6\xdb\x85\x54\xa9\x29\ +\xe5\x46\x3c\x76\x8c\xf3\x68\xa3\x8e\x23\x59\x9b\x03\xe9\xea\x43\ +\x30\x9a\x85\xf2\xb5\x66\xb3\x7c\xd7\xdf\xc1\x36\xc9\x20\x54\xab\ +\x3e\x56\x43\xa8\x7f\x92\x90\xda\xa2\x39\x68\xe3\x39\xce\x19\x8b\ +\x5d\x87\xc5\xc7\xaa\xbd\x22\xe2\x19\xdd\x8a\xef\x92\x55\xf2\x20\ +\x62\x05\xad\x03\x82\x26\x2b\x51\xf2\x98\x97\xbc\xc3\x45\x23\xa1\ +\x1e\x6b\xb6\xcd\x26\x32\x9e\x87\xbf\xbf\xff\xb9\xc5\x78\x14\x85\ +\x7f\xe4\xf2\xae\x83\xa7\x32\xe0\xb3\x7c\x03\xd3\x6e\x99\xa7\x4e\ +\xd7\x44\xa1\x2a\x3c\xbc\xbc\x4d\x56\xb0\xda\xea\x40\xd4\xbf\x77\ +\xab\x14\x10\xda\x2a\x8e\x8c\xd5\x19\x90\xae\xd3\x43\xb7\x52\x1c\ +\x0e\x3c\xf5\x9e\x11\x8b\xa3\x55\xa2\x9c\xc6\x1f\xca\x24\x4d\x7f\ +\x55\x83\x68\x5c\xac\x3b\x4d\xca\x54\x68\x04\x1d\xd7\xb3\x6f\x18\ +\xa4\x05\x37\x19\x37\xd1\x57\xad\x45\x97\x95\x0a\x2f\xe4\x71\x62\ +\x53\x3e\x13\xe9\xd4\xfc\x4d\x29\x8d\x13\xed\x42\xe6\x9b\xf5\x2a\ +\x8f\x45\xed\xde\x64\x73\xa1\x57\x2f\x1d\x81\x86\x51\x9e\xd4\x6a\ +\x8c\x88\x4b\x01\x2d\xb4\xae\xd9\x4d\xcb\x45\xcc\xc5\x4e\xe0\xbb\ +\x23\xcb\x75\x11\xc1\xbe\x8f\xdd\xeb\xae\xea\xad\x79\xb9\xd4\xaa\ +\xd0\xf1\x21\x1b\x2e\x23\xad\xb4\xd4\x25\xaa\x2b\x7d\x75\x9d\xc2\ +\xd5\xe7\x66\x0e\x89\x0d\xb3\x3c\x13\xd5\x95\x56\x21\xab\xa6\xdc\ +\xa4\x42\x69\x1f\xa0\x16\x40\x49\x93\xf9\x9d\x50\x9e\x54\x50\x51\ +\x37\x0f\x88\x0f\x9d\xa6\xa9\x0a\x16\xa4\x27\x9c\x6d\xca\x52\x97\ +\xfd\x99\x27\x59\x08\x19\xcb\xe2\x46\x0a\x4b\x2b\x64\x0a\x90\x2d\ +\x43\xbb\x91\x75\xc3\xd7\x82\x98\x43\x0d\x91\x92\xef\x0f\x73\xd4\ +\xa4\x87\x32\x0a\xa5\x75\xc5\xe5\x9d\x90\x07\xfd\x7d\x52\x24\xb3\ +\x24\x55\x5d\x54\x97\xa9\xb8\x89\x93\x62\x0d\xeb\x13\x26\x99\x9a\ +\xc6\x4d\x7e\x2f\xe4\x3c\xcd\xb7\xad\x5e\x64\x1c\xbe\xac\x19\x8f\ +\xee\x16\xd5\xfc\x42\x1e\x41\x2d\xd8\xa4\xbc\x14\x8f\x2a\xb4\xca\ +\xba\xcd\x08\x33\x7b\x52\xaf\x4a\x16\x23\x50\xd0\x6c\x28\x68\xbd\ +\x06\xfb\x83\x81\xe3\x7b\x3e\xed\x33\x90\xd0\x03\x09\x10\xa6\x9e\ +\x8b\x49\xaf\xc1\xbe\xdf\x40\xb1\xda\x70\x30\x0a\x08\x71\x7d\x7f\ +\xd4\x0e\x62\x70\xa3\x35\x1f\xb5\x57\x06\x36\x08\xfc\x59\xcc\x47\ +\xd8\x71\x28\x66\x23\xfc\x84\x99\x6e\xf5\xa0\x8d\x79\x8a\x64\x40\ +\xa9\xeb\x05\x8e\x6f\x57\x48\xee\x5a\x16\x0b\x10\x65\x04\xea\xfc\ +\xc8\xc6\x1e\xf2\x1c\x97\x79\xd7\xfa\x1d\xf5\x18\xcb\x55\x30\xd4\ +\x76\x90\x47\x80\x3a\x23\xd7\x81\xc7\x0e\x12\x30\x88\xc5\xf6\x91\ +\x03\x42\x36\x6a\x2e\x9a\x48\x02\x0f\x29\x5b\x17\xa6\x78\xce\x46\ +\x33\x79\x38\x97\xda\xc6\xe5\xdc\xda\x3c\xa5\xaf\x9e\x9b\xea\xa9\ +\x9e\x43\x07\xa9\x27\xe1\xf4\xa0\x8a\x01\xef\xb5\xbd\x97\x96\xb5\ +\x3d\x5c\x85\xc6\x0c\x22\xf9\x3a\xba\x52\x06\xeb\x03\x48\x66\x2e\ +\xfd\xde\x89\xfb\x64\x71\x3c\x85\xb1\x05\x8f\x3a\xc4\xa1\x3e\x01\ +\xac\x20\x8a\x6d\x87\xda\x9e\x33\xb2\xd4\x35\x61\x98\xe1\x60\xa4\ +\x2c\x18\x71\x18\xa6\x23\xe6\xda\x28\x70\x1c\x07\x78\x43\x81\x29\ +\x2e\x75\xec\x0b\xb4\x7b\xa1\x6d\xd1\x0b\xb8\xff\xe7\xc1\x4d\x74\ +\x6c\xbb\x84\x20\xd7\x63\x01\xbd\x60\xfb\x39\x6c\x7b\x17\x6c\xff\ +\xfd\xd8\xd6\x00\xdd\xa1\x5c\xc3\x73\x07\x72\x2f\x80\x27\x24\x12\ +\xd8\xee\x88\x05\x36\x62\x1e\x73\xd8\x05\xd9\xfd\xc8\xa6\x16\xbb\ +\x60\xfb\xff\x13\xdb\xc4\xf6\x10\x20\x00\x07\xd7\xda\x76\xd2\xe2\ +\xf0\x1a\x0c\x5f\x13\xf5\xb6\x7e\x7b\xf5\x17\x93\x56\xec\x3d\ \x00\x00\x0f\xd2\ \x00\ \x00\x52\x9a\x78\x9c\xe5\x5c\x5b\x6f\xe3\xb8\x15\x7e\x9f\x5f\xa1\ @@ -30164,6 +34420,112 @@ qt_resource_data = "\ \x74\x68\x69\x63\x20\x42\x6f\x6c\x64\x2c\x20\x42\x6f\x6c\x64\x27\ \x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\ \x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ +\x00\x00\x06\x71\ +\x00\ +\x00\x28\x71\x78\x9c\xed\x59\x5b\x6f\xdb\x36\x14\x7e\xcf\xaf\xd0\ +\xd4\x97\x06\xb3\x28\x91\xba\x2b\x76\xf6\xb0\xae\x43\x81\x01\x03\ +\xd6\x16\x7b\x2c\x68\x89\xb6\xb5\xc8\xa2\x40\xd1\xb1\x9d\x5f\xbf\ +\x43\xdd\x1d\x2b\x97\xa5\xad\xbb\x75\x76\x90\x58\x3c\x17\xf2\x5c\ +\xbe\x73\x8e\x63\x4e\x7f\xda\xad\x33\xed\x96\x89\x32\xe5\xf9\x4c\ +\xc7\xc8\xd2\x35\x96\xc7\x3c\x49\xf3\xe5\x4c\xff\xf8\xe1\xad\x11\ +\xe8\x5a\x29\x69\x9e\xd0\x8c\xe7\x6c\xa6\xe7\x5c\xff\xe9\xfa\x62\ +\xfa\x83\x61\x68\x3f\x0b\x46\x25\x4b\xb4\x6d\x2a\x57\xda\xbb\xfc\ +\xa6\x8c\x69\xc1\xb4\xd7\x2b\x29\x8b\xc8\x34\xb7\xdb\x2d\x4a\x1b\ +\x22\xe2\x62\x69\x5e\x6a\x86\x71\x7d\x71\x31\x2d\x6f\x97\x17\x9a\ +\xa6\xc1\xb9\x79\x19\x25\xf1\x4c\x6f\x14\x8a\x8d\xc8\x2a\xc1\x24\ +\x36\x59\xc6\xd6\x2c\x97\xa5\x89\x11\x36\xf5\x5e\x3c\xee\xc5\x63\ +\x75\x7a\x7a\xcb\x62\xbe\x5e\xf3\xbc\xac\x34\xf3\xf2\xd5\x40\x58\ +\x24\x8b\x4e\x5a\x59\xb3\xb5\x2b\x21\x1c\x86\xa1\x69\x11\x93\x10\ +\x03\x24\x8c\x72\x9f\x4b\xba\x33\x0e\x55\xc1\xc6\x31\x55\x62\x59\ +\x96\x09\xbc\x5e\xf2\x79\x52\xd1\x2e\x83\x50\x3c\x68\x4c\xc5\x1d\ +\x9e\x0e\xe1\x2f\xe0\xb7\x53\x68\x09\xa8\xe4\x1b\x11\xb3\x05\x68\ +\x32\x94\x33\x69\xbe\xf9\xf0\xa6\x63\x1a\x16\x4a\x64\x32\xd8\xa6\ +\x8d\xfe\xc1\xb9\x07\x29\xc9\xe9\x9a\x95\x05\x8d\x59\x69\xb6\xf4\ +\x4a\x7f\x9b\x26\x72\x35\xd3\x3d\xa7\xd8\x55\xeb\x15\x4b\x97\x2b\ +\x39\x20\xa4\xc9\x4c\x07\x0f\x89\x4f\xbc\x6a\xdd\xda\x10\x75\x48\ +\xb2\x90\x4d\x6a\xd1\x66\xe3\x21\xcb\x09\x10\xd6\x44\xe8\x7b\xd6\ +\xa1\x76\xc2\x63\x65\xd2\x4c\x7f\x9f\xd3\xe2\xd3\x2f\x3b\xc9\x72\ +\xa5\x82\xda\x60\x76\x7b\xf1\x8d\x2c\x36\xf2\x13\x6b\x25\x66\x3a\ +\xb8\x33\xf0\xad\x62\x2b\x35\x74\xe0\xd7\x00\xe7\x58\xbf\x06\xca\ +\x34\x61\x8b\x52\x71\x6a\x97\xd4\x0a\x7c\x0a\x2a\x1e\x70\x21\x2f\ +\x8c\x8a\x5f\x05\x4d\x52\x40\x63\x2d\x37\xb0\x22\xe6\x59\xc6\x62\ +\x88\x0b\xcd\xb6\x74\x5f\xea\x9d\x00\x6c\x75\xa8\x6a\x63\xc7\x69\ +\x36\x85\x6d\x4b\xc9\x8b\x56\x16\xbc\x97\xfb\x0c\x5c\x56\x44\x03\ +\x76\xe4\x22\x7a\xb5\xa8\x5e\x57\x15\x89\x43\x7e\x52\xb9\x8f\xf0\ +\x95\xde\xeb\xf0\xc5\xa2\x64\x70\xb0\x35\xa0\x55\x39\x01\x0d\x38\ +\xcb\xd3\x35\xf3\xf3\x4e\xb3\xc6\x4e\xc3\xe3\xa7\x05\xdd\x69\x53\ +\xf3\xd0\xed\x86\xda\x05\xac\x80\xf8\x17\x10\x31\x28\xdb\x76\xa7\ +\x2e\xf7\x72\xaf\x90\x7a\x28\x6a\x27\xfa\x51\xd0\x6f\x8b\x4f\x3b\ +\x70\x5c\x8b\x34\x9b\xc0\x1f\x3c\x2a\xb1\xaf\x25\x30\x54\x22\xbc\ +\x59\xa3\x32\x77\x0a\xcf\x8f\x6c\xd3\x58\x60\x70\x91\x2e\x53\xc0\ +\x4c\x25\x47\x30\xb2\xab\xd7\xa1\x0e\x04\x63\xe0\x1b\xf1\x6d\xa7\ +\x8f\x89\x8a\x05\xcd\xfe\x31\x88\xaa\xa6\x10\xad\x04\x83\x26\xf6\ +\x6a\x04\x4d\xc3\xb3\x0f\x8f\xb0\x03\xb7\xf7\x78\xd9\x10\x3f\xe6\ +\xa9\x84\x6e\xb5\x29\x99\x78\xaf\x2a\xfe\xf7\xfc\x63\xc9\x8e\xa4\ +\x3e\x08\x9a\x97\xd0\x5e\xd6\x33\x7d\x4d\xa5\x48\x77\xaf\xf1\xc4\ +\x52\x3f\xc8\x0b\x03\x97\x84\x0e\x3c\x13\x8b\xa0\x80\x04\x9e\x7d\ +\xd9\xa9\xc7\x90\x11\x42\x5c\x44\x3c\xc7\x22\x3d\x15\xb2\xe0\xf9\ +\x04\xf9\xa1\x6f\x7b\x1d\x75\x31\x2a\xbb\x18\x95\x15\x10\x75\x07\ +\xd9\x8e\x8b\x83\xe0\x6b\x07\xd4\xf0\x9f\x08\xa9\x41\xbe\xe7\xa0\ +\x7e\xd1\x56\x07\xb1\x3c\x61\xb3\x33\x9c\xd3\xb6\xbb\xc1\x79\x0f\ +\x34\xbc\xaf\x84\x50\xf7\x29\x84\xfa\x67\x84\x3e\x17\xa1\xee\x49\ +\x11\x7a\xe2\x81\x0c\xde\xbd\x08\xa1\x07\x81\x7f\x3c\x47\xe3\xf9\ +\x1c\xcf\xfd\x38\x4e\x3e\x13\x7c\xcf\x43\xf8\x71\xa1\x38\xae\x85\ +\x5f\x52\x71\x0f\xe1\xec\x6b\x8f\x25\xfb\xc9\xa2\xff\xae\x87\xfd\ +\x97\xad\x7a\xfb\xa4\x55\x4f\x4e\x5c\xf5\xf6\xb9\xea\xfb\xa8\x1c\ +\x57\xbd\x11\xbc\xa4\xe8\xbe\x55\xdd\xe3\xa7\xea\xde\x3d\x97\xfd\ +\x73\xcb\x1e\x9f\xb4\xec\xdd\x13\x97\x3d\x3e\x97\x7d\x1f\x95\x91\ +\xb2\x7f\xfe\xb8\x1f\xf9\x16\xe0\xd4\x65\x1f\x3e\x55\xf6\xf6\xb9\ +\xec\x9f\x5b\xf6\xe1\x49\xcb\x3e\x3c\x75\xd9\x93\x6f\xf4\x6f\x28\ +\x79\x0a\xa2\xde\x19\xa2\xcf\x85\x28\x39\x29\x44\xad\x13\x43\xf4\ +\x85\x08\xfd\x5f\x4c\xa6\x00\xbb\x2f\xa9\xb8\xc7\xe7\xd2\xd4\x54\ +\x57\x18\xd5\x53\xf7\xc5\xba\xba\x51\x49\x6e\x53\xb6\xbd\xe8\x4c\ +\x99\xd3\xce\xb6\x82\x2e\x59\x95\x6f\x38\xb9\x4e\x78\xc3\x98\x73\ +\x91\x30\xd1\xb2\xbc\xea\x75\xc0\x6a\x20\x51\x5f\x1a\x5e\x1c\x5a\ +\xa7\x76\xed\xf8\xd6\x38\xbf\x5c\xd1\x84\x6f\x21\x25\xf7\x99\x77\ +\x9c\x43\x12\x5c\xe4\xde\x67\x54\x09\x0c\x90\x6b\x11\xdb\x0d\x8f\ +\x98\x70\x12\xf1\x91\x4d\x1c\x72\xb4\x63\xbc\x11\x02\x62\x69\x64\ +\x74\xcf\xc0\x9b\xa5\x43\x82\x56\xbf\x5c\xf1\xed\x52\xa8\xa0\x48\ +\xb1\x61\xf7\x15\x13\x1e\x6f\xd4\x45\xa4\xb1\xa9\xd3\xdb\x5c\x7f\ +\x0d\x24\x94\xae\x31\x9f\xf3\xdd\xf8\x06\xdb\x34\x07\x27\x8d\xe6\ +\x42\x0d\x93\xe0\x28\x14\x8d\x44\x7b\xc5\xe6\xbb\x47\x6e\x37\x12\ +\xbb\xbe\xb0\xef\xb3\x94\xeb\x47\x4e\x37\xbc\x35\xdd\xa5\xeb\xf4\ +\x8e\x25\xaa\x4e\x1b\x94\xac\x99\xa4\x09\x95\xb4\x47\x44\x4b\x21\ +\xbe\xdd\x7e\x58\x9e\x8a\x64\x11\xfd\xf1\xe6\x6d\xd7\x30\xe2\x38\ +\xfa\x93\x8b\x9b\xbe\xd6\x95\x00\x9d\xf3\x0d\x98\xdd\xb5\x31\x75\ +\xa7\x16\x47\xaa\x8e\xa8\xbc\x4e\xd7\x90\x67\x75\x15\xfa\xe3\x6e\ +\x9d\x01\x36\x3b\xc6\x81\xb0\xba\xf9\xe9\x37\xad\xb7\x15\xac\xbe\ +\xea\x1c\xbd\x1d\x4e\xe2\x75\xaa\x94\xcc\xf7\x32\xcd\xb2\x77\xea\ +\x90\x41\x63\x6b\x36\x4d\x65\xc6\x06\xdd\xce\x6c\xac\x6f\xdb\xd1\ +\xc0\xb9\xa9\xd9\x7a\x5f\xad\x96\x7d\x54\x2a\xbc\xe0\xfb\x81\xcd\ +\xe8\x9c\x65\x33\xfd\x37\xc5\xd4\x8e\xb8\x4b\xc1\x37\xc5\x9a\x27\ +\xac\x51\x6f\xa3\xb9\x1c\xf6\x82\x21\x02\x35\x4d\x1e\xb5\x1e\x0b\ +\x61\x8f\x00\x5a\x48\xd3\x82\xda\x95\x87\x6c\xcf\x72\xc3\xc0\x9b\ +\x18\x9e\x87\xb0\x15\x04\x96\x77\xd9\x8f\x90\x82\xca\x55\x1f\x49\ +\x95\x56\x8d\x38\x2e\xf2\x31\x1c\x37\xf1\x5c\x68\x7d\x38\xb4\x35\ +\xaa\x39\x50\x44\x40\xb4\x27\xed\x83\x66\x69\x18\x7e\x8c\xd0\x47\ +\x4a\xd6\x9b\x58\x0f\xca\x0c\x44\xee\x06\x7d\xbf\x6b\x37\x02\xc0\ +\xd8\xaa\x8c\xf2\x77\x8f\xf3\xab\xde\xdd\x98\x3a\xca\x07\x7d\xdc\ +\x18\xe1\x0e\x04\xaa\x3b\x38\xf0\xdf\x86\x58\x0d\xf5\xea\xb9\xd6\ +\x8c\x34\xab\x7a\x5d\x2d\x00\x36\x6a\x31\x07\x3f\xaa\xc5\x60\x9e\ +\x56\x4b\xb1\xc9\x58\x94\xf3\xfc\x0e\xda\x1c\x0c\x40\xc1\x6f\x98\ +\x92\x27\x8c\xb0\x66\x59\x97\x74\x44\x6c\x04\x43\x2a\x24\x9e\xdf\ +\xd2\x55\xfb\x06\x20\x44\xf3\x8d\x94\x43\xda\x5f\x3c\xcd\x23\xc0\ +\x46\x9e\xb4\x54\x00\x31\x13\x19\x14\xa7\x8c\x9c\x96\xd6\xdb\xd1\ +\x10\x12\x0a\x7d\x52\x08\xba\x57\xe6\xb0\x21\xb5\x9e\xbe\x30\x91\ +\xd7\x54\xdc\x30\x51\xf3\x6f\xd3\x32\x9d\xa7\x99\xda\xa2\x7a\xcc\ +\xd8\x55\x92\x96\x05\x20\x31\x4a\x73\x65\xc6\x15\xbf\x65\x62\x91\ +\xf1\x6d\xc7\x67\x39\x85\x37\x63\x4e\xe3\x9b\x65\x65\x5f\x44\x63\ +\xe8\x7a\x9b\x8c\x4a\x36\x96\x80\xfa\xa2\x96\x8a\x78\xc0\x3c\x46\ +\xb0\x61\x21\x1f\xe2\x42\x7c\xec\x4f\xe0\xd9\xf1\x89\xe5\xc0\x30\ +\x9e\xa8\xcb\x7f\x3b\xf0\x42\xe2\x2a\x32\x0c\xe8\xd0\x0f\x5c\x3c\ +\xc1\x36\x86\x81\x1f\xd8\x13\x4c\x88\x9a\xdb\xa1\x7f\x39\xfc\xac\ +\x72\x06\x76\x0d\x6c\xc3\x3e\x43\xfb\x5f\x04\x6d\x77\x00\x6d\xb7\ +\x87\xb6\x3f\x80\xf6\xc4\x20\xc8\xc3\x24\xc4\x5e\xa8\xb0\x6d\xa3\ +\x90\x60\x7c\xc6\xf6\x28\xb6\x07\x5f\xd0\x9e\xd1\xfd\x1f\x41\x37\ +\xb6\x6d\x44\x2c\x58\x29\x74\xfb\x08\xd2\xeb\x5c\x0e\xfe\xeb\x5b\ +\xd6\x1f\xb0\xe0\x6d\xaa\x3e\x07\x5e\x5f\xfc\x0d\x09\xf6\x2a\xdc\ +\ \x00\x00\x09\xcf\ \x00\ \x00\x35\xea\x78\x9c\xed\x5a\x5b\x6f\xdb\xca\x11\x7e\xf7\xaf\x60\ @@ -30992,6 +35354,424 @@ qt_resource_data = "\ \x33\x31\x30\x30\x32\x29\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ \x2f\x67\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\ \x3e\x0a\ +\x00\x00\x0a\xac\ +\x00\ +\x00\x25\xf5\x78\x9c\xed\x59\x5b\x6f\xdb\xd8\x11\x7e\xf7\xaf\x60\ +\x95\x97\x04\x15\xa9\x73\xbf\xc8\x96\xf7\x61\x83\x2d\x16\x68\x51\ +\xa0\x9b\xa0\x8f\x05\x4d\xd1\x36\x1b\x49\x14\x48\xca\x97\xfc\xfa\ +\x7e\xc3\xbb\x2c\xda\x71\xb6\xdb\xdd\x4d\xb1\x56\x8c\x88\x73\xe6\ +\x9c\x33\x67\xe6\x9b\x6f\xe6\xd0\x17\xdf\x3d\x6c\x37\xc1\x5d\x5a\ +\x94\x59\xbe\x5b\xcd\x78\xc4\x66\x41\xba\x4b\xf2\x75\xb6\xbb\x59\ +\xcd\x3e\x7e\xf8\x21\x74\xb3\xa0\xac\xe2\xdd\x3a\xde\xe4\xbb\x74\ +\x35\xdb\xe5\xb3\xef\x2e\xcf\x2e\xfe\x14\x86\xc1\xf7\x45\x1a\x57\ +\xe9\x3a\xb8\xcf\xaa\xdb\xe0\xc7\xdd\xa7\x32\x89\xf7\x69\xf0\xf6\ +\xb6\xaa\xf6\xcb\xc5\xe2\xfe\xfe\x3e\xca\x5a\x61\x94\x17\x37\x8b\ +\x77\x41\x18\x5e\x9e\x9d\x5d\x94\x77\x37\x67\x41\x10\x60\xdf\x5d\ +\xb9\x5c\x27\xab\x59\x3b\x61\x7f\x28\x36\xb5\xe2\x3a\x59\xa4\x9b\ +\x74\x9b\xee\xaa\x72\xc1\x23\xbe\x98\x0d\xea\xc9\xa0\x9e\xd0\xee\ +\xd9\x5d\x9a\xe4\xdb\x6d\xbe\x2b\xeb\x99\xbb\xf2\xcd\x48\xb9\x58\ +\x5f\xf7\xda\x64\xcd\xbd\xac\x95\xb8\xf7\x7e\xc1\xc4\x42\x88\x10\ +\x1a\x61\xf9\xb8\xab\xe2\x87\xf0\x78\x2a\x6c\x9c\x9a\x2a\x18\x63\ +\x0b\x8c\x0d\x9a\xaf\xd3\x5a\x3e\x6c\xe0\x8a\x67\x8d\xa9\x47\xc7\ +\xbb\xc3\xfd\x7b\xfc\xf6\x13\x3a\x41\x54\xe6\x87\x22\x49\xaf\x31\ +\x33\x8d\x76\x69\xb5\x78\xff\xe1\x7d\x3f\x18\xb2\x68\x5d\xad\x47\ +\xcb\x74\xde\x3f\xda\xf7\x28\x24\xbb\x78\x9b\x96\xfb\x38\x49\xcb\ +\x45\x27\xaf\xe7\xdf\x67\xeb\xea\x76\x35\x33\x6a\xff\x50\x3f\xdf\ +\xa6\xd9\xcd\x6d\x35\x12\x64\xeb\xd5\x0c\x27\x14\xde\xe9\xfa\x79\ +\x04\x20\xde\x28\xb4\xcb\x2d\xfb\x11\x16\x29\x17\xc9\x88\x07\x85\ +\x77\xce\xd4\x4a\x9d\xe5\xcb\x75\x9e\x90\x29\xab\xd9\xfb\x22\xbe\ +\xae\xfe\xf5\x3d\x41\x2d\x22\x0f\x5e\x42\xed\x62\x9d\x5e\x97\xa4\ +\xde\x6c\x4b\x4f\xd8\xd7\xd6\x63\x18\x85\xef\xd2\xb8\xf8\x4b\x11\ +\xaf\x33\x20\xa6\xd1\x6b\x34\x8f\x47\xa4\x33\xac\x9d\x83\x59\x65\ +\x95\xef\x3b\x5d\x18\x52\x3d\x6e\xb0\x3b\x09\xc3\x24\xdf\xe4\xc5\ +\xf2\x0d\x4f\xad\x49\xe5\x79\x2d\xca\xe1\xa2\xac\x7a\x5c\xf2\xf3\ +\xd9\x30\x27\xbf\xbe\x2e\x53\xf8\x84\x8d\x64\xb5\x5b\x30\x03\x7b\ +\x89\x59\xb0\x78\xfd\x6e\xd7\xf5\xcf\x2b\x76\xe3\xd3\xbb\xa9\x7e\ +\xb7\x8b\xc5\xf1\xb1\x5f\xf6\x52\x17\x25\x98\xb1\x49\x13\xac\x1f\ +\x6f\xee\xe3\xc7\xb2\xdf\xa4\x46\xe6\xf2\xb6\x48\x91\x49\x6f\x26\ +\xfc\xf9\xa2\xbb\xcd\xb0\x0c\x5f\xcd\x24\xa0\x21\xb4\xf4\xba\x97\ +\x3e\x42\x6a\x78\xa4\x38\xb3\x46\x0e\xba\x02\xba\x2c\xe2\x5c\x1a\ +\x39\xac\xf0\x08\x29\x17\x11\x37\xd0\x1d\x7c\x70\xd3\x6e\xf6\x71\ +\x97\x55\x48\xc5\x43\x99\x16\x3f\x11\x9c\xff\xbe\xfb\x58\xa6\x27\ +\x5a\x1f\x8a\x78\x57\x22\x77\xb6\xab\xd9\x36\xae\x8a\xec\xe1\x2d\ +\x9f\x33\xfa\x44\xde\x38\xe7\x85\xf5\xf3\x90\x47\x7a\x0e\x12\x54\ +\x5a\x28\xe3\xdf\x0d\x5e\xfd\xdf\xf8\x2f\x34\x5f\xf0\x60\xa8\x7f\ +\x63\x1f\x7e\xc9\x01\x93\x69\x86\x63\xbd\x1e\xfa\x3a\xf6\xd7\xd7\ +\xfa\xbf\x48\xb4\x50\xfd\xba\xa9\x16\xbe\x9c\x6c\x17\x0b\x62\xa8\ +\xfa\x5b\xcf\x6f\x44\x6e\xeb\xbb\x2c\xbd\x1f\x68\xec\x2a\xee\x11\ +\xba\x8f\x6f\xd2\xda\x38\x60\xa4\xb1\xae\x1d\xb8\xca\x8b\x75\x5a\ +\x74\x43\xa6\xfe\x39\x1a\x6a\xed\x6f\xea\xf6\xd9\x31\x24\x69\xd5\ +\x7e\x9c\x4d\x8f\x97\xb7\xf1\x3a\xbf\x5f\xcd\xc4\xd3\xc1\xcf\x79\ +\x8e\x2c\x11\x91\x13\x4e\x09\xcb\x9f\x0e\x27\x0f\x18\xd4\x91\x52\ +\xcc\x9e\x4c\x4d\xb0\x5d\xc8\x7d\xa4\xbd\xe0\xcc\x9d\x8c\x1e\x8a\ +\x02\x8e\x0a\x37\xf1\x63\x8a\x43\xd5\xff\x75\xcb\x97\xb7\xf9\xfd\ +\x4d\x41\xce\xa9\x8a\x43\xfa\x74\x26\x6a\xc4\x81\x7a\x82\xf0\xd0\ +\x00\xb5\xad\x44\x23\x0d\x9a\x1b\x5e\x5d\xe5\x0f\xd3\x0b\xdc\x67\ +\x3b\x1c\x36\x6c\x6b\x1b\x17\xee\xc4\x25\xad\x46\x57\xed\xac\xd6\ +\xcf\x68\x3c\x0c\x68\x7c\x3a\x84\xd3\x8b\x13\x9f\xb4\x63\xdb\xf8\ +\x21\xdb\x66\x9f\xd3\x35\x81\xab\xc1\xd0\xc5\x36\xad\xe2\x75\x5c\ +\xc5\x03\x32\x3a\x89\xf0\xbe\x2b\x58\x17\x68\x54\x96\xff\x78\xff\ +\x43\x8f\xf2\x24\x59\xfe\x33\x2f\x3e\x0d\x00\x25\x85\xf8\x2a\x3f\ +\xc0\xec\x3e\xf7\xa8\x74\x26\x4b\x22\xbc\xb8\xba\xcc\xb6\x88\x37\ +\x75\x25\x7f\x46\x73\x00\x8c\xf6\x03\x47\xca\xd5\xe3\x3e\x1d\x16\ +\x6d\x96\x2d\xd2\xa6\xeb\x98\x6c\xd4\xd6\xc9\x36\xa3\x49\x8b\x9f\ +\xaa\x6c\xb3\xf9\x91\x36\x19\x65\x63\xbb\x68\x56\x6d\xd2\x51\x8a\ +\x2e\x5a\xeb\xbb\x1c\x1a\x1d\xee\x62\xd1\x9d\xbe\x7e\xba\x19\xbc\ +\x72\x84\x94\xde\xb1\x9b\xf8\x2a\xdd\xac\x66\x7f\xa5\xc1\xe0\x64\ +\xf4\xa6\xc8\x0f\xfb\x6d\xbe\x4e\xdb\xe9\x9d\x37\xf7\x71\x75\x3b\ +\x66\x30\x7a\x96\x8c\xa9\x90\x87\x03\x87\xb6\xd4\xd1\x51\x04\x8b\ +\x34\xaf\x13\xd0\x9e\x5f\xe3\xa4\xcb\x37\xac\xfe\xa9\x1f\x46\x3c\ +\x52\x56\x45\xfe\x29\xed\x47\x9b\xc7\x06\x73\x4b\x4e\x75\xc6\x28\ +\xdb\x49\x89\x3b\x60\xe7\x12\x56\xee\xd6\x63\xe1\xbf\xf3\x6c\x77\ +\x2c\x85\x93\xd3\x62\x03\xf0\x54\x4b\xd5\xc9\x9e\x6e\x1a\xae\x63\ +\xe4\x73\x51\xc4\x8f\xcb\x1d\xfa\xa7\xfe\x20\x04\xa9\x00\x95\x43\ +\x4a\xcd\xe4\x5c\xfb\x88\x5b\xcb\xbd\x09\x92\x00\xa5\x2f\x10\x73\ +\xf4\x8d\x1c\x05\xc1\x88\x20\x54\x73\x11\x29\x63\x84\xc5\x77\x83\ +\xef\x46\x09\x25\x75\x10\x72\x16\x49\xee\xb8\x13\x54\x20\xa5\xe0\ +\x82\x1b\x08\x05\x6a\x65\x28\x22\xef\x95\xd5\x3e\xf8\x3e\x80\xc0\ +\x42\x87\xeb\xb9\xb6\x11\x13\x9a\x09\x13\x70\x54\x2c\x8f\x42\x66\ +\xe6\x5a\x46\xc2\x6a\xab\x5d\x2d\xd3\xb4\xca\x5c\x63\x5d\xe3\x99\ +\x0b\x5c\xe4\x2d\x97\x5e\x91\x84\x71\x83\xcc\x0b\x4c\xa4\x84\xf6\ +\xd2\xcf\x95\x8a\x2c\x76\x77\x3a\xb0\x14\x03\xa7\x1c\x9f\x2b\x11\ +\x31\xe7\x95\xc6\x44\x54\x33\x2c\x3b\x97\x1e\x74\x64\x31\x97\xcc\ +\x60\x46\x48\x9c\x55\xba\x48\x70\xe9\xac\x0f\xb8\x8c\x0c\x99\x01\ +\x3d\x18\x2c\x3c\xe3\x3c\xe0\xba\x75\x89\xb0\x38\xa8\xe2\x2a\xe0\ +\xaa\x33\x83\x63\x5d\x8d\x09\x62\xd0\xe2\x36\xc2\x91\xb4\x51\x24\ +\x6a\x17\xc3\x37\xa7\xb8\x30\x3a\xe0\xad\x6d\x7e\x4e\xb4\x68\x8d\ +\xb3\x2a\x90\x30\x5c\x8f\x9e\x13\xd2\x12\x52\x72\x2d\xe6\x9c\xa5\ +\xa1\x0d\x40\x93\x4c\x73\x29\xb1\x21\x3c\xe1\xa5\xb6\xce\x90\x10\ +\xc6\xc0\x90\x39\x1c\xe5\x98\x70\xd6\x9a\x80\x1c\x45\x1f\x34\x27\ +\x8a\xe1\x00\x0e\xc1\xeb\xe6\x60\x4a\x54\x0f\x4a\x32\xc8\x58\x87\ +\x0d\x3b\x11\x3c\x1a\x81\xc3\x9d\x71\x81\x8e\x98\xa7\xcf\xdc\xc0\ +\x54\xc7\x18\xb9\x98\x82\xca\xdd\xdc\x53\x53\xa0\x24\xfc\x54\xeb\ +\xf0\x71\xe8\x23\xa5\xe9\x33\xb7\xf0\x9b\x95\x98\x15\xca\x6e\x37\ +\xb8\xd7\x7a\x23\x03\x20\x88\xd5\x3a\xf0\x2d\x83\x5f\x1c\x4d\xd3\ +\x46\x33\xb8\xcd\xc0\x91\xda\x2b\x53\x4f\x6b\x76\x6b\xa6\x09\x1f\ +\x00\x3c\xad\x01\xb0\xd6\x4a\xad\xb0\x14\x8c\x83\xc9\x46\x02\xa2\ +\xaa\xc5\x58\x0f\x31\x60\x32\x6c\x2d\x53\x04\xd6\x70\x40\xeb\xf8\ +\xe1\xf3\xd0\x54\x0d\xfd\xd9\x0e\xb9\x56\xe5\x45\x88\x02\x74\x17\ +\x57\x87\x22\x1d\x37\x14\x43\xa1\x06\x59\x10\x9d\xa1\xbe\x24\x65\ +\x89\x7f\xdd\x6f\x92\x0c\x45\xff\x79\xfa\x78\x4a\x1e\x35\x53\x80\ +\x2d\xdf\x9e\xf6\x7e\xe6\xdd\xb7\x42\x1d\x48\x0f\xdf\x40\x40\x13\ +\x60\x14\x43\x72\xfe\x92\xdc\x61\x40\x1d\x1e\x49\x66\x2d\xd8\x49\ +\x45\x8c\x72\x5d\x21\xd7\x6b\x64\x70\x49\x94\x20\x9c\x30\xdc\x42\ +\x66\x2d\xd6\x87\x9e\xb2\x91\xb4\xc4\x0e\x40\xb5\xf6\x0d\x66\x15\ +\x91\x8e\x34\x5c\x06\xb2\x81\x23\x2c\x56\x1c\xdc\x81\xdc\x53\x81\ +\x8a\x78\x9b\x41\x60\x0a\x06\xd4\x32\x9a\x2b\x44\xbd\xe0\x5c\x82\ +\x6d\x34\x14\x6b\x42\x69\x20\x29\x69\x94\x61\x76\x30\x9c\x40\xf8\ +\x08\x09\x47\xc9\x94\x0c\x39\x17\x36\x19\x46\x29\xd7\xae\x16\x82\ +\x48\x84\xf1\x5c\xb9\x91\x56\x97\x9a\x7d\x2e\x93\x1e\x25\xb3\x0c\ +\xda\x34\xa0\xeb\x47\x9b\xf1\xc4\x28\x2d\x0d\x8c\x84\x62\x44\x20\ +\x62\x9a\x3f\xe0\xfd\x09\xfe\x10\x5f\xcb\x1f\xe6\x29\x7f\xd8\x13\ +\xfa\xb0\x4f\xe9\x43\xf1\x57\xd0\x87\xfa\x79\xf4\xa1\x4f\xe9\xc3\ +\x9d\xd2\x87\x3a\xa2\x0f\x7d\x44\x1f\xe6\xf7\xc8\x1e\x63\x9a\xf8\ +\x19\x0d\x05\x2e\xae\x4e\x49\x21\xf5\xfe\xe1\x29\x31\x5c\x1d\xaa\ +\xea\x65\x5e\xe8\xb7\x18\x67\xfb\xdf\xa8\x06\x6a\xcb\x0c\xe2\x2c\ +\x90\x46\xb8\x17\x4b\x43\x0c\xa0\xb5\x46\x0d\x17\x82\x06\xb5\x95\ +\x2d\x01\x84\xd4\x15\x51\x99\x86\x93\xad\x02\x04\xea\xf0\x5a\xe1\ +\x24\xd5\x68\x94\x66\xba\x55\x93\x48\x70\x94\x49\x00\x32\x72\x54\ +\xbf\xeb\x38\xa1\xbd\x45\xa8\x21\xb2\x28\x3c\xdc\x4d\x89\xda\x2d\ +\x2c\xd5\x64\xa2\x1a\xa1\x3c\x97\x9c\xd0\xe1\x81\x49\xd0\x00\xc5\ +\x93\x6b\x00\x9c\x64\x1c\xa6\xb9\x3a\x92\x12\x20\xa2\x8a\x03\x38\ +\x0a\xa7\x29\xaf\x60\x01\xb2\x9b\xe9\x49\xd9\x28\xe2\x1d\x9b\x5b\ +\xaf\x5e\x0d\x83\x6f\x25\xb2\x8a\xa2\x88\x38\x8c\x02\x8b\x0e\x05\ +\x61\x95\x14\xbf\x27\x91\x3d\x0d\xec\x69\x5c\x4f\xc3\x7a\x1a\xc2\ +\xe9\xa0\x9e\xc6\x74\x22\xa4\x13\x11\x9d\x08\xde\xab\xe3\x19\xb2\ +\xdf\x6b\x44\x5f\x51\xc4\x27\x43\xba\xa5\x72\x80\x08\x80\x34\xa9\ +\x49\x16\x4a\x61\x8b\x36\x7e\x12\x34\x6f\xbc\xa9\xdf\x68\x21\x44\ +\x20\x65\x10\xb8\xb7\xa8\xa3\x86\x3c\x05\xfa\xc5\xb5\x3e\xa0\xa0\ +\x73\x14\x03\x72\xb1\x50\x02\xd1\x19\xe6\xa1\x17\x86\xb6\x90\x75\ +\xd5\x75\x1c\x9d\xec\x20\x52\xa8\xbe\x5c\x30\x8d\x8d\x50\x1e\x2c\ +\xe7\xa8\xaa\x54\x89\x9c\x36\x28\xa0\x52\x1b\x0b\x09\x2a\xb3\x92\ +\xe8\x89\xb1\x8b\x77\xc4\xe1\xd4\x20\x70\x46\xc5\x1d\x0c\xad\x8d\ +\xd3\x24\x41\x81\xb2\xb8\x27\x9c\x4a\xea\xe4\x47\xd5\xb6\x8e\xf0\ +\xc9\x22\x23\xd0\x05\x80\x26\x70\x64\xa9\xa5\xe6\xa3\x93\x51\x23\ +\xa1\x8d\xf7\xb5\xac\x86\x99\x25\x59\x7d\x36\x4b\x66\x33\x45\xc8\ +\x25\x8a\x41\x43\xe1\xa9\xf2\x4a\xe0\x0d\x22\x43\x5b\xe0\xe4\x06\ +\x69\x81\x56\x46\x28\xa4\x03\x89\x3c\xea\xa7\xb2\x54\xc7\x6c\xad\ +\xe4\xd0\x96\x68\x54\xaf\xf9\x30\x0f\x07\x86\xbd\xb8\x79\xa0\xec\ +\x63\x9a\xc6\x96\x3a\xb2\x4e\x2b\x34\xf7\xbd\x61\x27\x92\x09\x6c\ +\x3a\xfe\x7a\xae\xf9\x42\xc9\x69\xea\xcd\x37\x84\x5f\x44\xdb\x7b\ +\xdc\x9f\xa8\xb3\x32\x48\x76\x5c\xcb\x24\x20\x6d\x90\xcf\x32\x72\ +\xd8\x8e\x2a\x8a\xa0\x96\x85\xda\x0a\x0c\x59\x34\x2f\x62\x54\x7d\ +\x9a\x96\x84\xa0\xc0\xf0\x51\x24\x33\x6d\x2f\x25\xa8\x83\xd4\xde\ +\xd6\xfd\x45\x3d\x9f\xd0\x01\x20\xbb\xa6\xe5\xd0\x5a\x38\x02\x07\ +\x5a\x5a\x63\xfc\x94\x68\x32\x58\xe6\xff\x8f\x46\x14\x3a\x46\x26\ +\x04\xe7\xa3\x30\x84\x27\x71\x78\x2e\x0c\x13\x51\x98\x08\xc2\x69\ +\x0c\x4e\xfd\xfd\xda\x08\x84\xe2\xab\x13\xa6\xd7\xab\xba\x3f\x02\ +\x84\x09\x2e\x62\x69\x41\xef\xf2\xa8\xdd\x6c\xda\xd4\x67\x62\xd6\ +\x65\x1b\x65\xda\x6a\x16\x17\xc9\xd3\x8b\x5e\xfb\x6e\x79\x14\xcf\ +\xe7\x82\x5b\x3f\x16\x87\x4d\xba\x4c\xef\x52\x64\xef\xfa\xc5\x70\ +\x8b\x5f\xe7\xc2\x37\x96\x36\xaf\xbf\x97\xec\x7c\x1b\x17\x9f\xd2\ +\xa2\x19\xbf\xcb\xca\xec\x2a\xdb\xd0\x12\xf5\xd7\x4d\x7a\xbe\xce\ +\xca\xfd\x06\xf3\xb3\x1d\x99\x71\x9e\xdf\xa5\xc5\xf5\x26\xbf\xef\ +\xc7\xd3\x5d\x8c\xff\xc2\xab\x38\xf9\x74\x53\xdb\xb7\x8c\x93\xe4\ +\xb0\x3d\x6c\xe2\x2a\x9d\x88\xea\xe8\xef\x14\xbd\xbb\xeb\xd7\xcc\ +\xac\xbd\xa4\x4d\x0c\x3f\xae\x66\x5a\x37\xa8\x9c\x18\x2e\x68\x76\ +\x77\x13\x9c\x18\x7e\x9c\x1a\x6e\x6e\xbc\xa2\xbb\xc9\xf5\xcb\x07\ +\x71\xd0\x2b\xcf\xfb\x6f\x01\x0b\xd0\xba\x50\xc1\x68\xef\x46\xec\ +\x05\xad\x91\xd2\x00\xeb\xea\xcb\x7f\x93\x62\xfd\xcd\x95\x08\x0f\ +\x89\xca\x15\x93\xef\xfe\x40\xea\x6f\x87\xd4\xd0\xfd\x81\xd5\x69\ +\xac\x8a\xfe\xb5\x01\xb0\xea\xa5\xd1\x8e\x49\xf1\x1c\x56\xc7\x95\ +\x10\x0d\x14\x3e\xdf\xcc\x2b\x31\xd7\xe4\xa4\x3a\x79\x25\x16\xb6\ +\xe1\x70\x47\xdf\xe9\x1b\xc3\x07\x25\xae\xfb\x2e\xe9\xca\x83\xc6\ +\x59\xa2\xaf\x36\x91\x42\xf7\x2a\x35\xdc\x6e\x01\x20\xd6\x88\x70\ +\x71\x12\x9a\xda\x21\xc9\xa4\x32\x73\x7a\x49\x82\x3e\x93\x74\x9c\ +\xf1\xce\xce\xe9\x8d\x96\x47\xf3\x08\x09\xae\x4b\xce\x9b\x79\x3f\ +\x89\xf5\xef\x61\x9a\x57\xdd\x28\x70\xce\x4a\x09\x4b\x70\x95\x42\ +\x47\xeb\x27\x45\x53\xc5\x56\xbf\xbe\xdd\xf9\x62\x6f\xfa\x8a\xc6\ +\x74\x94\xe2\xd3\x51\x47\xff\x2d\xad\xf0\x8a\xf1\xa7\x71\x9f\xbc\ +\x17\xd7\x91\xfe\xc5\xc2\xee\xe8\x4f\x07\x4e\x20\x5d\x18\x5d\x93\ +\x84\xb2\x6d\xd4\x39\x5d\x06\xb8\xa2\x3b\x12\xb5\x37\xc2\xe2\xfa\ +\x2a\xe8\x26\x83\xcb\x99\xac\xdf\x7b\x5a\xea\xaf\x02\x5f\xc7\x97\ +\x13\xa7\x4b\xdc\xae\x81\x1a\x24\x8c\x44\x0b\xec\xe8\x12\xad\xe9\ +\xb5\x9d\x9f\x10\x4d\xc5\xc5\x7d\x65\x1b\x7a\xb1\xb8\xb9\x3c\xbb\ +\xa0\x3f\x00\x5e\x9e\xfd\x07\x1b\x72\x19\xbf\ +\x00\x00\x0f\x23\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x50\x61\x72\x61\x6c\ +\x6c\x65\x6c\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\x5f\x65\x78\x74\x65\ +\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\x73\x76\x67\x2e\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x64\x65\ +\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\ +\x32\x37\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\x65\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\ +\x3a\x74\x79\x70\x65\x3d\x22\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x70\x65\x72\x73\x70\x33\x64\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x78\x3d\x22\x30\ +\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x79\x3d\ +\x22\x30\x20\x3a\x20\x31\x30\x30\x30\x20\x3a\x20\x30\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\ +\x70\x5f\x7a\x3d\x22\x36\x34\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x70\x65\x72\x73\x70\x33\x64\x2d\x6f\x72\x69\x67\x69\x6e\ +\x3d\x22\x33\x32\x20\x3a\x20\x32\x31\x2e\x33\x33\x33\x33\x33\x33\ +\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\x65\x32\x37\x33\x34\ +\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\ +\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\ +\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\ +\x2d\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\ +\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x35\ +\x30\x2d\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\ +\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\ +\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\ +\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\ +\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\ +\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\ +\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\x3d\ +\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\ +\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\ +\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\ +\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x34\x22\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x36\x2d\x32\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\ +\x70\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\ +\x73\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\ +\x3d\x22\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x73\x74\x6f\x70\x33\x31\x34\x38\x2d\x30\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ +\x64\x69\x65\x6e\x74\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\ +\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\ +\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x62\x61\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\ +\x6f\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\ +\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\ +\x22\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\ +\x6f\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\ +\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\ +\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\ +\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\ +\x6f\x6d\x3d\x22\x33\x2e\x38\x38\x39\x30\x38\x37\x33\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\ +\x22\x32\x38\x2e\x31\x31\x37\x31\x32\x36\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x35\x33\ +\x2e\x36\x36\x35\x37\x37\x36\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\ +\x61\x79\x65\x72\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\ +\x20\x20\x73\x68\x6f\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\ +\x70\x78\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x67\x72\x69\x64\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\ +\x65\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\ +\x32\x38\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\ +\x3d\x22\x37\x35\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x77\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x32\x32\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\ +\x6f\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\ +\x20\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\ +\x61\x32\x37\x33\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\ +\x3a\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\ +\x57\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\ +\x66\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\ +\x6d\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\ +\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\ +\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\ +\x74\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\ +\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\ +\x72\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\ +\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\ +\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\ +\x61\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\ +\x72\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\ +\x79\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\ +\x22\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x31\x36\x32\x31\x32\x38\ +\x32\x2c\x30\x2c\x30\x2c\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\ +\x36\x2e\x33\x36\x30\x35\x39\x38\x36\x2c\x2d\x36\x36\x2e\x31\x30\ +\x38\x38\x30\x36\x29\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x72\ +\x65\x63\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\ +\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\ +\x30\x3b\x66\x69\x6c\x6c\x3a\x23\x30\x30\x62\x32\x38\x36\x3b\x66\ +\x69\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\ +\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\ +\x73\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x32\x65\x32\x65\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x32\x37\x2e\x38\ +\x34\x35\x32\x33\x30\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\ +\x6e\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\ +\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\ +\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\ +\x69\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\ +\x69\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\ +\x68\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\ +\x6b\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\ +\x6d\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\ +\x62\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\ +\x69\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\ +\x65\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\ +\x6e\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\ +\x3a\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x65\x63\x74\x33\x39\ +\x34\x32\x2d\x34\x2d\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x77\x69\x64\x74\x68\x3d\x22\x32\x39\x33\x2e\x35\x32\x34\x39\ +\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\ +\x68\x74\x3d\x22\x36\x32\x2e\x33\x37\x32\x36\x35\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x78\x3d\x22\x2d\x36\x30\x34\x2e\x30\ +\x31\x37\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x3d\ +\x22\x2d\x33\x38\x34\x2e\x34\x35\x36\x31\x35\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\ +\x22\x6d\x61\x74\x72\x69\x78\x28\x2d\x30\x2e\x38\x34\x31\x33\x32\ +\x37\x36\x32\x2c\x2d\x30\x2e\x35\x34\x30\x35\x32\x35\x35\x31\x2c\ +\x30\x2e\x35\x33\x33\x35\x39\x39\x30\x34\x2c\x2d\x30\x2e\x38\x34\ +\x35\x37\x33\x37\x35\x39\x2c\x30\x2c\x30\x29\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x3c\x72\x65\x63\x74\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\ +\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\ +\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\ +\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\ +\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\ +\x64\x74\x68\x3a\x32\x37\x2e\x38\x34\x35\x32\x33\x30\x31\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\x75\ +\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\ +\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\x2d\ +\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\x72\ +\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\x6e\ +\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x6f\ +\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\x6e\ +\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\x76\ +\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\x69\ +\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\x76\ +\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\x61\ +\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\x6c\ +\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\ +\x3d\x22\x72\x65\x63\x74\x33\x39\x34\x32\x2d\x34\x2d\x39\x2d\x39\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x77\x69\x64\x74\x68\ +\x3d\x22\x32\x39\x33\x2e\x35\x32\x34\x39\x36\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x32\ +\x2e\x33\x37\x32\x36\x35\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x78\x3d\x22\x2d\x36\x30\x33\x2e\x32\x36\x38\x38\x36\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x20\x79\x3d\x22\x2d\x35\x32\x30\ +\x2e\x39\x39\x37\x33\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\ +\x69\x78\x28\x2d\x30\x2e\x38\x34\x31\x33\x32\x37\x36\x31\x2c\x2d\ +\x30\x2e\x35\x34\x30\x35\x32\x35\x35\x33\x2c\x30\x2e\x35\x33\x33\ +\x35\x39\x39\x30\x36\x2c\x2d\x30\x2e\x38\x34\x35\x37\x33\x37\x35\ +\x38\x2c\x30\x2c\x30\x29\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\ +\x2f\x67\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\ +\x3e\x0a\ \x00\x00\x0a\x5e\ \x00\ \x00\x29\x34\x78\x9c\xed\x5a\xdb\x8e\xdb\x46\x12\x7d\xf7\x57\x68\ @@ -31797,6 +36577,460 @@ qt_resource_data = "\ \xcb\xdd\x3a\x51\x7b\x74\x02\xf9\xeb\xe7\x4f\xdb\xeb\xf5\xcb\x1d\ \x4a\xda\x12\xe7\xf5\x68\xd6\xe4\xb0\xb3\x2a\x7b\x9d\xad\xf3\x56\ \xf8\xb9\xb6\x79\xf6\xed\xc5\xff\x01\xea\x49\x79\xab\ +\x00\x00\x0a\x96\ +\x00\ +\x00\x29\x84\x78\x9c\xed\x5a\x59\x6f\xdb\x48\x12\x7e\xcf\xaf\xd0\ +\x2a\x2f\x09\x56\x6c\xf6\x7d\x28\x96\xe7\x21\xc1\x0c\x06\xf0\x62\ +\x81\x9d\x04\xfb\x18\xd0\x24\x2d\x73\x4d\x91\x02\x49\xd9\x92\x7f\ +\xfd\x56\x37\x6f\x91\xf6\xe4\x9a\x64\x1e\xa2\x20\xb1\xf8\x75\xf5\ +\x51\xc7\x57\x5d\x45\xe7\xe2\x97\xe3\x2e\x5d\xdc\xc7\x45\x99\xe4\ +\xd9\x66\x49\x10\x5e\x2e\xe2\x2c\xcc\xa3\x24\xdb\x6e\x96\x1f\xde\ +\xff\xea\xe9\xe5\xa2\xac\x82\x2c\x0a\xd2\x3c\x8b\x37\xcb\x2c\x5f\ +\xfe\x72\xf9\xe2\xe2\x1f\x9e\xb7\x78\x5b\xc4\x41\x15\x47\x8b\x87\ +\xa4\xba\x5d\xfc\x9e\xdd\x95\x61\xb0\x8f\x17\xaf\x6e\xab\x6a\xbf\ +\xf6\xfd\x87\x87\x07\x94\x34\x20\xca\x8b\xad\xff\x7a\xe1\x79\x97\ +\x2f\x5e\x5c\x94\xf7\xdb\x17\x8b\xc5\x02\xf6\xcd\xca\x75\x14\x6e\ +\x96\xcd\x84\xfd\xa1\x48\x9d\x60\x14\xfa\x71\x1a\xef\xe2\xac\x2a\ +\x7d\x82\x88\xbf\xec\xc5\xc3\x5e\x3c\xb4\xbb\x27\xf7\x71\x98\xef\ +\x76\x79\x56\xba\x99\x59\xf9\x72\x20\x5c\x44\x37\x9d\xb4\x3d\xcd\ +\x03\x73\x42\xc4\x18\xe3\x63\xea\x53\xea\x81\x84\x57\x9e\xb2\x2a\ +\x38\x7a\xe3\xa9\x70\xc6\xb9\xa9\x14\x63\xec\xc3\x58\x2f\xf9\x69\ +\x52\xeb\x63\x0a\xa6\x78\xf2\x30\x6e\x74\xb8\x3b\x98\x7f\x0f\x7f\ +\xbb\x09\x2d\x80\xca\xfc\x50\x84\xf1\x0d\xcc\x8c\x51\x16\x57\xfe\ +\xbb\xf7\xef\xba\x41\x0f\xa3\xa8\x8a\x06\xcb\xb4\xd6\x1f\xed\x3b\ +\x72\x49\x16\xec\xe2\x72\x1f\x84\x71\xe9\xb7\xb8\x9b\xff\x90\x44\ +\xd5\xed\x66\x29\xf9\xfe\xe8\x9e\x6f\xe3\x64\x7b\x5b\x0d\x80\x24\ +\xda\x2c\x41\x43\x46\x19\x76\xcf\xed\x19\xd6\x5d\x24\x61\xc4\x68\ +\x2d\xda\x2c\x3c\x1c\xe2\x1a\x91\x45\x61\x94\x3c\x9b\x1d\xe5\xa1\ +\x3d\xd2\x66\xf9\xae\x08\x6e\xaa\x8f\x57\x79\x78\x87\x5a\x43\x76\ +\xeb\xe4\x87\x6a\x7f\xa8\x3e\xc6\xc7\x2a\xce\xea\x05\x41\x95\x81\ +\x5e\x6e\xd8\x4e\x43\x23\x9d\x06\x31\x4e\x96\x97\x80\x5c\x44\xf1\ +\x4d\x69\x47\x6a\x75\xec\x13\xe8\x43\xdd\x18\x8c\x82\x4f\xe2\xa0\ +\xf8\xad\x08\xa2\x04\x22\xb1\x96\x1b\x9c\x22\xcc\xd3\x34\x0e\xc1\ +\x26\x41\xfa\x10\x9c\xca\x65\x27\x00\x4b\x8d\xa7\x32\xaa\x58\xb3\ +\x28\x2c\x5b\x56\xf9\xbe\x95\x05\xcd\xab\x53\x0a\xea\x5a\xd0\x83\ +\x15\xf3\x62\xfd\xf2\xc6\x7d\xde\x38\x28\x07\xdf\x24\xd5\x69\x4d\ +\xde\x2c\xfb\x39\xf9\xcd\x4d\x19\xc3\xc6\x78\x80\x39\x7f\xc0\x0c\ +\xd8\x4b\x2c\x17\xfe\xd7\xed\x86\xe7\x76\x23\xf3\xbb\xa9\x6e\xb7\ +\x0b\x7f\xac\x76\x83\xda\xa7\x20\xfd\x6c\x33\x3a\x4a\xac\x6f\x8b\ +\x18\x28\xfc\x72\xc6\x9e\x43\x73\x8f\xb7\xa0\x9c\xf4\x67\xdd\x36\ +\xe0\x87\x2c\xa9\x80\xab\x87\x32\x2e\xfe\xb0\xf1\xfe\xef\xec\x43\ +\x19\x4f\xa4\xde\x17\x41\x56\x02\xb9\x76\x9b\xe5\x2e\xa8\x8a\xe4\ +\xf8\x8a\xac\x30\xfc\x81\xac\xa8\xb1\xe2\xc6\xc0\x77\x8f\x73\x24\ +\xb9\xe4\x58\xbd\xee\xe6\x87\xc7\xcd\x92\x2a\xad\x90\x30\xa6\xdf\ +\x3b\x3c\x6d\x96\x42\x50\xa4\x8d\x62\xb2\x43\x6f\x66\x65\x6f\x66\ +\x65\x8b\xcd\x92\x69\xa4\xa9\x61\xd2\xf4\x76\xfe\xc2\xc0\x7c\xd6\ +\xa2\x86\x3d\x13\xc0\x94\x63\xf3\xcd\x2c\xea\xd5\x26\x85\x1f\x42\ +\x0a\x89\x34\x63\x7a\x45\x38\xd6\x88\x52\x22\x7b\x93\x1e\x89\x35\ +\x93\x00\x5b\x6b\xa1\x3b\xf4\x04\xa8\x54\x40\x60\x82\x75\x6f\xbc\ +\x23\x05\x59\x83\x31\x22\x7c\x20\x4a\x87\xa2\x3f\xd4\x78\xea\xaf\ +\x35\x1e\x53\xf2\xc7\x1a\x6f\x26\xe3\x99\xcf\xc9\x78\x18\xd3\x80\ +\x46\x5f\x9c\xf1\xcc\xe7\x65\x3c\x0c\x5c\x16\xe6\x8b\x33\x9e\xf9\ +\xd3\x8c\xf7\x23\x42\x4c\xfc\xc5\x21\x06\x49\xef\x6f\xcd\xcf\xb9\ +\x18\x14\xe2\xfb\xdd\xba\x42\x7d\xcf\x5b\x57\x98\x1f\x11\x83\x42\ +\x3c\x1f\x83\xec\x9b\xc5\x20\x46\x4a\x63\x4a\x19\xaf\x6f\xdf\x15\ +\x5c\x95\x48\x0b\x22\xe4\x0a\x9f\x47\x20\xa3\x88\x09\x45\x46\x11\ +\xa8\x88\x0d\x2b\x4a\xcc\x38\x02\x35\x33\x08\x2b\xc2\x46\x21\xd8\ +\xcb\x76\x16\xed\xac\xb4\x87\x8a\x71\x0f\x66\x82\x26\xa3\x9d\xd2\ +\x55\xaa\xd5\xc9\xd6\xd5\x63\x51\x16\x2d\x27\x96\xbe\xdf\x7f\x84\ +\x0b\x1f\x2f\xd6\x0b\x46\xe1\x1f\x32\x2b\x71\xaa\x25\x08\xf4\x0d\ +\xf0\x03\xcf\xca\x3c\xda\xea\xfb\x99\x65\x9a\x13\x78\x79\x91\x6c\ +\x13\xa8\x72\x9d\x1c\x25\x88\xb9\xcf\x78\x0e\x78\x6f\xa0\x1b\x14\ +\xbd\xba\xd1\xfe\xc2\xb7\x55\xb0\xfb\xd6\x69\x6a\x0b\xf2\xe8\x3e\ +\x89\x1f\xfa\x52\xf9\x3a\xe8\xdc\xb8\x0f\xb6\xb1\x0b\x6a\x08\x98\ +\x3a\xaa\x9b\x81\xeb\xbc\x88\xe2\xa2\x1d\x92\xee\x33\x1a\x6a\xe2\ +\xbe\xee\x39\x5f\x9c\x29\x03\xab\x76\xe3\x78\x7e\xbc\xbc\x0d\xa2\ +\xfc\x01\xfc\x7a\x3e\xf8\x98\xe7\x10\x4a\x02\x89\xf3\x01\x57\xa6\ +\x19\x04\xd5\x0c\xa5\x7a\x32\x78\xb2\xe1\x04\x4d\x0b\xa6\x52\x4d\ +\x06\x0f\x45\x01\x91\xea\xa5\xc1\x29\x06\x75\xb6\x94\x75\x09\xb9\ +\xbc\xcd\x1f\xb6\x85\xb5\x4a\x55\x1c\xe2\xf3\x89\xd0\xd0\x1c\x6c\ +\x23\xeb\x1d\x6a\x2a\x34\xed\xd3\x40\xc2\xce\xf5\xae\xaf\xf3\xe3\ +\xfc\x02\x0f\x49\x06\x5a\x7a\x4d\x43\x46\xa8\x9e\xd8\xa2\x91\x68\ +\x5b\x34\x25\x26\x7a\x37\x12\xc7\x3e\x79\x9d\x0f\x59\xdd\x27\x76\ +\x6c\xc6\x76\xc1\x31\xd9\x25\x8f\x71\x64\xb3\x51\x13\x26\xbb\xb8\ +\x0a\xa2\xa0\x0a\xfa\x90\x68\x11\x08\xa6\x36\xed\x5e\x40\x77\xbd\ +\xfe\xcf\xbb\x5f\xbb\xb4\x18\x86\xeb\xff\xe6\xc5\x5d\x9f\xd1\xac\ +\x40\x70\x0d\x0d\xdb\x66\xd9\xa5\x6a\xdb\x97\x85\x6b\x9b\x0e\x82\ +\xea\x32\xd9\x81\xa3\x6d\x2b\xfd\x4f\xe8\x68\x21\x38\xbb\x81\x91\ +\xb0\xe5\x62\xbf\x68\xbd\x6c\x11\xd7\xad\xf2\xec\xdb\x85\x28\xdc\ +\x25\x76\x92\xff\x47\x95\xa4\xe9\xef\x76\x93\x41\xfa\x6e\x16\x4d\ +\xaa\x34\xbe\x74\x7b\xd6\x5f\x5b\x2d\xfc\x46\x8d\x36\xff\x0e\xb4\ +\xbc\xf0\x5b\x33\xb8\xa7\x6d\x6f\x1e\x17\x38\xe4\xdc\xc2\x69\x70\ +\x1d\xa7\x9b\xe5\x95\x1d\x5c\x4c\x46\xb7\x45\x7e\xd8\xef\xf2\x28\ +\x6e\xa6\xb7\x66\xdd\x0e\x79\x0c\xa1\xa8\xfb\x8c\x56\xcd\xa4\x52\ +\x62\x18\xb4\x1b\xc2\xa5\xd2\xfe\xc9\x83\x74\x8a\x30\x91\x82\xac\ +\x3c\xc3\x90\x52\x4a\x92\x41\x47\xd3\x1d\x22\x3e\xee\xf3\xa2\xf2\ +\x6e\x92\x34\xae\x3b\x73\xff\x36\xdf\xc5\xfe\x09\xd2\xcc\x9d\xff\ +\xae\x89\xee\xd2\xbf\x0a\xae\x7d\xd7\xb3\xfb\x49\x98\x67\xa5\x1f\ +\xa6\x79\x19\xa3\x7d\xb6\x7d\x72\xc5\x63\xb4\x4f\x36\x4b\x8e\xb8\ +\x91\x84\x4b\xfa\xa4\xdc\xe9\x4c\xae\xf3\xc3\xb6\x77\xf9\xfc\x1c\ +\x89\x04\x26\x46\xaa\xfe\x1a\x78\xea\x14\x9f\x22\xf9\xf5\x16\x18\ +\xb9\xc7\x7d\x4d\x83\x2a\x7e\xe5\xc9\x95\xa7\x5f\x0f\x77\x6e\xdc\ +\x2a\x86\x9c\xd8\x07\xd5\xed\x30\xc6\x9b\xa2\xa2\x2f\x55\xe0\x7c\ +\xa9\x2d\x6e\x8d\x50\xcc\x3d\x78\xe3\x31\xaf\x38\xa4\xa0\xcc\x7d\ +\x9c\xe5\x91\xad\xb5\x8b\xfc\x2e\x1e\x94\xde\xf6\xb1\xce\x32\x6b\ +\x85\x14\xc7\x9c\xc1\xd5\x6a\xdc\x47\x6b\xd3\x0a\xd8\x3b\x1f\x8c\ +\xb2\xbe\x3e\x54\xd5\x10\xfb\x5f\x9e\x64\x6b\xe0\x54\x5c\xbc\xd9\ +\x05\xc5\x5d\x5c\xac\xb3\x3c\x8b\x9b\xef\x5e\x59\x05\x45\x35\x42\ +\x76\x49\x34\x7a\x8e\xb3\xe6\xb9\x59\xd3\x2d\x95\x42\xda\xa9\xd6\ +\xbc\xc5\xa2\x00\x32\x7e\x51\x04\xa7\x91\xa4\x45\xeb\x62\x09\x0a\ +\xa8\x06\xeb\x15\xbf\x4f\xca\xe4\x3a\x49\xed\x83\xfb\x9a\xc6\x6f\ +\xa2\xa4\xdc\x03\x9d\xd6\x49\x66\x0f\xfe\x26\xbf\x8f\x8b\x9b\x34\ +\x7f\xe8\xc6\xc1\xc9\xf0\xc3\xbb\x0e\xc2\x3b\x4b\x40\x38\x58\x10\ +\x82\x8f\x0f\xd6\x57\xcb\xa1\x07\xc0\x4b\xff\x5a\x40\x51\x81\x91\ +\x86\xcf\x4a\x10\x89\xb8\x16\x74\xf1\x76\x01\xed\xbd\x46\x44\xb2\ +\x0e\x24\x06\x30\xc1\x10\xd3\x86\xaf\x84\x20\xc8\x76\xd4\xda\x62\ +\x14\x09\xf0\x17\x14\x38\x1c\xc1\x95\xa2\xe9\xe2\xaa\x41\xa1\xdc\ +\x7a\x12\x15\xc8\x68\xc1\xc8\x08\x95\x92\x21\x22\x08\x13\x0e\xd5\ +\x14\x2a\x1d\x2e\x9f\x40\xc7\xeb\x5a\x94\x72\x33\x40\x9d\x06\x0c\ +\x41\x63\x05\xa7\x95\x0a\x09\xcb\x3c\x50\x15\x0b\xbb\x18\x68\xc5\ +\x25\x22\x4a\x82\xae\xa0\x3e\x41\x06\x6b\x36\xc0\x60\xb6\x16\x50\ +\x69\x11\x26\x3b\x94\x00\xa6\xe1\x9e\x17\x56\x52\x6a\x84\xb5\xd4\ +\xa6\xc6\x94\x21\xca\xe9\xc4\x65\xad\x92\xb6\x07\x22\x42\xcc\x83\ +\x52\x52\xa4\xe1\x28\xca\xa2\x06\x1b\xc4\x88\x79\x0a\x15\x90\xd8\ +\xb4\x22\x92\xb4\x28\x80\x74\x80\xbe\xb5\x28\x1c\x46\x59\x0f\x08\ +\x0c\x8a\x30\x0d\x5e\xd1\x8a\x21\x6e\x8b\xcf\xd6\xa5\x64\xce\xcd\ +\x8f\xa3\x60\x70\x25\x15\x50\x14\x68\xab\xc6\x57\x49\x01\x45\xd6\ +\xa7\x11\x97\x28\xfe\x6d\x89\x6b\x94\xfe\x49\xdc\x29\x71\xdd\x2b\ +\x43\xf0\x0a\xf8\xca\x8c\x06\xda\x22\xcb\xc0\x35\x29\xb8\xe1\xa3\ +\xc1\xb6\xbe\x22\x5c\x20\xa9\x38\x13\xa3\x51\xf7\x52\x8f\xb9\x7b\ +\x64\x3c\x70\xb2\x65\xbb\x84\x2a\x1c\xda\xe7\x61\x8b\xe8\x6f\xbb\ +\xaf\xe3\xd4\xde\xd7\xdd\x70\xf3\xdb\x22\x05\xaa\xc6\xb0\x2c\x43\ +\xf8\x9c\xdd\x11\x75\xbc\x99\x61\x8b\xd8\xe4\x24\xc2\x11\xf4\x44\ +\x6c\x25\x39\x86\x2f\x92\x6b\x47\xca\x29\x4a\x15\x34\x56\x98\x2b\ +\xbe\x92\x42\x23\xa1\x0d\x74\x18\x80\x29\x5b\x18\x00\xa6\x2c\x37\ +\x9a\xd9\x0a\xb2\x03\xd7\x98\xaf\x14\xa6\x50\x41\x2b\xda\x24\x04\ +\x6c\x14\x05\x0c\xb8\xc5\x81\xc9\x16\xb3\x35\x34\xcc\x56\x4c\x0c\ +\xf6\x06\x01\x21\xa0\x7f\x53\x40\x54\x8c\x05\x16\x16\x83\xc2\x5e\ +\x13\xb1\x52\x90\x05\x64\x3b\x7b\x82\xd9\x14\x65\x9b\x3c\x69\xd8\ +\x14\xc5\x06\x4b\xa7\x8f\x61\x4c\x32\x97\x28\xa6\x5a\x0e\x99\xda\ +\xb0\xcf\x71\x0e\x0a\xc2\x57\x2f\xa7\x5d\xec\xeb\x4f\x26\xe1\x30\ +\x9c\x6b\x06\x92\xfd\xf1\x33\x18\x77\x1e\xf5\xc3\xf8\xd8\xfe\x49\ +\xd5\x80\x57\x73\x35\xc3\xe0\xb5\xdb\x27\xd7\x0c\xf3\x66\x10\xcf\ +\x98\x01\xf4\x7e\x84\xfe\xed\x69\x33\x08\xc8\xea\x2e\xff\x90\x9f\ +\xf9\xe7\xa9\xc2\x41\xc1\xc5\x4a\x6c\x25\x2e\x25\x41\xc2\x51\x0c\ +\xb8\x21\xa4\x31\x0d\x02\x77\xbb\x46\x52\xd8\x47\x08\x69\x42\x98\ +\x2b\x22\x14\x72\x97\xbd\x46\xca\x4e\x76\xd3\x00\x03\x12\xd6\xa8\ +\x80\x4b\x93\x36\x53\x8d\x26\x0e\xe3\xd2\x4a\x02\x66\xec\x57\x3d\ +\xc0\xdc\xc5\xca\x90\x19\xa3\x96\xaf\xda\xd8\x57\x30\xa6\x43\x21\ +\x2f\x68\x9b\x01\x98\x3d\x30\xdc\x8f\x14\x12\x9a\x1c\x61\x90\x01\ +\x84\xa4\xf5\x9a\x1d\xaa\xdd\x25\x3b\x78\xa6\x88\x12\xc8\x9d\x35\ +\x46\xa1\x15\x01\xcc\xd6\x45\x54\xda\x62\xc2\xdd\xcc\x56\x8c\x0f\ +\x8e\x62\x40\x15\x28\x3b\x9c\x20\xac\x42\xa4\xbd\xb5\xa9\xdb\xad\ +\xde\x56\x69\x31\x82\x38\xc2\x8c\xd4\x27\x19\xa0\x14\xb5\x06\x6b\ +\x40\x48\x11\x52\x22\x48\x55\xae\x3a\x81\xa4\x07\x5b\x72\x67\x7b\ +\x6e\x63\xd7\x62\x90\x6d\xdc\x64\xe7\x8f\xab\x89\xcf\x9e\x2a\x01\ +\x46\x2f\xa4\xbf\x92\x87\xea\x27\x0f\xbf\x17\x0f\x21\xfa\xce\x78\ +\xe8\x90\x9e\x87\x46\x9e\xf1\x50\xc1\x75\x35\xe5\xa1\x45\xcf\x79\ +\x68\xb1\x73\x1e\xf6\xd8\x90\x87\x3d\x3a\xe4\x61\x8b\x0e\x79\xa8\ +\xe0\xfa\x3d\xe7\xa1\x7b\x9d\x39\xe1\x21\xdc\x87\x23\x1e\x2a\xb8\ +\x24\xcf\x79\xa8\x88\x38\xe7\xa1\xb2\xb5\xee\x84\x87\x56\xf0\x9c\ +\x87\x6e\xdb\x31\x0f\x15\x96\x33\x3c\x54\x98\xcf\xf0\x10\x96\x9e\ +\xf0\x10\xce\x30\xe1\xa1\xf3\xc7\xd5\xc4\x67\x4f\xf2\x50\x7d\x3b\ +\x1e\x9a\x9f\x3c\xfc\x4e\x3c\x04\x0a\x9d\xf1\xb0\x46\x3a\x1e\x2a\ +\xaa\xcf\x79\x08\xa5\xe0\x0c\x0f\x19\x9d\xf2\x10\xb0\x09\x0f\x3b\ +\x6c\xc4\xc3\x0e\x1d\xf1\xb0\x41\x47\x3c\x64\x6a\xca\x43\xce\xe6\ +\x78\xc8\xc5\x98\x87\xd0\x19\x4c\x78\xc8\xd5\x84\x87\x5c\xcf\xf1\ +\x10\x04\x27\x3c\xb4\xdb\x9e\xf1\x90\xe9\x39\x1e\x42\xaf\x32\xe1\ +\xa1\x82\x26\xf7\x9c\x87\xd6\xf6\xe7\x3c\xac\xfd\x71\x35\xf1\xd9\ +\x93\x3c\x34\x5f\xd7\xf9\x3c\x3e\x3e\xce\x37\x3f\x1c\xcf\x34\x3f\ +\x14\x92\x16\xd5\xd0\xfd\x93\xb6\x2d\x78\x3b\x8b\x42\xb3\x41\xc0\ +\xa9\xd0\x94\x58\xac\x6d\x88\xb4\xfd\xdf\x1d\x14\xfa\x7c\x6a\x43\ +\xca\x30\x5e\x47\xa2\x72\x46\x58\x09\xc6\x91\x96\xb4\x89\x28\xe3\ +\x16\x84\x7e\xb0\x59\xd0\xbe\xe2\x01\x77\xd2\x15\x18\x73\xd0\x39\ +\xf1\x76\xb2\x06\xf3\xba\x25\xa9\xf5\x68\x3d\xdb\xd4\xc7\xa1\xb3\ +\x98\x33\x31\x69\x0e\x6e\x9a\xad\xdf\xce\x81\x54\x29\x02\xb1\xe2\ +\x5e\xe3\x08\xa4\x39\x77\xbb\x40\xa1\xe6\x7a\x21\x01\x5a\xd5\xfd\ +\x99\x9d\xac\xe0\xda\x90\x04\x4e\x09\x35\x11\x37\x70\xab\x59\x4c\ +\x22\x89\x95\xfb\x9d\xaf\x3b\xa3\xd5\x46\x4b\x6b\x1e\xb5\x12\xa0\ +\x96\x32\xa0\x4f\xdd\x07\x4a\xe0\x87\xd5\x91\xdb\xa6\x8c\xda\x57\ +\x5b\x1a\xec\xc7\x39\x04\x90\xb0\x4c\x50\xd4\x75\x72\xc4\x20\x53\ +\x9b\x4c\x0c\xdd\x00\x7d\x20\xc1\xda\x19\x52\x62\xcc\x6c\x94\x03\ +\x9d\x6b\xab\xd1\xce\x92\x33\xd8\xd5\xac\x13\x9f\xed\xed\xa6\xff\ +\x2f\xe8\x6f\xd0\xdb\x35\xf1\xef\x7e\x5c\xd8\x5f\x6d\x5c\xbe\xf8\ +\x3f\x45\x39\x68\xb0\ +\x00\x00\x11\x72\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x49\x6e\x74\x65\x72\ +\x73\x65\x63\x74\x69\x6f\x6e\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\x5f\ +\x65\x78\x74\x65\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\x73\ +\x76\x67\x2e\x69\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\ +\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\x20\ +\x20\x3c\x64\x65\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x64\x65\x66\x73\x32\x37\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\ +\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\ +\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\ +\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\ +\x2d\x63\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\ +\x74\x6f\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\ +\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x73\x74\x6f\x70\x33\x31\x34\x36\x22\x20\x2f\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\ +\x6f\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\ +\x70\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\ +\x74\x6f\x70\x33\x31\x34\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\ +\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\ +\x3e\x0a\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x70\x65\x72\x73\x70\x65\x63\x74\x69\x76\x65\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\ +\x3d\x22\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\ +\x33\x64\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x76\x70\x5f\x78\x3d\x22\x30\x20\x3a\x20\x33\x32\ +\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x79\x3d\x22\x30\x20\x3a\x20\ +\x31\x30\x30\x30\x20\x3a\x20\x30\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x7a\x3d\x22\ +\x36\x34\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\ +\x73\x70\x33\x64\x2d\x6f\x72\x69\x67\x69\x6e\x3d\x22\x33\x32\x20\ +\x3a\x20\x32\x31\x2e\x33\x33\x33\x33\x33\x33\x20\x3a\x20\x31\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x65\x72\x73\ +\x70\x65\x63\x74\x69\x76\x65\x32\x37\x33\x34\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\ +\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\ +\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\ +\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\ +\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x33\x38\x35\x30\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\ +\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\ +\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\ +\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\ +\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\ +\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\ +\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\ +\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\x36\x37\ +\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\ +\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\ +\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\ +\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x31\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\ +\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x38\x35\x30\x2d\x34\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ +\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\ +\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\ +\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\ +\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\ +\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\ +\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\ +\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\ +\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\ +\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\ +\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\x65\x61\ +\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\ +\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x31\x22\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\ +\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\ +\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\ +\x6f\x70\x33\x31\x34\x36\x2d\x32\x22\x20\x2f\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\ +\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\ +\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\ +\x6f\x70\x33\x31\x34\x38\x2d\x32\x22\x20\x2f\x3e\x0a\x20\x20\x20\ +\x20\x3c\x2f\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x3e\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\ +\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\ +\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\ +\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\ +\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x2d\x31\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\ +\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x34\x32\x34\x37\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ +\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\ +\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\ +\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\ +\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\ +\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\ +\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\ +\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\ +\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\ +\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\ +\x38\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\ +\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\ +\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x62\ +\x61\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x70\x61\x67\x65\x63\x6f\ +\x6c\x6f\x72\x3d\x22\x23\x66\x66\x66\x66\x66\x66\x22\x0a\x20\x20\ +\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\ +\x23\x36\x36\x36\x36\x36\x36\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\ +\x72\x64\x65\x72\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x70\x61\x67\x65\x6f\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x70\x61\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\ +\x6d\x3d\x22\x33\x2e\x38\x38\x39\x30\x38\x37\x33\x22\x0a\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\ +\x31\x35\x2e\x35\x31\x37\x37\x36\x39\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x79\x3d\x22\x31\x37\x2e\ +\x34\x31\x30\x34\x38\x33\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x63\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\ +\x79\x65\x72\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\ +\x20\x73\x68\x6f\x77\x67\x72\x69\x64\x3d\x22\x74\x72\x75\x65\x22\ +\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\ +\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\ +\x78\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x3a\x67\x72\x69\x64\x2d\x62\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\ +\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\ +\x77\x69\x6e\x64\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x32\ +\x38\x30\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\ +\x22\x37\x35\x35\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\ +\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\ +\x69\x6e\x64\x6f\x77\x2d\x79\x3d\x22\x32\x32\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\ +\x77\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\ +\x2f\x3e\x0a\x20\x20\x3c\x6d\x65\x74\x61\x64\x61\x74\x61\x0a\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x6d\x65\x74\x61\x64\x61\x74\x61\ +\x32\x37\x33\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\ +\x52\x44\x46\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\ +\x6f\x72\x6b\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\ +\x3a\x61\x62\x6f\x75\x74\x3d\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x3c\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\ +\x61\x67\x65\x2f\x73\x76\x67\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\ +\x66\x6f\x72\x6d\x61\x74\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\ +\x3c\x64\x63\x3a\x74\x79\x70\x65\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x72\x64\x66\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\ +\x67\x2f\x64\x63\x2f\x64\x63\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\ +\x69\x6c\x6c\x49\x6d\x61\x67\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\ +\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\ +\x6b\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\ +\x3e\x0a\x20\x20\x3c\x2f\x6d\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\ +\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\ +\x79\x65\x72\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\ +\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\ +\x65\x72\x22\x3e\x0a\x20\x20\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x67\x34\x32\x38\x39\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\ +\x6d\x61\x74\x72\x69\x78\x28\x30\x2e\x31\x36\x32\x31\x32\x38\x32\ +\x2c\x30\x2c\x30\x2c\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x36\ +\x2e\x33\x36\x30\x35\x39\x38\x36\x2c\x2d\x36\x36\x2e\x31\x30\x38\ +\x38\x30\x36\x29\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x3c\x70\x61\ +\x74\x68\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\ +\x65\x3d\x22\x63\x6f\x6c\x6f\x72\x3a\x23\x30\x30\x30\x30\x30\x30\ +\x3b\x66\x69\x6c\x6c\x3a\x23\x30\x30\x62\x32\x38\x36\x3b\x66\x69\ +\x6c\x6c\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\ +\x6c\x2d\x72\x75\x6c\x65\x3a\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\ +\x74\x72\x6f\x6b\x65\x3a\x23\x30\x30\x32\x65\x32\x65\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x35\x2e\x30\x30\x30\ +\x30\x30\x30\x30\x33\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\ +\x65\x63\x61\x70\x3a\x62\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\ +\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\ +\x74\x3a\x34\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\ +\x74\x79\x3a\x31\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\ +\x61\x72\x72\x61\x79\x3a\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\ +\x65\x2d\x64\x61\x73\x68\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\ +\x61\x72\x6b\x65\x72\x3a\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\ +\x69\x6c\x69\x74\x79\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\ +\x73\x70\x6c\x61\x79\x3a\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\ +\x72\x66\x6c\x6f\x77\x3a\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\ +\x61\x62\x6c\x65\x2d\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\ +\x61\x63\x63\x75\x6d\x75\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\x20\x31\x34\x2e\x34\x33\x37\ +\x35\x20\x34\x2e\x37\x38\x31\x32\x35\x20\x4c\x20\x34\x2e\x36\x35\ +\x36\x32\x35\x20\x31\x34\x2e\x35\x36\x32\x35\x20\x4c\x20\x32\x32\ +\x20\x33\x31\x2e\x39\x30\x36\x32\x35\x20\x4c\x20\x34\x2e\x36\x35\ +\x36\x32\x35\x20\x34\x39\x2e\x32\x35\x20\x4c\x20\x31\x34\x2e\x34\ +\x33\x37\x35\x20\x35\x39\x2e\x30\x33\x31\x32\x35\x20\x4c\x20\x33\ +\x31\x2e\x37\x38\x31\x32\x35\x20\x34\x31\x2e\x36\x38\x37\x35\x20\ +\x4c\x20\x34\x39\x2e\x31\x32\x35\x20\x35\x39\x2e\x30\x33\x31\x32\ +\x35\x20\x4c\x20\x35\x38\x2e\x39\x30\x36\x32\x35\x20\x34\x39\x2e\ +\x32\x35\x20\x4c\x20\x34\x31\x2e\x35\x36\x32\x35\x20\x33\x31\x2e\ +\x39\x30\x36\x32\x35\x20\x4c\x20\x35\x38\x2e\x39\x30\x36\x32\x35\ +\x20\x31\x34\x2e\x35\x36\x32\x35\x20\x4c\x20\x34\x39\x2e\x31\x32\ +\x35\x20\x34\x2e\x37\x38\x31\x32\x35\x20\x4c\x20\x33\x31\x2e\x37\ +\x38\x31\x32\x35\x20\x32\x32\x2e\x31\x32\x35\x20\x4c\x20\x31\x34\ +\x2e\x34\x33\x37\x35\x20\x34\x2e\x37\x38\x31\x32\x35\x20\x7a\x20\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x74\x72\x61\x6e\x73\ +\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x36\x2e\x31\ +\x36\x37\x39\x35\x38\x34\x2c\x30\x2c\x30\x2c\x36\x2e\x31\x36\x37\ +\x39\x35\x38\x34\x2c\x2d\x33\x39\x2e\x32\x33\x31\x39\x30\x38\x2c\ +\x34\x30\x37\x2e\x37\x35\x36\x33\x37\x29\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x65\x63\x74\x33\x39\x34\ +\x32\x2d\x34\x2d\x39\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\ +\x67\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\ +\x0a\ \x00\x00\x0b\xd5\ \x00\ \x00\x37\xfe\x78\x9c\xed\x5a\xdb\x72\xdb\xd6\x15\x7d\xd7\x57\xa0\ @@ -31989,6 +37223,273 @@ qt_resource_data = "\ \xe2\x26\xcb\xa0\x11\x91\x47\x58\x2c\x11\x28\x7f\x4c\x7d\x1c\x4c\ \x7b\xb4\xde\xf8\x64\x7c\xf1\xee\xe8\x84\xde\x7e\xbc\x3b\xfa\x2f\ \xca\x86\x31\xf6\ +\x00\x00\x10\x89\ +\x3c\ +\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\ +\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\ +\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\ +\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\ +\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\ +\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x64\ +\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\ +\x72\x67\x2f\x64\x63\x2f\x65\x6c\x65\x6d\x65\x6e\x74\x73\x2f\x31\ +\x2e\x31\x2f\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x63\x63\ +\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x63\x72\x65\x61\x74\x69\x76\ +\x65\x63\x6f\x6d\x6d\x6f\x6e\x73\x2e\x6f\x72\x67\x2f\x6e\x73\x23\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\ +\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\ +\x67\x2f\x31\x39\x39\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\ +\x2d\x73\x79\x6e\x74\x61\x78\x2d\x6e\x73\x23\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\ +\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\ +\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\ +\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\ +\x78\x6d\x6c\x6e\x73\x3a\x78\x6c\x69\x6e\x6b\x3d\x22\x68\x74\x74\ +\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\ +\x39\x39\x39\x2f\x78\x6c\x69\x6e\x6b\x22\x0a\x20\x20\x20\x78\x6d\ +\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\ +\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\ +\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\ +\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\ +\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\ +\x65\x73\x70\x61\x63\x65\x73\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\ +\x22\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\x36\x34\x70\x78\ +\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x70\ +\x78\x22\x0a\x20\x20\x20\x69\x64\x3d\x22\x73\x76\x67\x32\x37\x32\ +\x36\x22\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x76\ +\x65\x72\x73\x69\x6f\x6e\x3d\x22\x30\x2e\x33\x32\x22\x0a\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\ +\x6e\x3d\x22\x30\x2e\x34\x38\x2e\x31\x20\x72\x39\x37\x36\x30\x22\ +\x0a\x20\x20\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x64\x6f\x63\ +\x6e\x61\x6d\x65\x3d\x22\x53\x6e\x61\x70\x5f\x45\x6e\x64\x70\x6f\ +\x69\x6e\x74\x2e\x73\x76\x67\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x6f\x75\x74\x70\x75\x74\x5f\x65\x78\x74\x65\ +\x6e\x73\x69\x6f\x6e\x3d\x22\x6f\x72\x67\x2e\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x2e\x6f\x75\x74\x70\x75\x74\x2e\x73\x76\x67\x2e\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x76\x65\x72\x73\ +\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x3e\x0a\x20\x20\x3c\x64\x65\ +\x66\x73\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\ +\x32\x37\x32\x38\x22\x3e\x0a\x20\x20\x20\x20\x3c\x72\x61\x64\x69\ +\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\x65\ +\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\x68\x72\x65\x66\x3d\x22\x23\ +\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x33\x31\ +\x34\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\ +\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\x74\x34\x32\x37\ +\x34\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\ +\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\x75\x73\x65\x72\x53\x70\x61\ +\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x67\x72\x61\x64\x69\x65\x6e\x74\x54\x72\x61\x6e\x73\x66\x6f\x72\ +\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x2c\x30\x2c\x30\x2c\ +\x30\x2e\x36\x39\x38\x35\x32\x39\x34\x2c\x30\x2c\x32\x30\x32\x2e\ +\x38\x32\x38\x36\x33\x29\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\ +\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\ +\x20\x20\x20\x20\x20\x63\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\ +\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x78\x3d\x22\x32\ +\x32\x35\x2e\x32\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x66\x79\x3d\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x72\x3d\x22\x33\x34\x2e\x33\x34\x35\ +\x31\x38\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x6c\x69\x6e\ +\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x6f\x6c\x6c\ +\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\x73\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x69\x6e\x65\x61\x72\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x3e\x0a\x20\x20\x20\ +\x20\x20\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\ +\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\ +\x6c\x6f\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\ +\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x30\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\ +\x6f\x70\x33\x31\x34\x36\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x73\x74\x6f\x70\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\ +\x73\x74\x79\x6c\x65\x3d\x22\x73\x74\x6f\x70\x2d\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x66\x66\x66\x66\x66\x66\x3b\x73\x74\x6f\x70\x2d\x6f\ +\x70\x61\x63\x69\x74\x79\x3a\x30\x3b\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x20\x20\x6f\x66\x66\x73\x65\x74\x3d\x22\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x73\x74\x6f\x70\ +\x33\x31\x34\x38\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x2f\x6c\ +\x69\x6e\x65\x61\x72\x47\x72\x61\x64\x69\x65\x6e\x74\x3e\x0a\x20\ +\x20\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\ +\x6e\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\ +\x70\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\ +\x79\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\ +\x3a\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\ +\x61\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\x61\ +\x64\x69\x65\x6e\x74\x34\x32\x37\x32\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\ +\x22\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\ +\x54\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\ +\x78\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\ +\x34\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\ +\x36\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\ +\x22\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\ +\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\ +\x3d\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\ +\x20\x20\x20\x20\x3c\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\ +\x72\x73\x70\x65\x63\x74\x69\x76\x65\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x74\x79\x70\x65\x3d\x22\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\x33\x64\ +\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x76\x70\x5f\x78\x3d\x22\x30\x20\x3a\x20\x33\x32\x20\x3a\ +\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x76\x70\x5f\x79\x3d\x22\x30\x20\x3a\x20\x31\x30\ +\x30\x30\x20\x3a\x20\x30\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x76\x70\x5f\x7a\x3d\x22\x36\x34\ +\x20\x3a\x20\x33\x32\x20\x3a\x20\x31\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x65\x72\x73\x70\ +\x33\x64\x2d\x6f\x72\x69\x67\x69\x6e\x3d\x22\x33\x32\x20\x3a\x20\ +\x32\x31\x2e\x33\x33\x33\x33\x33\x33\x20\x3a\x20\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x65\x72\x73\x70\x65\ +\x63\x74\x69\x76\x65\x32\x37\x33\x34\x22\x20\x2f\x3e\x0a\x20\x20\ +\x20\x20\x3c\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\x69\x65\x6e\ +\x74\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x63\x6f\x6c\x6c\x65\x63\x74\x3d\x22\x61\x6c\x77\x61\x79\ +\x73\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x78\x6c\x69\x6e\x6b\x3a\ +\x68\x72\x65\x66\x3d\x22\x23\x6c\x69\x6e\x65\x61\x72\x47\x72\x61\ +\x64\x69\x65\x6e\x74\x33\x31\x34\x34\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x69\x64\x3d\x22\x72\x61\x64\x69\x61\x6c\x47\x72\x61\x64\ +\x69\x65\x6e\x74\x33\x30\x31\x31\x22\x0a\x20\x20\x20\x20\x20\x20\ +\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x55\x6e\x69\x74\x73\x3d\x22\ +\x75\x73\x65\x72\x53\x70\x61\x63\x65\x4f\x6e\x55\x73\x65\x22\x0a\ +\x20\x20\x20\x20\x20\x20\x20\x67\x72\x61\x64\x69\x65\x6e\x74\x54\ +\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\ +\x28\x31\x2c\x30\x2c\x30\x2c\x30\x2e\x36\x39\x38\x35\x32\x39\x34\ +\x2c\x30\x2c\x32\x30\x32\x2e\x38\x32\x38\x36\x33\x29\x22\x0a\x20\ +\x20\x20\x20\x20\x20\x20\x63\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\ +\x34\x30\x32\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x63\x79\x3d\x22\ +\x36\x37\x32\x2e\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\ +\x20\x20\x66\x78\x3d\x22\x32\x32\x35\x2e\x32\x36\x34\x30\x32\x22\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x66\x79\x3d\x22\x36\x37\x32\x2e\ +\x37\x39\x37\x33\x36\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x72\x3d\ +\x22\x33\x34\x2e\x33\x34\x35\x31\x38\x38\x22\x20\x2f\x3e\x0a\x20\ +\x20\x3c\x2f\x64\x65\x66\x73\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\ +\x70\x6f\x64\x69\x3a\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\ +\x20\x20\x20\x20\x69\x64\x3d\x22\x62\x61\x73\x65\x22\x0a\x20\x20\ +\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\ +\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\ +\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x36\x36\x36\x36\x36\x36\ +\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\ +\x63\x69\x74\x79\x3d\x22\x31\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\x70\x61\ +\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x73\x68\x61\ +\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x33\x2e\x38\x38\ +\x39\x30\x38\x37\x33\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\ +\x63\x61\x70\x65\x3a\x63\x78\x3d\x22\x31\x35\x2e\x37\x39\x36\x31\ +\x36\x39\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\ +\x65\x3a\x63\x79\x3d\x22\x32\x35\x2e\x32\x39\x32\x36\x31\x35\x22\ +\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\ +\x75\x72\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x67\x34\ +\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x73\x68\x6f\x77\x67\x72\ +\x69\x64\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x6f\x63\x75\x6d\x65\x6e\x74\ +\x2d\x75\x6e\x69\x74\x73\x3d\x22\x70\x78\x22\x0a\x20\x20\x20\x20\ +\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x69\x64\x2d\x62\ +\x62\x6f\x78\x3d\x22\x74\x72\x75\x65\x22\x0a\x20\x20\x20\x20\x20\ +\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\ +\x77\x69\x64\x74\x68\x3d\x22\x31\x32\x38\x30\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\ +\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x37\x35\x35\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\ +\x64\x6f\x77\x2d\x78\x3d\x22\x30\x22\x0a\x20\x20\x20\x20\x20\x69\ +\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x79\ +\x3d\x22\x32\x32\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\ +\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x6d\x61\x78\x69\x6d\ +\x69\x7a\x65\x64\x3d\x22\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x6d\ +\x65\x74\x61\x64\x61\x74\x61\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\ +\x22\x6d\x65\x74\x61\x64\x61\x74\x61\x32\x37\x33\x31\x22\x3e\x0a\ +\x20\x20\x20\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\ +\x20\x20\x20\x20\x3c\x63\x63\x3a\x57\x6f\x72\x6b\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x72\x64\x66\x3a\x61\x62\x6f\x75\x74\x3d\ +\x22\x22\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\ +\x66\x6f\x72\x6d\x61\x74\x3e\x69\x6d\x61\x67\x65\x2f\x73\x76\x67\ +\x2b\x78\x6d\x6c\x3c\x2f\x64\x63\x3a\x66\x6f\x72\x6d\x61\x74\x3e\ +\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\x63\x3a\x74\x79\x70\ +\x65\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x64\x66\ +\x3a\x72\x65\x73\x6f\x75\x72\x63\x65\x3d\x22\x68\x74\x74\x70\x3a\ +\x2f\x2f\x70\x75\x72\x6c\x2e\x6f\x72\x67\x2f\x64\x63\x2f\x64\x63\ +\x6d\x69\x74\x79\x70\x65\x2f\x53\x74\x69\x6c\x6c\x49\x6d\x61\x67\ +\x65\x22\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x3c\x64\ +\x63\x3a\x74\x69\x74\x6c\x65\x20\x2f\x3e\x0a\x20\x20\x20\x20\x20\ +\x20\x3c\x2f\x63\x63\x3a\x57\x6f\x72\x6b\x3e\x0a\x20\x20\x20\x20\ +\x3c\x2f\x72\x64\x66\x3a\x52\x44\x46\x3e\x0a\x20\x20\x3c\x2f\x6d\ +\x65\x74\x61\x64\x61\x74\x61\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\ +\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\x79\x65\x72\x31\x22\x0a\x20\ +\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x6c\x61\x62\ +\x65\x6c\x3d\x22\x4c\x61\x79\x65\x72\x20\x31\x22\x0a\x20\x20\x20\ +\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x67\x72\x6f\x75\x70\ +\x6d\x6f\x64\x65\x3d\x22\x6c\x61\x79\x65\x72\x22\x3e\x0a\x20\x20\ +\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\ +\x67\x34\x32\x38\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x74\x72\ +\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\ +\x30\x2e\x31\x36\x32\x31\x32\x38\x32\x2c\x30\x2c\x30\x2c\x30\x2e\ +\x31\x36\x32\x31\x32\x38\x32\x2c\x36\x2e\x33\x36\x30\x35\x39\x38\ +\x36\x2c\x2d\x36\x36\x2e\x31\x30\x38\x38\x30\x36\x29\x22\x3e\x0a\ +\x20\x20\x20\x20\x20\x20\x3c\x70\x61\x74\x68\x0a\x20\x20\x20\x20\ +\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\x22\x63\x6f\x6c\x6f\ +\x72\x3a\x23\x30\x30\x30\x30\x30\x30\x3b\x66\x69\x6c\x6c\x3a\x23\ +\x30\x30\x62\x32\x38\x36\x3b\x66\x69\x6c\x6c\x2d\x6f\x70\x61\x63\ +\x69\x74\x79\x3a\x31\x3b\x66\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3a\ +\x6e\x6f\x6e\x7a\x65\x72\x6f\x3b\x73\x74\x72\x6f\x6b\x65\x3a\x23\ +\x30\x30\x32\x65\x32\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\ +\x64\x74\x68\x3a\x33\x30\x2e\x38\x33\x39\x37\x39\x32\x32\x31\x3b\ +\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3a\x62\ +\x75\x74\x74\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\ +\x6f\x69\x6e\x3a\x72\x6f\x75\x6e\x64\x3b\x73\x74\x72\x6f\x6b\x65\ +\x2d\x6d\x69\x74\x65\x72\x6c\x69\x6d\x69\x74\x3a\x34\x3b\x73\x74\ +\x72\x6f\x6b\x65\x2d\x6f\x70\x61\x63\x69\x74\x79\x3a\x31\x3b\x73\ +\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\x61\x72\x72\x61\x79\x3a\ +\x6e\x6f\x6e\x65\x3b\x73\x74\x72\x6f\x6b\x65\x2d\x64\x61\x73\x68\ +\x6f\x66\x66\x73\x65\x74\x3a\x30\x3b\x6d\x61\x72\x6b\x65\x72\x3a\ +\x6e\x6f\x6e\x65\x3b\x76\x69\x73\x69\x62\x69\x6c\x69\x74\x79\x3a\ +\x76\x69\x73\x69\x62\x6c\x65\x3b\x64\x69\x73\x70\x6c\x61\x79\x3a\ +\x69\x6e\x6c\x69\x6e\x65\x3b\x6f\x76\x65\x72\x66\x6c\x6f\x77\x3a\ +\x76\x69\x73\x69\x62\x6c\x65\x3b\x65\x6e\x61\x62\x6c\x65\x2d\x62\ +\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x61\x63\x63\x75\x6d\x75\ +\x6c\x61\x74\x65\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x64\ +\x3d\x22\x4d\x20\x32\x37\x37\x2e\x30\x35\x36\x34\x2c\x34\x35\x35\ +\x2e\x32\x38\x31\x38\x33\x20\x39\x32\x2e\x34\x34\x31\x30\x32\x37\ +\x2c\x36\x32\x31\x2e\x33\x31\x38\x33\x32\x20\x63\x20\x2d\x38\x2e\ +\x38\x32\x34\x32\x37\x37\x2c\x2d\x33\x2e\x35\x31\x38\x35\x37\x20\ +\x2d\x31\x38\x2e\x34\x35\x33\x38\x33\x35\x2c\x2d\x35\x2e\x33\x35\ +\x35\x31\x33\x20\x2d\x32\x38\x2e\x35\x35\x32\x38\x30\x32\x2c\x2d\ +\x35\x2e\x30\x38\x34\x37\x34\x20\x2d\x33\x39\x2e\x37\x38\x32\x37\ +\x37\x32\x2c\x31\x2e\x30\x36\x35\x31\x37\x20\x2d\x37\x31\x2e\x30\ +\x37\x38\x32\x30\x38\x36\x2c\x33\x34\x2e\x31\x34\x31\x36\x31\x20\ +\x2d\x37\x30\x2e\x30\x31\x33\x30\x33\x34\x38\x2c\x37\x33\x2e\x39\ +\x32\x34\x33\x38\x20\x31\x2e\x30\x36\x35\x31\x37\x33\x37\x2c\x33\ +\x39\x2e\x37\x38\x32\x37\x37\x20\x33\x34\x2e\x31\x34\x31\x36\x30\ +\x34\x38\x2c\x37\x31\x2e\x32\x37\x33\x37\x37\x20\x37\x33\x2e\x39\ +\x32\x34\x33\x37\x37\x38\x2c\x37\x30\x2e\x32\x30\x38\x36\x20\x33\ +\x39\x2e\x37\x38\x32\x37\x37\x32\x2c\x2d\x31\x2e\x30\x36\x35\x31\ +\x37\x20\x37\x31\x2e\x32\x37\x33\x37\x38\x32\x2c\x2d\x33\x34\x2e\ +\x33\x33\x37\x31\x38\x20\x37\x30\x2e\x32\x30\x38\x36\x30\x32\x2c\ +\x2d\x37\x34\x2e\x31\x31\x39\x39\x35\x20\x2d\x30\x2e\x31\x30\x34\ +\x33\x37\x2c\x2d\x33\x2e\x38\x39\x37\x39\x36\x20\x2d\x30\x2e\x36\ +\x37\x33\x31\x32\x2c\x2d\x37\x2e\x36\x32\x38\x37\x36\x20\x2d\x31\ +\x2e\x33\x36\x38\x39\x37\x2c\x2d\x31\x31\x2e\x33\x34\x32\x38\x39\ +\x20\x4c\x20\x33\x32\x33\x2e\x34\x30\x35\x38\x31\x2c\x35\x30\x36\ +\x2e\x39\x31\x31\x35\x35\x20\x32\x37\x37\x2e\x30\x35\x36\x34\x2c\ +\x34\x35\x35\x2e\x32\x38\x31\x38\x33\x20\x7a\x22\x0a\x20\x20\x20\ +\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x72\x65\x63\x74\x32\x32\ +\x36\x39\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x6b\ +\x73\x63\x61\x70\x65\x3a\x63\x6f\x6e\x6e\x65\x63\x74\x6f\x72\x2d\ +\x63\x75\x72\x76\x61\x74\x75\x72\x65\x3d\x22\x30\x22\x20\x2f\x3e\ +\x0a\x20\x20\x20\x20\x3c\x2f\x67\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\ +\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\ " qt_resource_name = "\ @@ -32049,6 +37550,10 @@ qt_resource_name = "\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x66\x00\x69\x00\x2e\x00\x71\x00\x6d\ \x00\x0b\ +\x0a\xf1\xfa\xdd\ +\x00\x44\ +\x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x70\x00\x6c\x00\x2e\x00\x71\x00\x6d\ +\x00\x0b\ \x0a\xf7\x4a\xdd\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x6a\x00\x61\x00\x2e\x00\x71\x00\x6d\ @@ -32112,6 +37617,10 @@ qt_resource_name = "\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x52\x00\x65\x00\x63\x00\x74\x00\x61\x00\x6e\x00\x67\x00\x6c\x00\x65\x00\x2e\x00\x73\ \x00\x76\x00\x67\ +\x00\x0f\ +\x0a\x03\x3b\x47\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x43\x00\x65\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x15\ \x0b\x6a\xb0\xa7\ \x00\x70\ @@ -32175,6 +37684,11 @@ qt_resource_name = "\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x44\x00\x6f\x00\x77\x00\x6e\x00\x67\x00\x72\x00\x61\x00\x64\x00\x65\x00\x2e\x00\x73\ \x00\x76\x00\x67\ +\x00\x11\ +\x09\x41\x15\xe7\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x4d\x00\x69\x00\x64\x00\x70\x00\x6f\x00\x69\x00\x6e\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\ +\ \x00\x0e\ \x0b\xfc\x0f\x47\ \x00\x44\ @@ -32201,6 +37715,11 @@ qt_resource_name = "\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x44\x00\x69\x00\x6d\x00\x65\x00\x6e\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x2e\x00\x73\ \x00\x76\x00\x67\ +\x00\x16\ +\x03\x26\xaf\xe7\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x50\x00\x65\x00\x72\x00\x70\x00\x65\x00\x6e\x00\x64\x00\x69\x00\x63\x00\x75\x00\x6c\x00\x61\ +\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x11\ \x0c\x01\x82\x47\ \x00\x44\ @@ -32210,15 +37729,31 @@ qt_resource_name = "\ \x08\x90\xca\xa7\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x54\x00\x72\x00\x69\x00\x6d\x00\x65\x00\x78\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0d\ +\x0c\x67\x9c\x67\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x47\x00\x72\x00\x69\x00\x64\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x10\ \x02\x9d\x02\x87\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x4f\x00\x66\x00\x66\x00\x73\x00\x65\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0e\ +\x03\xfe\xc1\x67\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x4f\x00\x72\x00\x74\x00\x68\x00\x6f\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0d\ +\x0f\x15\x93\x27\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x4e\x00\x65\x00\x61\x00\x72\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x11\ \x0d\x09\x0b\xe7\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x42\x00\x53\x00\x70\x00\x6c\x00\x69\x00\x6e\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ \ +\x00\x0e\ +\x07\x2c\x24\xc7\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x41\x00\x6e\x00\x67\x00\x6c\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x11\ \x0d\x13\x54\x07\ \x00\x44\ @@ -32241,6 +37776,11 @@ qt_resource_name = "\ \x0c\x0c\x01\x67\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x54\x00\x65\x00\x78\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x12\ +\x03\x46\xc9\x27\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x45\x00\x78\x00\x74\x00\x65\x00\x6e\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x2e\x00\x73\x00\x76\ +\x00\x67\ \x00\x15\ \x0c\xdd\x3c\xc7\ \x00\x44\ @@ -32254,6 +37794,15 @@ qt_resource_name = "\ \x08\x62\x03\xc7\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x44\x00\x72\x00\x61\x00\x66\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x0f\ +\x0d\xf5\x38\xa7\ +\x00\x44\ +\x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x43\x00\x6c\x00\x6f\x00\x6e\x00\x65\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x11\ +\x0b\x07\x6b\x27\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x50\x00\x61\x00\x72\x00\x61\x00\x6c\x00\x6c\x00\x65\x00\x6c\x00\x2e\x00\x73\x00\x76\x00\x67\ +\ \x00\x0e\ \x05\x69\x00\x47\ \x00\x44\ @@ -32275,82 +37824,110 @@ qt_resource_name = "\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x44\x00\x65\x00\x6c\x00\x50\x00\x6f\x00\x69\x00\x6e\x00\x74\x00\x2e\x00\x73\x00\x76\ \x00\x67\ +\x00\x0d\ +\x01\x0e\x93\xc7\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x4c\x00\x6f\x00\x63\x00\x6b\x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x15\ +\x09\x1f\xeb\x67\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x49\x00\x6e\x00\x74\x00\x65\x00\x72\x00\x73\x00\x65\x00\x63\x00\x74\x00\x69\x00\x6f\x00\x6e\ +\x00\x2e\x00\x73\x00\x76\x00\x67\ \x00\x15\ \x03\x74\x49\x07\ \x00\x44\ \x00\x72\x00\x61\x00\x66\x00\x74\x00\x5f\x00\x32\x00\x44\x00\x53\x00\x68\x00\x61\x00\x70\x00\x65\x00\x56\x00\x69\x00\x65\x00\x77\ \x00\x2e\x00\x73\x00\x76\x00\x67\ +\x00\x11\ +\x0a\x37\x15\xe7\ +\x00\x53\ +\x00\x6e\x00\x61\x00\x70\x00\x5f\x00\x45\x00\x6e\x00\x64\x00\x70\x00\x6f\x00\x69\x00\x6e\x00\x74\x00\x2e\x00\x73\x00\x76\x00\x67\ +\ " qt_resource_struct = "\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x01\ -\x00\x00\x00\x10\x00\x02\x00\x00\x00\x02\x00\x00\x00\x42\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x28\x00\x00\x00\x1a\ -\x00\x00\x00\x38\x00\x02\x00\x00\x00\x05\x00\x00\x00\x15\ -\x00\x00\x00\x1a\x00\x02\x00\x00\x00\x10\x00\x00\x00\x05\ -\x00\x00\x02\x72\x00\x01\x00\x00\x00\x01\x00\x05\x98\x94\ -\x00\x00\x01\xe6\x00\x01\x00\x00\x00\x01\x00\x04\x95\x1d\ -\x00\x00\x01\x76\x00\x00\x00\x00\x00\x01\x00\x02\xce\xbb\ -\x00\x00\x02\x3a\x00\x01\x00\x00\x00\x01\x00\x05\x31\xe0\ -\x00\x00\x02\x1e\x00\x01\x00\x00\x00\x01\x00\x04\xfd\x24\ -\x00\x00\x01\x3e\x00\x01\x00\x00\x00\x01\x00\x02\x06\xcc\ -\x00\x00\x02\x02\x00\x01\x00\x00\x00\x01\x00\x04\xc7\xf2\ -\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x96\ -\x00\x00\x02\x56\x00\x01\x00\x00\x00\x01\x00\x05\x65\x8b\ -\x00\x00\x01\x22\x00\x00\x00\x00\x00\x01\x00\x01\x5e\x55\ -\x00\x00\x01\x92\x00\x01\x00\x00\x00\x01\x00\x03\x7e\xe2\ -\x00\x00\x01\x5a\x00\x00\x00\x00\x00\x01\x00\x02\x39\x0a\ -\x00\x00\x01\x06\x00\x01\x00\x00\x00\x01\x00\x01\x2b\x46\ -\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\x7f\x81\ -\x00\x00\x01\xca\x00\x01\x00\x00\x00\x01\x00\x04\x63\x05\ -\x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x03\xb2\x36\ +\x00\x00\x00\x10\x00\x02\x00\x00\x00\x02\x00\x00\x00\x50\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x35\x00\x00\x00\x1b\ +\x00\x00\x00\x38\x00\x02\x00\x00\x00\x05\x00\x00\x00\x16\ +\x00\x00\x00\x1a\x00\x02\x00\x00\x00\x11\x00\x00\x00\x05\ +\x00\x00\x02\x8e\x00\x01\x00\x00\x00\x01\x00\x06\x48\x2e\ +\x00\x00\x02\x02\x00\x01\x00\x00\x00\x01\x00\x05\x44\xb7\ +\x00\x00\x01\x92\x00\x00\x00\x00\x00\x01\x00\x03\x7e\x55\ +\x00\x00\x02\x56\x00\x01\x00\x00\x00\x01\x00\x05\xe1\x7a\ +\x00\x00\x02\x3a\x00\x01\x00\x00\x00\x01\x00\x05\xac\xbe\ +\x00\x00\x01\x3e\x00\x01\x00\x00\x00\x01\x00\x02\x0b\x39\ +\x00\x00\x02\x1e\x00\x01\x00\x00\x00\x01\x00\x05\x77\x8c\ +\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x03\ +\x00\x00\x02\x72\x00\x01\x00\x00\x00\x01\x00\x06\x15\x25\ +\x00\x00\x01\x5a\x00\x00\x00\x00\x00\x01\x00\x02\x3d\x77\ +\x00\x00\x01\x22\x00\x00\x00\x00\x00\x01\x00\x01\x62\xc2\ +\x00\x00\x01\xae\x00\x01\x00\x00\x00\x01\x00\x04\x2e\x7c\ +\x00\x00\x01\x76\x00\x00\x00\x00\x00\x01\x00\x02\xe8\xa4\ +\x00\x00\x01\x06\x00\x01\x00\x00\x00\x01\x00\x01\x2f\xb3\ +\x00\x00\x00\xea\x00\x00\x00\x00\x00\x01\x00\x00\x83\xee\ +\x00\x00\x01\xca\x00\x00\x00\x00\x00\x01\x00\x04\x61\xd0\ +\x00\x00\x01\xe6\x00\x01\x00\x00\x00\x01\x00\x05\x12\x9f\ \x00\x00\x00\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x00\xb0\x00\x01\x00\x00\x00\x01\x00\x00\x06\x29\ +\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x06\x29\ \x00\x00\x00\x64\x00\x00\x00\x00\x00\x01\x00\x00\x01\x64\ \x00\x00\x00\x96\x00\x00\x00\x00\x00\x01\x00\x00\x04\xc4\ \x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x03\x12\ -\x00\x00\x05\x9a\x00\x01\x00\x00\x00\x01\x00\x06\x98\x18\ -\x00\x00\x03\x70\x00\x00\x00\x00\x00\x01\x00\x05\xfc\x04\ -\x00\x00\x07\x1a\x00\x01\x00\x00\x00\x01\x00\x07\x1b\xa6\ -\x00\x00\x04\x7a\x00\x01\x00\x00\x00\x01\x00\x06\x46\xeb\ -\x00\x00\x05\xe2\x00\x00\x00\x00\x00\x01\x00\x06\xb5\x62\ -\x00\x00\x06\xa4\x00\x01\x00\x00\x00\x01\x00\x06\xfa\x9a\ -\x00\x00\x08\xea\x00\x01\x00\x00\x00\x01\x00\x07\xba\x42\ -\x00\x00\x03\xb6\x00\x01\x00\x00\x00\x01\x00\x06\x15\x26\ -\x00\x00\x05\xbc\x00\x00\x00\x00\x00\x01\x00\x06\xa2\xcc\ -\x00\x00\x03\xda\x00\x00\x00\x00\x00\x01\x00\x06\x1a\xa5\ -\x00\x00\x06\x2a\x00\x01\x00\x00\x00\x01\x00\x06\xce\x27\ -\x00\x00\x03\x92\x00\x01\x00\x00\x00\x01\x00\x06\x0a\xba\ -\x00\x00\x08\x74\x00\x00\x00\x00\x00\x01\x00\x07\x9c\x88\ -\x00\x00\x03\x14\x00\x01\x00\x00\x00\x01\x00\x05\xeb\x6e\ -\x00\x00\x04\xca\x00\x01\x00\x00\x00\x01\x00\x06\x62\x0a\ -\x00\x00\x08\x2c\x00\x01\x00\x00\x00\x01\x00\x07\x88\x92\ -\x00\x00\x08\x4e\x00\x01\x00\x00\x00\x01\x00\x07\x92\xf4\ -\x00\x00\x04\xa8\x00\x00\x00\x00\x00\x01\x00\x06\x4f\xf1\ -\x00\x00\x02\xe2\x00\x01\x00\x00\x00\x01\x00\x05\xe3\xb5\ -\x00\x00\x07\xe4\x00\x00\x00\x00\x00\x01\x00\x07\x5f\x08\ -\x00\x00\x05\x1e\x00\x01\x00\x00\x00\x01\x00\x06\x73\x7a\ -\x00\x00\x08\x08\x00\x00\x00\x00\x00\x01\x00\x07\x75\xbb\ -\x00\x00\x06\x7e\x00\x00\x00\x00\x00\x01\x00\x06\xe8\xe2\ -\x00\x00\x04\x2c\x00\x01\x00\x00\x00\x01\x00\x06\x36\x0d\ -\x00\x00\x03\x40\x00\x01\x00\x00\x00\x01\x00\x05\xf3\x75\ -\x00\x00\x07\x3c\x00\x01\x00\x00\x00\x01\x00\x07\x24\x4f\ -\x00\x00\x08\x9a\x00\x00\x00\x00\x00\x01\x00\x07\xa5\x15\ -\x00\x00\x05\x78\x00\x01\x00\x00\x00\x01\x00\x06\x8a\xb9\ -\x00\x00\x06\x56\x00\x01\x00\x00\x00\x01\x00\x06\xdf\x31\ -\x00\x00\x07\x92\x00\x00\x00\x00\x00\x01\x00\x07\x40\xa4\ -\x00\x00\x04\x50\x00\x01\x00\x00\x00\x01\x00\x06\x3c\xaa\ -\x00\x00\x04\xfe\x00\x01\x00\x00\x00\x01\x00\x06\x6d\xfb\ -\x00\x00\x07\xb4\x00\x01\x00\x00\x00\x01\x00\x07\x55\x35\ -\x00\x00\x06\xca\x00\x01\x00\x00\x00\x01\x00\x07\x00\x5e\ -\x00\x00\x06\xf2\x00\x01\x00\x00\x00\x01\x00\x07\x0b\xd0\ -\x00\x00\x08\xc0\x00\x01\x00\x00\x00\x01\x00\x07\xaf\xc0\ -\x00\x00\x03\xfc\x00\x01\x00\x00\x00\x01\x00\x06\x2d\xc4\ -\x00\x00\x05\x4c\x00\x00\x00\x00\x00\x01\x00\x06\x7b\x5f\ -\x00\x00\x06\x0a\x00\x01\x00\x00\x00\x01\x00\x06\xc4\xb3\ -\x00\x00\x07\x60\x00\x00\x00\x00\x00\x01\x00\x07\x2b\xa0\ -\x00\x00\x02\x8e\x00\x01\x00\x00\x00\x01\x00\x05\xcc\x17\ -\x00\x00\x02\xba\x00\x01\x00\x00\x00\x01\x00\x05\xd5\x2b\ +\x00\x00\x06\x02\x00\x01\x00\x00\x00\x01\x00\x07\x70\xc5\ +\x00\x00\x03\xb0\x00\x00\x00\x00\x00\x01\x00\x06\xc2\x72\ +\x00\x00\x08\x38\x00\x01\x00\x00\x00\x01\x00\x08\x24\x8f\ +\x00\x00\x0a\x7e\x00\x01\x00\x00\x00\x01\x00\x08\xe3\x77\ +\x00\x00\x04\xba\x00\x01\x00\x00\x00\x01\x00\x07\x0d\x59\ +\x00\x00\x06\x4a\x00\x00\x00\x00\x00\x01\x00\x07\x8e\x0f\ +\x00\x00\x07\x5e\x00\x01\x00\x00\x00\x01\x00\x07\xe6\xad\ +\x00\x00\x06\xbe\x00\x00\x00\x00\x00\x01\x00\x07\xb7\xde\ +\x00\x00\x08\xd2\x00\x01\x00\x00\x00\x01\x00\x08\x5e\x1e\ +\x00\x00\x0a\xce\x00\x01\x00\x00\x00\x01\x00\x08\xff\x87\ +\x00\x00\x03\xf6\x00\x01\x00\x00\x00\x01\x00\x06\xdb\x94\ +\x00\x00\x07\x84\x00\x01\x00\x00\x00\x01\x00\x07\xec\x71\ +\x00\x00\x06\x24\x00\x00\x00\x00\x00\x01\x00\x07\x7b\x79\ +\x00\x00\x04\x1a\x00\x00\x00\x00\x00\x01\x00\x06\xe1\x13\ +\x00\x00\x06\x92\x00\x01\x00\x00\x00\x01\x00\x07\xa6\xd4\ +\x00\x00\x03\xd2\x00\x01\x00\x00\x00\x01\x00\x06\xd1\x28\ +\x00\x00\x0a\x08\x00\x00\x00\x00\x00\x01\x00\x08\xc5\xbd\ +\x00\x00\x03\x30\x00\x01\x00\x00\x00\x01\x00\x06\x9c\xbc\ +\x00\x00\x05\x0a\x00\x01\x00\x00\x00\x01\x00\x07\x28\x78\ +\x00\x00\x09\xc0\x00\x01\x00\x00\x00\x01\x00\x08\xb1\xc7\ +\x00\x00\x09\xe2\x00\x01\x00\x00\x00\x01\x00\x08\xbc\x29\ +\x00\x00\x04\xe8\x00\x00\x00\x00\x00\x01\x00\x07\x16\x5f\ +\x00\x00\x02\xfe\x00\x01\x00\x00\x00\x01\x00\x06\x95\x03\ +\x00\x00\x07\xee\x00\x01\x00\x00\x00\x01\x00\x08\x0d\x65\ +\x00\x00\x09\x2c\x00\x00\x00\x00\x00\x01\x00\x08\x6e\x66\ +\x00\x00\x05\x5e\x00\x01\x00\x00\x00\x01\x00\x07\x39\xe8\ +\x00\x00\x09\x50\x00\x00\x00\x00\x00\x01\x00\x08\x85\x19\ +\x00\x00\x07\x18\x00\x00\x00\x00\x00\x01\x00\x07\xce\x80\ +\x00\x00\x04\x6c\x00\x01\x00\x00\x00\x01\x00\x06\xfc\x7b\ +\x00\x00\x0a\x9e\x00\x00\x00\x00\x00\x01\x00\x08\xee\x11\ +\x00\x00\x05\xb8\x00\x00\x00\x00\x00\x01\x00\x07\x51\x27\ +\x00\x00\x03\x5c\x00\x00\x00\x00\x00\x01\x00\x06\xa4\xc3\ +\x00\x00\x0a\xfe\x00\x00\x00\x00\x00\x01\x00\x09\x0b\x60\ +\x00\x00\x09\x98\x00\x00\x00\x00\x00\x01\x00\x08\xa2\xa0\ +\x00\x00\x03\x80\x00\x01\x00\x00\x00\x01\x00\x06\xb9\xe3\ +\x00\x00\x08\x5a\x00\x01\x00\x00\x00\x01\x00\x08\x2d\x38\ +\x00\x00\x0a\x2e\x00\x00\x00\x00\x00\x01\x00\x08\xce\x4a\ +\x00\x00\x05\xe0\x00\x01\x00\x00\x00\x01\x00\x07\x63\x66\ +\x00\x00\x06\xf0\x00\x01\x00\x00\x00\x01\x00\x07\xc4\xcf\ +\x00\x00\x08\xb0\x00\x00\x00\x00\x00\x01\x00\x08\x49\x8d\ +\x00\x00\x04\x90\x00\x01\x00\x00\x00\x01\x00\x07\x03\x18\ +\x00\x00\x07\x3e\x00\x01\x00\x00\x00\x01\x00\x07\xe0\x38\ +\x00\x00\x05\x3e\x00\x01\x00\x00\x00\x01\x00\x07\x34\x69\ +\x00\x00\x08\xfc\x00\x01\x00\x00\x00\x01\x00\x08\x64\x93\ +\x00\x00\x07\xc6\x00\x01\x00\x00\x00\x01\x00\x08\x01\xf3\ +\x00\x00\x08\x10\x00\x01\x00\x00\x00\x01\x00\x08\x14\xb9\ +\x00\x00\x0a\x54\x00\x01\x00\x00\x00\x01\x00\x08\xd8\xf5\ +\x00\x00\x09\x74\x00\x01\x00\x00\x00\x01\x00\x08\x97\xf0\ +\x00\x00\x04\x3c\x00\x01\x00\x00\x00\x01\x00\x06\xf4\x32\ +\x00\x00\x07\xa6\x00\x00\x00\x00\x00\x01\x00\x07\xf2\x21\ +\x00\x00\x05\x8c\x00\x00\x00\x00\x00\x01\x00\x07\x41\xcd\ +\x00\x00\x06\x72\x00\x01\x00\x00\x00\x01\x00\x07\x9d\x60\ +\x00\x00\x08\x7e\x00\x00\x00\x00\x00\x01\x00\x08\x34\x89\ +\x00\x00\x02\xaa\x00\x01\x00\x00\x00\x01\x00\x06\x7b\xb1\ +\x00\x00\x02\xd6\x00\x01\x00\x00\x00\x01\x00\x06\x85\x1e\ " def qInitResources(): diff --git a/src/Mod/Draft/Init.py b/src/Mod/Draft/Init.py index 5069e5fd67..47fd3dc985 100644 --- a/src/Mod/Draft/Init.py +++ b/src/Mod/Draft/Init.py @@ -1,6 +1,6 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index 957d9ed072..b4b83ee359 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -1,6 +1,6 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -24,8 +24,6 @@ __title__="FreeCAD Draft Workbench - Init file" __author__ = "Yorik van Havre " __url__ = ["http://free-cad.sourceforge.net"] -import os,DraftTools - class DraftWorkbench (Workbench): "the Draft Workbench" Icon = """ @@ -179,9 +177,9 @@ class DraftWorkbench (Workbench): else: return try: - import macros,DraftTools,DraftGui + import os,macros,DraftTools,DraftGui self.appendMenu(["&Macro",str(DraftTools.translate("draft","Installed Macros"))],macros.macrosList) - Log ('Loading Draft GUI...done\n') + Log ('Loading Draft module...done\n') except: pass self.cmdList = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc", @@ -190,28 +188,36 @@ class DraftWorkbench (Workbench): self.modList = ["Draft_Move","Draft_Rotate","Draft_Offset", "Draft_Trimex", "Draft_Upgrade", "Draft_Downgrade", "Draft_Scale", "Draft_Drawing","Draft_Edit","Draft_WireToBSpline","Draft_AddPoint", - "Draft_DelPoint","Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array"] + "Draft_DelPoint","Draft_Shape2DView","Draft_Draft2Sketch","Draft_Array", + "Draft_Clone"] self.treecmdList = ["Draft_ApplyStyle","Draft_ToggleDisplayMode","Draft_AddToGroup", - "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap"] + "Draft_SelectGroup","Draft_SelectPlane","Draft_ToggleSnap", + "Draft_ShowSnapBar","Draft_ToggleGrid"] self.lineList = ["Draft_UndoLine","Draft_FinishLine","Draft_CloseLine"] self.appendToolbar(str(DraftTools.translate("draft","Draft creation tools")),self.cmdList) self.appendToolbar(str(DraftTools.translate("draft","Draft modification tools")),self.modList) - self.appendMenu(str(DraftTools.translate("draft","Draft")),self.cmdList+self.modList) - self.appendMenu([str(DraftTools.translate("draft","Draft")),str(DraftTools.translate("draft","Display options"))],self.treecmdList) - self.appendMenu([str(DraftTools.translate("draft","Draft")),str(DraftTools.translate("draft","Wire tools"))],self.lineList) + self.appendMenu(str(DraftTools.translate("draft","&Draft")),self.cmdList+self.modList) + self.appendMenu([str(DraftTools.translate("draft","&Draft")),str(DraftTools.translate("draft","Context tools"))],self.treecmdList) + self.appendMenu([str(DraftTools.translate("draft","&Draft")),str(DraftTools.translate("draft","Wire tools"))],self.lineList) def Activated(self): - FreeCADGui.draftToolBar.Activated() - + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.Activated() + if hasattr(FreeCADGui,"Snapper"): + FreeCADGui.Snapper.show() + Msg("Draft workbench activated\n") + def Deactivated(self): - FreeCADGui.draftToolBar.Deactivated() + if hasattr(FreeCADGui,"draftToolBar"): + FreeCADGui.draftToolBar.Deactivated() + Msg("Draft workbench deactivated\n") def ContextMenu(self, recipient): if (recipient == "View"): if (FreeCAD.activeDraftCommand == None): if (FreeCADGui.Selection.getSelection()): self.appendContextMenu("Draft",self.cmdList+self.modList) - self.appendContextMenu("Display options",self.treecmdList) + self.appendContextMenu("Draft context tools",self.treecmdList) else: self.appendContextMenu("Draft",self.cmdList) else: diff --git a/src/Mod/Draft/Makefile.am b/src/Mod/Draft/Makefile.am index 7cf2d42240..f93f64cfe2 100644 --- a/src/Mod/Draft/Makefile.am +++ b/src/Mod/Draft/Makefile.am @@ -13,6 +13,8 @@ data_DATA = \ DraftGui.py \ DraftSnap.py \ DraftTrackers.py \ + DraftVecUtils.py \ + DraftGeomUtils.py \ WorkingPlane.py \ importOCA.py \ importDXF.py \ @@ -28,8 +30,6 @@ nobase_data_DATA = \ draftlibs/dxfImportObjects.py \ draftlibs/dxfLibrary.py \ draftlibs/dxfReader.py \ - draftlibs/fcvec.py \ - draftlibs/fcgeo.py \ draftlibs/__init__.py CLEANFILES = $(BUILT_SOURCES) @@ -39,76 +39,97 @@ EXTRA_DIST = \ CMakeLists.txt \ draft.dox \ Resources/Draft.qrc \ - Resources/translations/Draft_af.ts \ - Resources/translations/Draft_af.qm \ - Resources/translations/Draft_de.ts \ - Resources/translations/Draft_de.qm \ - Resources/translations/Draft_es.ts \ - Resources/translations/Draft_es.qm \ - Resources/translations/Draft_fi.ts \ - Resources/translations/Draft_fi.qm \ - Resources/translations/Draft_fr.ts \ - Resources/translations/Draft_fr.qm \ - Resources/translations/Draft_hr.ts \ - Resources/translations/Draft_hr.qm \ - Resources/translations/Draft_it.ts \ - Resources/translations/Draft_it.qm \ - Resources/translations/Draft_nl.ts \ - Resources/translations/Draft_nl.qm \ - Resources/translations/Draft_no.ts \ - Resources/translations/Draft_no.qm \ - Resources/translations/Draft_pt.ts \ - Resources/translations/Draft_pt.qm \ - Resources/translations/Draft_ru.ts \ - Resources/translations/Draft_ru.qm \ - Resources/translations/Draft_se.ts \ - Resources/translations/Draft_se.qm \ - Resources/translations/Draft_uk.ts \ - Resources/translations/Draft_uk.qm \ - Resources/translations/Draft_zh.ts \ - Resources/translations/Draft_zh.qm \ - Resources/icons/preferences-draft.svg \ - Resources/icons/Draft_AddPoint.svg \ - Resources/icons/Draft_AddToGroup.svg \ - Resources/icons/Draft_Apply.svg \ - Resources/icons/Draft_Arc.svg \ - Resources/icons/Draft_BSpline.svg \ - Resources/icons/Draft_Circle.svg \ - Resources/icons/Draft_Cursor.svg \ - Resources/icons/Draft_DelPoint.svg \ - Resources/icons/Draft_Dimension.svg \ - Resources/icons/Draft_Dot.svg \ - Resources/icons/Draft_Downgrade.svg \ - Resources/icons/Draft_Drawing.svg \ - Resources/icons/Draft_Edit.svg \ - Resources/icons/Draft_Finish.svg \ - Resources/icons/Draft_Line.svg \ - Resources/icons/Draft_Lock.svg \ - Resources/icons/Draft_Macro.svg \ - Resources/icons/Draft_Move.svg \ - Resources/icons/Draft_Offset.svg \ - Resources/icons/Draft_Point.svg \ - Resources/icons/Draft_Polygon.svg \ - Resources/icons/Draft_Rectangle.svg \ - Resources/icons/Draft_Rotate.svg \ - Resources/icons/Draft_Scale.svg \ - Resources/icons/Draft_SelectGroup.svg \ - Resources/icons/Draft_SelectPlane.svg \ - Resources/icons/Draft_SwitchMode.svg \ - Resources/icons/Draft_Text.svg \ - Resources/icons/Draft_Trimex.svg \ - Resources/icons/Draft_Upgrade.svg \ - Resources/icons/Draft_Wire.svg \ - Resources/icons/Draft_Wipe.svg \ - Resources/icons/Draft_WireToBSpline.svg \ - Resources/icons/Draft_Construction.svg \ - Resources/icons/Draft_Draft.svg \ Resources/icons/Draft_2DShapeView.svg \ + Resources/icons/Draft_AddPoint.svg \ + Resources/icons/Draft_AddToGroup.svg \ + Resources/icons/Draft_Apply.svg \ + Resources/icons/Draft_Arc.svg \ + Resources/icons/Draft_Array.svg \ + Resources/icons/Draft_BSpline.svg \ + Resources/icons/Draft_Circle.svg \ + Resources/icons/Draft_Clone.svg \ + Resources/icons/Draft_Construction.svg \ Resources/icons/Draft_Cursor.svg \ - Resources/patterns/concrete.svg \ - Resources/patterns/cross.svg \ - Resources/patterns/line.svg \ - Resources/patterns/simple.svg \ - Resources/patterns/square.svg \ + Resources/icons/Draft_DelPoint.svg \ + Resources/icons/Draft_Dimension.svg \ + Resources/icons/Draft_Dot.svg \ + Resources/icons/Draft_Downgrade.svg \ + Resources/icons/Draft_Draft2Sketch.svg \ + Resources/icons/Draft_Draft.svg \ + Resources/icons/Draft_Drawing.svg \ + Resources/icons/Draft_Edit.svg \ + Resources/icons/Draft_Finish.svg \ + Resources/icons/Draft_Line.svg \ + Resources/icons/Draft_Lock.svg \ + Resources/icons/Draft_Macro.svg \ + Resources/icons/Draft_Move.svg \ + Resources/icons/Draft_Offset.svg \ + Resources/icons/Draft_Point.svg \ + Resources/icons/Draft_Polygon.svg \ + Resources/icons/Draft_Rectangle.svg \ + Resources/icons/Draft_Rotate.svg \ + Resources/icons/Draft_Scale.svg \ + Resources/icons/Draft_SelectGroup.svg \ + Resources/icons/Draft_SelectPlane.svg \ + Resources/icons/Draft_SwitchMode.svg \ + Resources/icons/Draft_Text.svg \ + Resources/icons/Draft_Trimex.svg \ + Resources/icons/Draft_Upgrade.svg \ + Resources/icons/Draft_Wipe.svg \ + Resources/icons/Draft_Wire.svg \ + Resources/icons/Draft_WireToBSpline.svg \ + Resources/icons/preferences-draft.svg \ + Resources/icons/Snap_Angle.svg \ + Resources/icons/Snap_Center.svg \ + Resources/icons/Snap_Endpoint.svg \ + Resources/icons/Snap_Extension.svg \ + Resources/icons/Snap_Grid.svg \ + Resources/icons/Snap_Intersection.svg \ + Resources/icons/Snap_Lock.svg \ + Resources/icons/Snap_Midpoint.svg \ + Resources/icons/Snap_Near.svg \ + Resources/icons/Snap_Ortho.svg \ + Resources/icons/Snap_Parallel.svg \ + Resources/icons/Snap_Perpendicular.svg \ + Resources/patterns/concrete.svg \ + Resources/patterns/cross.svg \ + Resources/patterns/line.svg \ + Resources/patterns/simple.svg \ + Resources/patterns/square.svg \ + Resources/translations/Draft_af.qm \ + Resources/translations/Draft_af.ts \ + Resources/translations/Draft_de.qm \ + Resources/translations/Draft_de.ts \ + Resources/translations/Draft_es.qm \ + Resources/translations/Draft_es.ts \ + Resources/translations/Draft_fi.qm \ + Resources/translations/Draft_fi.ts \ + Resources/translations/Draft_fr.qm \ + Resources/translations/Draft_fr.ts \ + Resources/translations/Draft_hr.qm \ + Resources/translations/Draft_hr.ts \ + Resources/translations/Draft_hu.qm \ + Resources/translations/Draft_hu.ts \ + Resources/translations/Draft_it.qm \ + Resources/translations/Draft_it.ts \ + Resources/translations/Draft_ja.qm \ + Resources/translations/Draft_ja.ts \ + Resources/translations/Draft_nl.qm \ + Resources/translations/Draft_nl.ts \ + Resources/translations/Draft_no.qm \ + Resources/translations/Draft_no.ts \ + Resources/translations/Draft_pl.qm \ + Resources/translations/Draft_pl.ts \ + Resources/translations/Draft_pt.qm \ + Resources/translations/Draft_pt.ts \ + Resources/translations/Draft_ru.qm \ + Resources/translations/Draft_ru.ts \ + Resources/translations/Draft_se.qm \ + Resources/translations/Draft_se.ts \ + Resources/translations/Draft_uk.qm \ + Resources/translations/Draft_uk.ts \ + Resources/translations/Draft_zh.qm \ + Resources/translations/Draft_zh.ts \ Resources/ui/userprefs-base.ui \ - Resources/ui/userprefs-import.ui + Resources/ui/userprefs-import.ui + diff --git a/src/Mod/Draft/Resources/Draft.qrc b/src/Mod/Draft/Resources/Draft.qrc index 6823b6747a..c2ac4a36d1 100644 --- a/src/Mod/Draft/Resources/Draft.qrc +++ b/src/Mod/Draft/Resources/Draft.qrc @@ -40,6 +40,19 @@ icons/Draft_Dot.svg icons/Draft_Point.svg icons/Draft_Snap.svg + icons/Snap_Lock.svg + icons/Snap_Endpoint.svg + icons/Snap_Midpoint.svg + icons/Snap_Perpendicular.svg + icons/Snap_Grid.svg + icons/Snap_Intersection.svg + icons/Snap_Parallel.svg + icons/Snap_Angle.svg + icons/Snap_Center.svg + icons/Snap_Extension.svg + icons/Snap_Ortho.svg + icons/Snap_Near.svg + icons/Draft_Clone.svg patterns/concrete.svg patterns/cross.svg patterns/line.svg @@ -56,6 +69,7 @@ translations/Draft_ru.qm translations/Draft_se.qm translations/Draft_uk.qm + translations/Draft_pl.qm translations/Draft_pt.qm translations/Draft_hr.qm translations/Draft_zh.qm diff --git a/src/Mod/Draft/Resources/icons/Draft_Clone.svg b/src/Mod/Draft/Resources/icons/Draft_Clone.svg new file mode 100755 index 0000000000..2084513660 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Draft_Clone.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Angle.svg b/src/Mod/Draft/Resources/icons/Snap_Angle.svg new file mode 100644 index 0000000000..ed16f54e8a --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Angle.svg @@ -0,0 +1,395 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Center.svg b/src/Mod/Draft/Resources/icons/Snap_Center.svg new file mode 100644 index 0000000000..2471899893 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Center.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Endpoint.svg b/src/Mod/Draft/Resources/icons/Snap_Endpoint.svg new file mode 100644 index 0000000000..c2646f3bbb --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Endpoint.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Extension.svg b/src/Mod/Draft/Resources/icons/Snap_Extension.svg new file mode 100644 index 0000000000..3614773f8f --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Extension.svg @@ -0,0 +1,306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Grid.svg b/src/Mod/Draft/Resources/icons/Snap_Grid.svg new file mode 100644 index 0000000000..ad29fdc4f4 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Grid.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Intersection.svg b/src/Mod/Draft/Resources/icons/Snap_Intersection.svg new file mode 100644 index 0000000000..2f14be47dc --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Intersection.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Lock.svg b/src/Mod/Draft/Resources/icons/Snap_Lock.svg new file mode 100644 index 0000000000..a5fbc85b31 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Lock.svg @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Midpoint.svg b/src/Mod/Draft/Resources/icons/Snap_Midpoint.svg new file mode 100644 index 0000000000..ce2b5e7440 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Midpoint.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Near.svg b/src/Mod/Draft/Resources/icons/Snap_Near.svg new file mode 100644 index 0000000000..a2389050ed --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Near.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Ortho.svg b/src/Mod/Draft/Resources/icons/Snap_Ortho.svg new file mode 100644 index 0000000000..14ca56c127 --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Ortho.svg @@ -0,0 +1,237 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Parallel.svg b/src/Mod/Draft/Resources/icons/Snap_Parallel.svg new file mode 100644 index 0000000000..ab186c586b --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Parallel.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/icons/Snap_Perpendicular.svg b/src/Mod/Draft/Resources/icons/Snap_Perpendicular.svg new file mode 100644 index 0000000000..8dc363effe --- /dev/null +++ b/src/Mod/Draft/Resources/icons/Snap_Perpendicular.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/patterns/concrete.svg b/src/Mod/Draft/Resources/patterns/concrete.svg index 8c2fd6c616..2aa5e9565e 100644 --- a/src/Mod/Draft/Resources/patterns/concrete.svg +++ b/src/Mod/Draft/Resources/patterns/concrete.svg @@ -11,102 +11,22 @@ style="fill:none; stroke:#000000; stroke-width:.5" transform="scale(.01)" id="g3401"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/src/Mod/Draft/Resources/ui/userprefs-base.ui b/src/Mod/Draft/Resources/ui/userprefs-base.ui index 320d916725..ebf2bdbd97 100755 --- a/src/Mod/Draft/Resources/ui/userprefs-base.ui +++ b/src/Mod/Draft/Resources/ui/userprefs-base.ui @@ -7,7 +7,7 @@ 0 0 590 - 629 + 632 @@ -469,7 +469,7 @@ Snap maximum - true + false maxSnap @@ -494,6 +494,9 @@ + + false + Maximum number of edges to be considered for snapping @@ -504,6 +507,9 @@ + + false + 999 @@ -520,6 +526,62 @@ + + + + + + If checked, the Snap toolbar will be shown whenever you use snapping + + + Show Draft Snap toolbar + + + true + + + showSnapBar + + + Mod/Draft + + + + + + + Hide Draft snap toolbar after use + + + hideSnapBar + + + Mod/Draft + + + + + + + + + + + if checked, a widget indicating the current working plane orientation appears during drawing operations + + + Show Working Plane tracker + + + showPlaneTracker + + + Mod/Draft + + + + + @@ -592,7 +654,7 @@ Use grid - true + false grid @@ -615,8 +677,30 @@ + + + + false + + + If checked, the Draft grid will always be visible when the Draft workbench is active. Otherwise only when using a command + + + Always show + + + alwaysShowGrid + + + Mod/Draft + + + + + false + Grid spacing @@ -624,9 +708,18 @@ + + false + The spacing between each grid line + + 4 + + + 9999.989999999999782 + 1.000000000000000 @@ -640,6 +733,9 @@ + + false + Main lines every @@ -647,6 +743,9 @@ + + false + Mainlines will be drawn thicker. Specify here how many squares between mainlines. @@ -794,19 +893,6 @@ Values with differences below this value will be treated as same. - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -829,17 +915,6 @@ Values with differences below this value will be treated as same. - - - - - - - - Default text font - - - @@ -853,6 +928,13 @@ Values with differences below this value will be treated as same. + + + + Default text font + + + @@ -1141,12 +1223,12 @@ such as "Arial:Bold" setEnabled(bool) - 103 - 373 + 92 + 379 - 347 - 374 + 417 + 381 @@ -1173,12 +1255,12 @@ such as "Arial:Bold" setEnabled(bool) - 49 - 275 + 67 + 270 - 550 - 277 + 571 + 272 @@ -1189,12 +1271,12 @@ such as "Arial:Bold" setEnabled(bool) - 44 - 275 + 62 + 270 - 405 - 283 + 516 + 272 @@ -1209,8 +1291,8 @@ such as "Arial:Bold" 365 - 163 - 369 + 354 + 381 @@ -1225,8 +1307,40 @@ such as "Arial:Bold" 367 - 393 - 368 + 516 + 381 + + + + + gui::prefcheckbox_7 + clicked(bool) + gui::prefcheckbox_9 + setEnabled(bool) + + + 158 + 290 + + + 400 + 293 + + + + + gui::prefcheckbox_2 + clicked(bool) + gui::prefcheckbox_10 + setEnabled(bool) + + + 72 + 375 + + + 226 + 373 diff --git a/src/Mod/Draft/Resources/ui/userprefs-import.ui b/src/Mod/Draft/Resources/ui/userprefs-import.ui index 09d5ee1c21..a14084d3b3 100755 --- a/src/Mod/Draft/Resources/ui/userprefs-import.ui +++ b/src/Mod/Draft/Resources/ui/userprefs-import.ui @@ -320,6 +320,26 @@ If color mapping is choosed, you must choose a color mapping file containing a t + + + + + + If this is checked, when polylines have a width defined, they will be rendered as closed wires with the correct width + + + Render polylines with width + + + renderPolylineWidth + + + Mod/Draft + + + + + diff --git a/src/Mod/Draft/WorkingPlane.py b/src/Mod/Draft/WorkingPlane.py index 160df966e6..6c1d6066b9 100644 --- a/src/Mod/Draft/WorkingPlane.py +++ b/src/Mod/Draft/WorkingPlane.py @@ -22,9 +22,8 @@ #*************************************************************************** -import FreeCAD, FreeCADGui, math +import FreeCAD, FreeCADGui, math, DraftVecUtils from FreeCAD import Vector -from draftlibs import fcvec __title__="FreeCAD Working Plane utility" __author__ = "Ken Cline" @@ -51,7 +50,7 @@ class plane: self.stored = None def __repr__(self): - return "Workplane x="+str(fcvec.rounded(self.u))+" y="+str(fcvec.rounded(self.v))+" z="+str(fcvec.rounded(self.axis)) + return "Workplane x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis)) def offsetToPoint(self, p, direction=None): ''' @@ -87,8 +86,29 @@ class plane: def projectPoint(self, p, direction=None): '''project point onto plane, default direction is orthogonal''' - if not direction: direction = self.axis + if not direction: + direction = self.axis + lp = self.getLocalCoords(p) + gp = self.getGlobalCoords(Vector(lp.x,lp.y,0)) + a = direction.getAngle(gp.sub(p)) + if a > math.pi/2: + direction = DraftVecUtils.neg(direction) + a = math.pi - a + ld = self.getLocalRot(direction) + gd = self.getGlobalRot(Vector(ld.x,ld.y,0)) + hyp = abs(math.tan(a) * lp.z) + return gp.add(DraftVecUtils.scaleTo(gd,hyp)) + + def projectPointOld(self, p, direction=None): + '''project point onto plane, default direction is orthogonal. Obsolete''' + if not direction: + direction = self.axis t = Vector(direction) + #t.normalize() + a = round(t.getAngle(self.axis),DraftVecUtils.precision()) + pp = round((math.pi)/2,DraftVecUtils.precision()) + if a == pp: + return p t.multiply(self.offsetToPoint(p, direction)) return p.add(t) @@ -96,10 +116,10 @@ class plane: self.doc = FreeCAD.ActiveDocument self.axis = axis; self.axis.normalize() - if (fcvec.equals(axis, Vector(1,0,0))): + if (DraftVecUtils.equals(axis, Vector(1,0,0))): self.u = Vector(0,1,0) self.v = Vector(0,0,1) - elif (fcvec.equals(axis, Vector(-1,0,0))): + elif (DraftVecUtils.equals(axis, Vector(-1,0,0))): self.u = Vector(0,-1,0) self.v = Vector(0,0,1) elif upvec: @@ -109,12 +129,12 @@ class plane: else: self.v = axis.cross(Vector(1,0,0)) self.v.normalize() - self.u = fcvec.rotate(self.v, -math.pi/2, self.axis) + self.u = DraftVecUtils.rotate(self.v, -math.pi/2, self.axis) offsetVector = Vector(axis); offsetVector.multiply(offset) self.position = point.add(offsetVector) self.weak = False # FreeCAD.Console.PrintMessage("(position = " + str(self.position) + ")\n") - # FreeCAD.Console.PrintMessage("Current workplane: x="+str(fcvec.rounded(self.u))+" y="+str(fcvec.rounded(self.v))+" z="+str(fcvec.rounded(self.axis))+"\n") + # FreeCAD.Console.PrintMessage("Current workplane: x="+str(DraftVecUtils.rounded(self.u))+" y="+str(DraftVecUtils.rounded(self.v))+" z="+str(DraftVecUtils.rounded(self.axis))+"\n") def alignToCurve(self, shape, offset): if shape.ShapeType == 'Edge': @@ -162,7 +182,7 @@ class plane: def getRotation(self): "returns a placement describing the working plane orientation ONLY" - m = fcvec.getPlaneRotation(self.u,self.v,self.axis) + m = DraftVecUtils.getPlaneRotation(self.u,self.v,self.axis) return FreeCAD.Placement(m) def getPlacement(self): @@ -174,6 +194,13 @@ class plane: 0.0,0.0,0.0,1.0) return FreeCAD.Placement(m) + def setFromPlacement(self,pl): + "sets the working plane from a placement (rotaton ONLY)" + rot = FreeCAD.Placement(pl).Rotation + self.u = rot.multVec(FreeCAD.Vector(1,0,0)) + self.v = rot.multVec(FreeCAD.Vector(0,1,0)) + self.axis = rot.multVec(FreeCAD.Vector(0,0,1)) + def save(self): "stores the current plane state" self.stored = [self.u,self.v,self.axis,self.position,self.weak] @@ -190,15 +217,16 @@ class plane: def getLocalCoords(self,point): "returns the coordinates of a given point on the working plane" - xv = fcvec.project(point,self.u) + pt = point.sub(self.position) + xv = DraftVecUtils.project(pt,self.u) x = xv.Length if xv.getAngle(self.u) > 1: x = -x - yv = fcvec.project(point,self.v) + yv = DraftVecUtils.project(pt,self.v) y = yv.Length if yv.getAngle(self.v) > 1: y = -y - zv = fcvec.project(point,self.axis) + zv = DraftVecUtils.project(pt,self.axis) z = zv.Length if zv.getAngle(self.axis) > 1: z = -z @@ -206,19 +234,44 @@ class plane: def getGlobalCoords(self,point): "returns the global coordinates of the given point, taken relatively to this working plane" - vx = fcvec.scale(self.u,point.x) - vy = fcvec.scale(self.v,point.y) - vz = fcvec.scale(self.axis,point.z) - return (vx.add(vy)).add(vz) + vx = DraftVecUtils.scale(self.u,point.x) + vy = DraftVecUtils.scale(self.v,point.y) + vz = DraftVecUtils.scale(self.axis,point.z) + pt = (vx.add(vy)).add(vz) + return pt.add(self.position) + def getLocalRot(self,point): + "Same as getLocalCoords, but discards the WP position" + xv = DraftVecUtils.project(point,self.u) + x = xv.Length + if xv.getAngle(self.u) > 1: + x = -x + yv = DraftVecUtils.project(point,self.v) + y = yv.Length + if yv.getAngle(self.v) > 1: + y = -y + zv = DraftVecUtils.project(point,self.axis) + z = zv.Length + if zv.getAngle(self.axis) > 1: + z = -z + return Vector(x,y,z) + + def getGlobalRot(self,point): + "Same as getGlobalCoords, but discards the WP position" + vx = DraftVecUtils.scale(self.u,point.x) + vy = DraftVecUtils.scale(self.v,point.y) + vz = DraftVecUtils.scale(self.axis,point.z) + pt = (vx.add(vy)).add(vz) + return pt + def getClosestAxis(self,point): "returns which of the workingplane axes is closest from the given vector" ax = point.getAngle(self.u) ay = point.getAngle(self.v) az = point.getAngle(self.axis) - bx = point.getAngle(fcvec.neg(self.u)) - by = point.getAngle(fcvec.neg(self.v)) - bz = point.getAngle(fcvec.neg(self.axis)) + bx = point.getAngle(DraftVecUtils.neg(self.u)) + by = point.getAngle(DraftVecUtils.neg(self.v)) + bz = point.getAngle(DraftVecUtils.neg(self.axis)) b = min(ax,ay,az,bx,by,bz) if b in [ax,bx]: return "x" diff --git a/src/Mod/Draft/importAirfoilDAT.py b/src/Mod/Draft/importAirfoilDAT.py index 8815ee9a32..4b0d681622 100644 --- a/src/Mod/Draft/importAirfoilDAT.py +++ b/src/Mod/Draft/importAirfoilDAT.py @@ -28,7 +28,9 @@ import re, FreeCAD, FreeCADGui, Part, cProfile, os, string from FreeCAD import Vector, Base from Draft import * -pythonopen = open +if open.__module__ == '__builtin__': + pythonopen = open + useDraftWire = True def decodeName(name): @@ -53,10 +55,10 @@ def open(filename): def insert(filename,docname): "called when freecad imports a file" groupname = os.path.splitext(os.path.basename(filename))[0] - try: - doc=FreeCAD.getDocument(docname) - except: - doc=FreeCAD.newDocument(docname) + try: + doc=FreeCAD.getDocument(docname) + except: + doc=FreeCAD.newDocument(docname) importgroup = doc.addObject("App::DocumentObjectGroup",groupname) importgroup.Label = decodeName(groupname) process(doc,filename) diff --git a/src/Mod/Draft/importDXF.py b/src/Mod/Draft/importDXF.py index 234da7d887..ba8fa2909d 100644 --- a/src/Mod/Draft/importDXF.py +++ b/src/Mod/Draft/importDXF.py @@ -3,7 +3,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (GPL) * @@ -24,7 +24,7 @@ #*************************************************************************** __title__="FreeCAD Draft Workbench - DXF importer/exporter" -__author__ = "Yorik van Havre " +__author__ = "Yorik van Havre " __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"] ''' @@ -40,8 +40,8 @@ lines, polylines, lwpolylines, circles, arcs, texts, colors,layers (from groups) ''' -import FreeCAD, os, Part, math, re, string, Mesh, Draft -from draftlibs import fcvec, dxfColorMap, dxfLibrary, fcgeo +import FreeCAD, os, Part, math, re, string, Mesh, Draft, DraftVecUtils, DraftGeomUtils +from draftlibs import dxfColorMap, dxfLibrary from draftlibs.dxfReader import readDXF from Draft import _Dimension, _ViewProviderDimension from FreeCAD import Vector @@ -52,7 +52,8 @@ else: gui = True try: draftui = FreeCADGui.draftToolBar except: draftui = None -pythonopen = open # to distinguish python built-in open function from the one declared here +if open.__module__ == '__builtin__': + pythonopen = open # to distinguish python built-in open function from the one declared here def prec(): "returns the current Draft precision level" @@ -133,10 +134,10 @@ def calcBulge(v1,bulge,v2): ''' chord = v2.sub(v1) sagitta = (bulge * chord.Length)/2 - startpoint = v1.add(fcvec.scale(chord,0.5)) + startpoint = v1.add(DraftVecUtils.scale(chord,0.5)) perp = chord.cross(Vector(0,0,1)) - if not fcvec.isNull(perp): perp.normalize() - endpoint = fcvec.scale(perp,sagitta) + if not DraftVecUtils.isNull(perp): perp.normalize() + endpoint = DraftVecUtils.scale(perp,sagitta) return startpoint.add(endpoint) def getGroup(ob,exportList): @@ -201,6 +202,7 @@ class fcformat: self.makeBlocks = params.GetBool("groupLayers") self.stdSize = params.GetBool("dxfStdSize") self.importDxfHatches = params.GetBool("importDxfHatches") + self.renderPolylineWidth = params.GetBool("renderPolylineWidth") bparams = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View") if self.paramstyle > 1: @@ -217,7 +219,7 @@ class fcformat: v1 = FreeCAD.Vector(r1,g1,b1) v2 = FreeCAD.Vector(r2,g2,b2) v = v2.sub(v1) - v = fcvec.scale(v,0.5) + v = DraftVecUtils.scale(v,0.5) cv = v1.add(v) else: c1 = bparams.GetUnsigned("BackgroundColor") @@ -347,7 +349,7 @@ def drawLine(line,shapemode=False): if (len(line.points) > 1): v1=vec(line.points[0]) v2=vec(line.points[1]) - if not fcvec.equals(v1,v2): + if not DraftVecUtils.equals(v1,v2): try: if (fmt.paramstyle >= 4) and (not shapemode): return Draft.makeWire([v1,v2]) @@ -369,11 +371,11 @@ def drawPolyline(polyline,shapemode=False,num=None): v1 = vec(p1) v2 = vec(p2) verts.append(v1) - if not fcvec.equals(v1,v2): + if not DraftVecUtils.equals(v1,v2): if polyline.points[p].bulge: curves = True cv = calcBulge(v1,polyline.points[p].bulge,v2) - if fcvec.isColinear([v1,cv,v2]): + if DraftVecUtils.isColinear([v1,cv,v2]): try: edges.append(Part.Line(v1,v2).toShape()) except: warn(polyline,num) else: @@ -389,8 +391,8 @@ def drawPolyline(polyline,shapemode=False,num=None): v1 = vec(p1) v2 = vec(p2) cv = calcBulge(v1,polyline.points[-1].bulge,v2) - if not fcvec.equals(v1,v2): - if fcvec.isColinear([v1,cv,v2]): + if not DraftVecUtils.equals(v1,v2): + if DraftVecUtils.isColinear([v1,cv,v2]): try: edges.append(Part.Line(v1,v2).toShape()) except: @@ -402,7 +404,21 @@ def drawPolyline(polyline,shapemode=False,num=None): warn(polyline,num) if edges: try: - if (fmt.paramstyle >= 4) and (not curves) and (not shapemode): + width = rawValue(polyline,43) + if width and fmt.renderPolylineWidth: + w = Part.Wire(edges) + w1 = w.makeOffset(width/2) + if polyline.closed: + w2 = w.makeOffset(-width/2) + w1 = Part.Face(w1) + w2 = Part.Face(w2) + if w1.BoundBox.DiagonalLength > w2.BoundBox.DiagonalLength: + return w1.cut(w2) + else: + return w2.cut(w1) + else: + return Part.Face(w1) + elif (fmt.paramstyle >= 4) and (not curves) and (not shapemode): ob = Draft.makeWire(verts) ob.Closed = polyline.closed return ob @@ -525,7 +541,7 @@ def drawSolid(solid): if p4x != None: p4 = FreeCAD.Vector(p4x,p4y,p4z) if p4 and (p4 != p3) and (p4 != p2) and (p4 != p1): try: - return Part.Face(Part.makePolygon([p1,p2,p3,p4,p1])) + return Part.Face(Part.makePolygon([p1,p2,p4,p3,p1])) except: warn(solid) else: @@ -721,11 +737,11 @@ def addText(text,attrib=False): rz = rawValue(text,31) if rx or ry or rz: xv = Vector(rx,ry,rz) - if not fcvec.isNull(xv): - ax = fcvec.neg(xv.cross(Vector(1,0,0))) - if fcvec.isNull(ax): + if not DraftVecUtils.isNull(xv): + ax = DraftVecUtils.neg(xv.cross(Vector(1,0,0))) + if DraftVecUtils.isNull(ax): ax = Vector(0,0,1) - ang = -math.degrees(fcvec.angle(xv,Vector(1,0,0),ax)) + ang = -math.degrees(DraftVecUtils.angle(xv,Vector(1,0,0),ax)) Draft.rotate(newob,ang,axis=ax) elif hasattr(text,"rotation"): if text.rotation: @@ -884,7 +900,7 @@ def processdxf(document,filename): edges = [] for s in shapes: edges.extend(s.Edges) - shapes = fcgeo.findWires(edges) + shapes = DraftGeomUtils.findWires(edges) for s in shapes: newob = addObject(s) @@ -1197,13 +1213,13 @@ def getArcData(edge): # check the midpoint seems more reliable ve1 = edge.Vertexes[0].Point ve2 = edge.Vertexes[-1].Point - ang1 = -math.degrees(fcvec.angle(ve1.sub(ce))) - ang2 = -math.degrees(fcvec.angle(ve2.sub(ce))) - ve3 = fcgeo.findMidpoint(edge) - ang3 = -math.degrees(fcvec.angle(ve3.sub(ce))) + ang1 = -math.degrees(DraftVecUtils.angle(ve1.sub(ce))) + ang2 = -math.degrees(DraftVecUtils.angle(ve2.sub(ce))) + ve3 = DraftGeomUtils.findMidpoint(edge) + ang3 = -math.degrees(DraftVecUtils.angle(ve3.sub(ce))) if (ang3 < ang1) and (ang2 < ang3): ang1, ang2 = ang2, ang1 - return fcvec.tup(ce), radius, ang1, ang2 + return DraftVecUtils.tup(ce), radius, ang1, ang2 def getSplineSegs(edge): "returns an array of vectors from a bSpline edge" @@ -1227,16 +1243,18 @@ def getSplineSegs(edge): def getWire(wire,nospline=False): "returns an array of dxf-ready points and bulges from a wire" - edges = fcgeo.sortEdges(wire.Edges) + edges = DraftGeomUtils.sortEdges(wire.Edges) points = [] for edge in edges: v1 = edge.Vertexes[0].Point - if (isinstance(edge.Curve,Part.Circle)): - mp = fcgeo.findMidpoint(edge) + if len(edge.Vertexes) < 2: + points.append((v1.x,v1.y,v1.z,None,None,0.0)) + elif (isinstance(edge.Curve,Part.Circle)): + mp = DraftGeomUtils.findMidpoint(edge) v2 = edge.Vertexes[-1].Point c = edge.Curve.Center - angle = abs(fcvec.angle(v1.sub(c),v2.sub(c))) - # if (fcvec.angle(v2.sub(c)) < fcvec.angle(v1.sub(c))): + angle = abs(DraftVecUtils.angle(v1.sub(c),v2.sub(c))) + # if (DraftVecUtils.angle(v2.sub(c)) < DraftVecUtils.angle(v1.sub(c))): # angle = -angle # polyline bulge -> negative makes the arc go clockwise bul = math.tan(angle/4) @@ -1250,17 +1268,15 @@ def getWire(wire,nospline=False): bul = -bul points.append((v1.x,v1.y,v1.z,None,None,bul)) elif (isinstance(edge.Curve,Part.BSplineCurve)) and (not nospline): - bul = 0.0 spline = getSplineSegs(edge) spline.pop() for p in spline: - points.append((p.x,p.y,p.z,None,None,bul)) + points.append((p.x,p.y,p.z,None,None,0.0)) else: - bul = 0.0 - points.append((v1.x,v1.y,v1.z,None,None,bul)) - if not fcgeo.isReallyClosed(wire): + points.append((v1.x,v1.y,v1.z,None,None,0.0)) + if not DraftGeomUtils.isReallyClosed(wire): v = edges[-1].Vertexes[-1].Point - points.append(fcvec.tup(v)) + points.append(DraftVecUtils.tup(v)) # print "wire verts: ",points return points @@ -1288,7 +1304,7 @@ def writeShape(ob,dxfobject,nospline=False): layer=getGroup(ob,exportList))) else: dxfobject.append(dxfLibrary.PolyLine(getWire(wire,nospline), [0.0,0.0,0.0], - int(fcgeo.isReallyClosed(wire)), color=getACI(ob), + int(DraftGeomUtils.isReallyClosed(wire)), color=getACI(ob), layer=getGroup(ob,exportList))) if len(processededges) < len(ob.Shape.Edges): # lone edges loneedges = [] @@ -1317,7 +1333,7 @@ def writeShape(ob,dxfobject,nospline=False): else: # anything else is treated as lines ve1=edge.Vertexes[0].Point ve2=edge.Vertexes[1].Point - dxfobject.append(dxfLibrary.Line([fcvec.tup(ve1), fcvec.tup(ve2)], + dxfobject.append(dxfLibrary.Line([DraftVecUtils.tup(ve1), DraftVecUtils.tup(ve2)], color=getACI(ob), layer=getGroup(ob,exportList))) @@ -1376,7 +1392,7 @@ def export(objectslist,filename,nospline=False): # temporary - as dxfLibrary doesn't support mtexts well, we use several single-line texts # well, anyway, at the moment, Draft only writes single-line texts, so... for text in ob.LabelText: - point = fcvec.tup(FreeCAD.Vector(ob.Position.x, + point = DraftVecUtils.tup(FreeCAD.Vector(ob.Position.x, ob.Position.y-ob.LabelText.index(text), ob.Position.z)) if gui: height = float(ob.ViewObject.FontSize) @@ -1387,14 +1403,14 @@ def export(objectslist,filename,nospline=False): layer=getGroup(ob,exportList))) elif 'Dimline' in ob.PropertiesList: - p1 = fcvec.tup(ob.Start) - p2 = fcvec.tup(ob.End) + p1 = DraftVecUtils.tup(ob.Start) + p2 = DraftVecUtils.tup(ob.End) base = Part.Line(ob.Start,ob.End).toShape() - proj = fcgeo.findDistance(ob.Dimline,base) + proj = DraftGeomUtils.findDistance(ob.Dimline,base) if not proj: - pbase = fcvec.tup(ob.End) + pbase = DraftVecUtils.tup(ob.End) else: - pbase = fcvec.tup(ob.End.add(fcvec.neg(proj))) + pbase = DraftVecUtils.tup(ob.End.add(DraftVecUtils.neg(proj))) dxf.append(dxfLibrary.Dimension(pbase,p1,p2,color=getACI(ob), layer=getGroup(ob,exportList))) diff --git a/src/Mod/Draft/importOCA.py b/src/Mod/Draft/importOCA.py index 18220fa53b..79e769aa2f 100644 --- a/src/Mod/Draft/importOCA.py +++ b/src/Mod/Draft/importOCA.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License (GPL) * @@ -22,22 +22,23 @@ #*************************************************************************** __title__="FreeCAD Draft Workbench - OCA importer/exporter" -__author__ = "Yorik van Havre " +__author__ = "Yorik van Havre " __url__ = ["http://yorik.orgfree.com","http://free-cad.sourceforge.net"] ''' This script imports OCA/gcad files into FreeCAD. ''' -import FreeCAD, os, Part, math -from draftlibs import fcvec, fcgeo +import FreeCAD, os, Part, math, DraftVecUtils, DraftGeomUtils from FreeCAD import Vector try: import FreeCADGui except ValueError: gui = False else: gui = True -pythonopen = open +if open.__module__ == '__builtin__': + pythonopen = open + params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") def getpoint(data): @@ -54,7 +55,7 @@ def getpoint(data): if (data[1][0] == "R"): return objects[data[0]].add(objects[data[1]]) elif (data[1][0] == "C"): - return fcgeo.findProjection(objects[data[0]],objects[data[1]]) + return DraftGeomUtils.findProjection(objects[data[0]],objects[data[1]]) elif (data[0][0] == "C"): if objects[data[0]]: p1 = objects[data[0]].Curve.Position @@ -63,7 +64,7 @@ def getpoint(data): else: if (data[1][0] == "L"): l = objects[data[1]] - return p1.add(fcgeo.vec(l)) + return p1.add(DraftGeomUtils.vec(l)) def getarea(data): "turns an OCA area definition into a FreeCAD Part Wire" @@ -109,7 +110,7 @@ def getarc(data): c = Part.Circle() c.Center = verts[0] if rad: c.Radius = rad - else: c.Radius = fcvec.new(verts[0],verts[1]).Length + else: c.Radius = DraftVecUtils.new(verts[0],verts[1]).Length elif (data[0][0] == "L"): # 2-lines circle lines = [] @@ -119,7 +120,7 @@ def getarc(data): rad = float(data[p+1]) elif (data[p][0] == "L"): lines.append(objects[data[p]]) - circles = fcgeo.circleFrom2LinesRadius(lines[0],lines[1],rad) + circles = DraftGeomUtils.circleFrom2LinesRadius(lines[0],lines[1],rad) if circles: c = circles[0] if c: return c.toShape() @@ -266,7 +267,7 @@ def export(exportList,filename): oca.write("C"+str(count)+"=ARC ") oca.write(writepoint(e.Vertexes[0].Point)) oca.write(" ") - oca.write(writepoint(fcgeo.findMidpoint(e))) + oca.write(writepoint(DraftGeomUtils.findMidpoint(e))) oca.write(" ") oca.write(writepoint(e.Vertexes[-1].Point)) else: diff --git a/src/Mod/Draft/importSVG.py b/src/Mod/Draft/importSVG.py index b2f7377103..099041d0ad 100644 --- a/src/Mod/Draft/importSVG.py +++ b/src/Mod/Draft/importSVG.py @@ -1,7 +1,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -38,8 +38,7 @@ currently unsupported: use, image # implement inherting fill style from group # handle relative units -import xml.sax, string, FreeCAD, os, math, re, Draft -from draftlibs import fcvec +import xml.sax, string, FreeCAD, os, math, re, Draft, DraftVecUtils, DraftGeomUtils from FreeCAD import Vector try: import FreeCADGui @@ -48,7 +47,8 @@ else: gui = True try: draftui = FreeCADGui.draftToolBar except: draftui = None -pythonopen = open +if open.__module__ == '__builtin__': + pythonopen = open svgcolors = { 'Pink': (255, 192, 203), @@ -216,7 +216,7 @@ def getcolor(color): b = float(v[2]/255.0) return (r,g,b,0.0) -def getsize(length,mode='discard',base=None): +def getsize(length,mode='discard',base=1): """parses length values containing number and unit with mode 'discard': extracts a number from the given string (removes unit suffixes) with mode 'tuple': return number and unit as a tuple @@ -253,13 +253,15 @@ def getsize(length,mode='discard',base=None): return float(number) elif mode == 'tuple': return float(number),unit + elif mode == 'isabsolute': + return unit in ('mm','cm','in','px','pt') elif mode == 'mm': return float(number)*tomm[unit] elif mode == 'css': if unit != '%': return float(number)*topx[unit] else: - return float(number)*(base or 1) + return float(number)*base def makewire(path,checkclosed=False,donttry=False): '''try to make a wire out of the list of edges. If the 'Wire' functions fails or the wire is not @@ -267,7 +269,8 @@ def makewire(path,checkclosed=False,donttry=False): #ToDo Do not catch all exceptions if not donttry: try: - sh = Part.Wire(path) + sh = Part.Wire(DraftGeomUtils.sortEdges(path)) + #sh = Part.Wire(path) isok = (not checkclosed) or sh.isClosed() except:# BRep_API:command not done isok = False @@ -329,13 +332,13 @@ def arcend2center(lastvec,currentvec,rx,ry,xrotation=0.0,correction=False): m2=FreeCAD.Matrix() m2.rotateZ(xrotation) centeroff = currentvec.add(lastvec) - centeroff = fcvec.scale(centeroff,.5) + centeroff = DraftVecUtils.scale(centeroff,.5) vcenter = m2.multiply(vcx1).add(centeroff) # Step3 F.6.5.3 #angle1 = Vector(1,0,0).getAngle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5 #angledelta = Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0).getAngle(Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6 #we need the right sign for the angle - angle1 = fcvec.angle(Vector(1,0,0),Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5 - angledelta = fcvec.angle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0),Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6 + angle1 = DraftVecUtils.angle(Vector(1,0,0),Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0)) # F.6.5.5 + angledelta = DraftVecUtils.angle(Vector((v1.x-vcx1.x)/rx,(v1.y-vcx1.y)/ry,0),Vector((-v1.x-vcx1.x)/rx,(-v1.y-vcx1.y)/ry,0)) # F.6.5.6 results.append((vcenter,angle1,angledelta)) return results,(rx,ry) @@ -428,23 +431,39 @@ class svgHandler(xml.sax.ContentHandler): if name == 'svg': m=FreeCAD.Matrix() if 'width' in data and 'height' in data and \ - 'viewBox' in data: - x0,y0,x1,y1=[float(n) for n in data['viewBox']] - vbw = x1-x0 - vbh = y1-y0 + 'viewBox' in data and\ + (getsize(attrs.getValue('width'),'isabsolute') and\ + getsize(attrs.getValue('height'),'isabsolute') or\ + len(self.grouptransform)!=0): + vbw=float(data['viewBox'][2]) + vbh=float(data['viewBox'][3]) + w=attrs.getValue('width') + h=attrs.getValue('height') self.viewbox=(vbw,vbh) - abw = getsize(attrs.getValue('width'),'mm') - abh = getsize(attrs.getValue('height'),'mm') + if len(self.grouptransform)==0: + unitmode='mm' + else: #nested svg element + unitmode='css' + abw = getsize(w,unitmode) + abh = getsize(h,unitmode) sx=abw/vbw sy=abh/vbh - m.scale(Vector(sx,sy,1)) - if round(sx/sy,5) != 1: - FreeCAD.Console.PrintWarning('Scaling Factors do not match!!!\n') - - #FreeCAD.Console.PrintMessage('attrs: %s %s\n'%(attrs.getValue('width'),attrs.getValue('height'))) - #FreeCAD.Console.PrintMessage('vb: %f %f %f %f\n'%(x0,y0,x1,y1)) - #FreeCAD.Console.PrintMessage('absolute: %f %f\n'%(abw,abh)) - else: + preservearstr=data.get('preserveAspectRatio',\ + '').lower() + uniformscaling = round(sx/sy,5) == 1 + if uniformscaling: + m.scale(Vector(sx,sy,1)) + else: + FreeCAD.Console.PrintWarning('Scaling Factors do not match!!!\n') + if preservearstr.startswith('none'): + m.scale(Vector(sx,sy,1)) + else: #preserve the aspect ratio + if preservearstr.endswith('slice'): + sxy=max(sx,sy) + else: + sxy=min(sx,sy) + m.scale(Vector(sxy,sxy,1)) + elif len(self.grouptransform)==0: #fallback to 90 dpi m.scale(Vector(25.4/90.0,25.4/90.0,1)) self.grouptransform.append(m) @@ -504,9 +523,11 @@ class svgHandler(xml.sax.ContentHandler): self.lastdim = obj data['d']=[] pathcommandsre=re.compile('\s*?([mMlLhHvVaAcCqQsStTzZ])\s*?([^mMlLhHvVaAcCqQsStTzZ]*)\s*?',re.DOTALL) + pointsre=re.compile('([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)',re.DOTALL) for d,pointsstr in pathcommandsre.findall(' '.join(data['d'])): relative = d.islower() - pointlist = [float(str1) for str1 in pointsstr.replace(',',' ').split()] + pointlist = [float(number) for number,exponent in pointsre.findall(pointsstr.replace(',',' '))] + if (d == "M" or d == "m"): x = pointlist.pop(0) y = pointlist.pop(0) @@ -535,7 +556,7 @@ class svgHandler(xml.sax.ContentHandler): currentvec = lastvec.add(Vector(x,-y,0)) else: currentvec = Vector(x,-y,0) - if not fcvec.equals(lastvec,currentvec): + if not DraftVecUtils.equals(lastvec,currentvec): seg = Part.Line(lastvec,currentvec).toShape() FreeCAD.Console.PrintMessage("line %s %s\n" %(lastvec,currentvec)) lastvec = currentvec @@ -576,15 +597,15 @@ class svgHandler(xml.sax.ContentHandler): # here is a better way to find the perpendicular if sweepflag == 1: # clockwise - perp = fcvec.rotate2D(chord,-math.pi/2) + perp = DraftVecUtils.rotate2D(chord,-math.pi/2) else: # anticlockwise - perp = fcvec.rotate2D(chord,math.pi/2) - chord = fcvec.scale(chord,.5) + perp = DraftVecUtils.rotate2D(chord,math.pi/2) + chord = DraftVecUtils.scale(chord,.5) if chord.Length > rx: a = 0 else: a = math.sqrt(rx**2-chord.Length**2) s = rx - a - perp = fcvec.scale(perp,s/perp.Length) + perp = DraftVecUtils.scale(perp,s/perp.Length) midpoint = lastvec.add(chord.add(perp)) seg = Part.Arc(lastvec,midpoint,currentvec).toShape() else:# big arc or elliptical arc @@ -653,7 +674,7 @@ class svgHandler(xml.sax.ContentHandler): currentvec = Vector(x,-y,0) pole2 = Vector(p2x,-p2y,0) - if not fcvec.equals(currentvec,lastvec): + if not DraftVecUtils.equals(currentvec,lastvec): mainv = currentvec.sub(lastvec) pole1v = lastvec.add(pole1) pole2v = currentvec.add(pole2) @@ -695,7 +716,7 @@ class svgHandler(xml.sax.ContentHandler): else: currentvec = Vector(x,-y,0) - if not fcvec.equals(currentvec,lastvec): + if not DraftVecUtils.equals(currentvec,lastvec): if True and \ pole.distanceToLine(lastvec,currentvec) < 20**(-1*(2+Draft.precision())): #print "straight segment" @@ -710,12 +731,12 @@ class svgHandler(xml.sax.ContentHandler): lastpole = ('quadratic',pole) path.append(seg) elif (d == "Z") or (d == "z"): - if not fcvec.equals(lastvec,firstvec): + if not DraftVecUtils.equals(lastvec,firstvec): seg = Part.Line(lastvec,firstvec).toShape() path.append(seg) if path: #the path should be closed by now #sh=makewire(path,True) - sh=makewire(path,donttry=True) + sh=makewire(path,donttry=False) if self.fill: sh = Part.Face(sh) sh = self.applyTrans(sh) obj = self.doc.addObject("Part::Feature",pathname) @@ -798,7 +819,7 @@ class svgHandler(xml.sax.ContentHandler): esh.append(arc.toShape()) for esh1,esh2 in zip(esh[-1:]+esh[:-1],esh): p1,p2 = esh1.Vertexes[-1].Point,esh2.Vertexes[0].Point - if not fcvec.equals(p1,p2): + if not DraftVecUtils.equals(p1,p2): edges.append(Part.Line(esh1.Vertexes[-1].Point,esh2.Vertexes[0].Point).toShape()) #straight segments edges.append(esh2) # elliptical segments sh = Part.Wire(edges) @@ -836,7 +857,7 @@ class svgHandler(xml.sax.ContentHandler): points=points+points[:2] # emulate closepath for svgx,svgy in zip(points[2::2],points[3::2]): currentvec = Vector(svgx,-svgy,0) - if not fcvec.equals(lastvec,currentvec): + if not DraftVecUtils.equals(lastvec,currentvec): seg = Part.Line(lastvec,currentvec).toShape() #print "polyline seg ",lastvec,currentvec lastvec = currentvec diff --git a/src/Mod/Draft/macros.py b/src/Mod/Draft/macros.py index a2668dad8c..2b106d19fc 100644 --- a/src/Mod/Draft/macros.py +++ b/src/Mod/Draft/macros.py @@ -1,6 +1,6 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Mod/Drawing/App/AppDrawing.cpp b/src/Mod/Drawing/App/AppDrawing.cpp index 86aafb4203..016abf81b6 100644 --- a/src/Mod/Drawing/App/AppDrawing.cpp +++ b/src/Mod/Drawing/App/AppDrawing.cpp @@ -20,7 +20,9 @@ #include "FeaturePage.h" #include "FeatureView.h" #include "FeatureViewPart.h" +#include "FeatureViewAnnotation.h" #include "FeatureProjection.h" +#include "FeatureClip.h" #include "PageGroup.h" extern struct PyMethodDef Drawing_methods[]; @@ -57,6 +59,8 @@ void DrawingExport initDrawing() Drawing::FeatureProjection ::init(); Drawing::FeatureViewPartPython ::init(); Drawing::FeatureViewPython ::init(); + Drawing::FeatureViewAnnotation ::init(); + Drawing::FeatureClip ::init(); } } // extern "C" diff --git a/src/Mod/Drawing/App/CMakeLists.txt b/src/Mod/Drawing/App/CMakeLists.txt index 3258959f80..00710b75e0 100644 --- a/src/Mod/Drawing/App/CMakeLists.txt +++ b/src/Mod/Drawing/App/CMakeLists.txt @@ -27,6 +27,10 @@ SET(Features_SRCS FeatureView.h FeatureViewPart.cpp FeatureViewPart.h + FeatureViewAnnotation.cpp + FeatureViewAnnotation.h + FeatureClip.cpp + FeatureClip.h PageGroup.cpp PageGroup.h ) diff --git a/src/Mod/Drawing/App/FeatureClip.cpp b/src/Mod/Drawing/App/FeatureClip.cpp new file mode 100644 index 0000000000..c45229929a --- /dev/null +++ b/src/Mod/Drawing/App/FeatureClip.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre 2012 * + * * + * 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 +#include +#include +#include + +#include "FeatureClip.h" +#include "FeatureView.h" + +using namespace Drawing; +using namespace std; + + +//=========================================================================== +// FeaturePage +//=========================================================================== + +PROPERTY_SOURCE(Drawing::FeatureClip, App::DocumentObjectGroup) + +FeatureClip::FeatureClip(void) +{ + static const char *group = "Drawing view"; + App::PropertyType hidden = (App::PropertyType)(App::Prop_Hidden); + ADD_PROPERTY_TYPE(ViewResult ,(""),group,hidden,"Resulting SVG view of this clip"); + ADD_PROPERTY_TYPE(X ,(10),group,App::Prop_None ,"The left margin of the view area of this clip"); + ADD_PROPERTY_TYPE(Y ,(10),group,App::Prop_None ,"The top margin of the view area of this clip"); + ADD_PROPERTY_TYPE(Height ,(10),group,App::Prop_None ,"The height of the view area of this clip"); + ADD_PROPERTY_TYPE(Width ,(10),group,App::Prop_None ,"The width of the view area of this clip"); + ADD_PROPERTY_TYPE(ShowFrame ,(0),group,App::Prop_None,"Specifies if the clip frame appears on the page or not"); +} + +FeatureClip::~FeatureClip() +{ +} + +/// get called by the container when a Property was changed +void FeatureClip::onChanged(const App::Property* prop) +{ + App::DocumentObjectGroup::onChanged(prop); +} + +App::DocumentObjectExecReturn *FeatureClip::execute(void) +{ + ostringstream svg; + + // creating clip path + svg << "" + << "" << endl; + + // show clip frame on the page if needed + + if (ShowFrame.getValue()) { + svg << "" << endl; + } + + // create clipped group + svg << "" << endl; + + // get through the children and collect all the views + const std::vector &Grp = Group.getValues(); + for (std::vector::const_iterator It= Grp.begin();It!=Grp.end();++It) { + if ((*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId())) { + Drawing::FeatureView *View = dynamic_cast(*It); + svg << View->ViewResult.getValue() << endl; + } + } + + // closing clipped group + svg << "" << endl; + + ViewResult.setValue(svg.str().c_str()); + return App::DocumentObject::StdReturn; +} diff --git a/src/Mod/Drawing/App/FeatureClip.h b/src/Mod/Drawing/App/FeatureClip.h new file mode 100644 index 0000000000..ae1e6c0fc0 --- /dev/null +++ b/src/Mod/Drawing/App/FeatureClip.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre 2012 * + * * + * 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 _FeatureClip_h_ +#define _FeatureClip_h_ + + +#include +#include + +namespace Drawing +{ + +/** Base class of all View Features in the drawing module + */ +class DrawingExport FeatureClip: public App::DocumentObjectGroup +{ + PROPERTY_HEADER(Drawing::FeatureClip); + +public: + /// Constructor + FeatureClip(void); + virtual ~FeatureClip(); + + App::PropertyFloat X; + App::PropertyFloat Y; + App::PropertyFloat Width; + App::PropertyFloat Height; + App::PropertyBool ShowFrame; + App::PropertyString ViewResult; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "DrawingGui::ViewProviderDrawingPage"; + } + +protected: + void onChanged(const App::Property* prop); +}; + + +} //namespace Drawing + + +#endif diff --git a/src/Mod/Drawing/App/FeaturePage.cpp b/src/Mod/Drawing/App/FeaturePage.cpp index 684fe28cf8..c1730ebc4a 100644 --- a/src/Mod/Drawing/App/FeaturePage.cpp +++ b/src/Mod/Drawing/App/FeaturePage.cpp @@ -37,6 +37,7 @@ #include "FeaturePage.h" #include "FeatureView.h" +#include "FeatureClip.h" using namespace Drawing; using namespace std; @@ -124,10 +125,14 @@ App::DocumentObjectExecReturn *FeaturePage::execute(void) // get through the children and collect all the views const std::vector &Grp = Group.getValues(); for (std::vector::const_iterator It= Grp.begin();It!=Grp.end();++It) { - if ((*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId())) { + if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId()) ) { Drawing::FeatureView *View = dynamic_cast(*It); ofile << View->ViewResult.getValue(); ofile << tempendl << tempendl << tempendl; + } else if ( (*It)->getTypeId().isDerivedFrom(Drawing::FeatureClip::getClassTypeId()) ) { + Drawing::FeatureClip *Clip = dynamic_cast(*It); + ofile << Clip->ViewResult.getValue(); + ofile << tempendl << tempendl << tempendl; } } } diff --git a/src/Mod/Drawing/App/FeatureViewAnnotation.cpp b/src/Mod/Drawing/App/FeatureViewAnnotation.cpp new file mode 100644 index 0000000000..b8624c28b1 --- /dev/null +++ b/src/Mod/Drawing/App/FeatureViewAnnotation.cpp @@ -0,0 +1,102 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net) 2012 * + * * + * 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 + +#include "FeatureViewAnnotation.h" + +using namespace Drawing; +using namespace std; + + +//=========================================================================== +// FeatureViewAnnotation +//=========================================================================== + +PROPERTY_SOURCE(Drawing::FeatureViewAnnotation, Drawing::FeatureView) + + +FeatureViewAnnotation::FeatureViewAnnotation(void) +{ + static const char *vgroup = "Drawing view"; + + ADD_PROPERTY_TYPE(Text ,(""),vgroup,App::Prop_None,"The text to be displayed"); + ADD_PROPERTY_TYPE(Font ,("Sans"),vgroup,App::Prop_None,"The name of the font to use"); + ADD_PROPERTY_TYPE(TextColor,(0.0f,0.0f,0.0f),vgroup,App::Prop_None,"The color of the text"); +} + +FeatureViewAnnotation::~FeatureViewAnnotation() +{ +} + +App::DocumentObjectExecReturn *FeatureViewAnnotation::execute(void) +{ + std::stringstream result,hr,hg,hb; + const App::Color& c = TextColor.getValue(); + hr << hex << setfill('0') << setw(2) << (int)(255.0*c.r); + hg << hex << setfill('0') << setw(2) << (int)(255.0*c.g); + hb << hex << setfill('0') << setw(2) << (int)(255.0*c.b); + + result << "" << endl + << "" << endl; + + int index=0; + for (std::vector::const_iterator it = Text.getValues().begin(); it != Text.getValues().end(); ++it) { + result << "" << it->c_str() << "" << endl; + index++; + } + + result << "" << endl << "" << endl; + + // Apply the resulting fragment + ViewResult.setValue(result.str().c_str()); + + return App::DocumentObject::StdReturn; +} + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(Drawing::FeatureViewAnnotationPython, Drawing::FeatureViewAnnotation) +template<> const char* Drawing::FeatureViewAnnotationPython::getViewProviderName(void) const { + return "DrawingGui::ViewProviderDrawingView"; +} +/// @endcond + +// explicit template instantiation +template class DrawingExport FeaturePythonT; +} diff --git a/src/Mod/Drawing/App/FeatureViewAnnotation.h b/src/Mod/Drawing/App/FeatureViewAnnotation.h new file mode 100644 index 0000000000..8bd68cf406 --- /dev/null +++ b/src/Mod/Drawing/App/FeatureViewAnnotation.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (c) Yorik van Havre (yorik@uncreated.net 2012) * + * * + * 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 _FeatureViewAnnotation_h_ +#define _FeatureViewAnnotation_h_ + + +#include +#include +#include "FeatureView.h" +#include + + +namespace Drawing +{ + + +/** Base class of all View Features in the drawing module + */ +class DrawingExport FeatureViewAnnotation : public FeatureView +{ + PROPERTY_HEADER(Drawing::FeatureView); + +public: + /// Constructor + FeatureViewAnnotation(void); + virtual ~FeatureViewAnnotation(); + + App::PropertyStringList Text; + App::PropertyString Font; + App::PropertyColor TextColor; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "DrawingGui::ViewProviderDrawingView"; + } +}; + +typedef App::FeaturePythonT FeatureViewAnnotationPython; + + +} //namespace Drawing + + +#endif diff --git a/src/Mod/Drawing/App/FeatureViewPart.cpp b/src/Mod/Drawing/App/FeatureViewPart.cpp index 3d09db914a..f4f755338c 100644 --- a/src/Mod/Drawing/App/FeatureViewPart.cpp +++ b/src/Mod/Drawing/App/FeatureViewPart.cpp @@ -76,11 +76,13 @@ PROPERTY_SOURCE(Drawing::FeatureViewPart, Drawing::FeatureView) FeatureViewPart::FeatureViewPart(void) { static const char *group = "Shape view"; + static const char *vgroup = "Drawing view"; ADD_PROPERTY_TYPE(Direction ,(0,0,1.0),group,App::Prop_None,"Projection direction"); ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"Shape to view"); ADD_PROPERTY_TYPE(ShowHiddenLines ,(false),group,App::Prop_None,"Control the appearance of the dashed hidden lines"); ADD_PROPERTY_TYPE(ShowSmoothLines ,(false),group,App::Prop_None,"Control the appearance of the smooth lines"); + ADD_PROPERTY_TYPE(LineWidth,(0.35),vgroup,App::Prop_None,"The thickness of the resulting lines"); } FeatureViewPart::~FeatureViewPart() @@ -196,7 +198,7 @@ App::DocumentObjectExecReturn *FeatureViewPart::execute(void) ProjectionAlgos::SvgExtractionType type = ProjectionAlgos::Plain; if (hidden) type = (ProjectionAlgos::SvgExtractionType)(type|ProjectionAlgos::WithHidden); if (smooth) type = (ProjectionAlgos::SvgExtractionType)(type|ProjectionAlgos::WithSmooth); - result << Alg.getSVG(type, this->Scale.getValue()); + result << Alg.getSVG(type, this->LineWidth.getValue() / this->Scale.getValue()); result << "" << endl; diff --git a/src/Mod/Drawing/App/FeatureViewPart.h b/src/Mod/Drawing/App/FeatureViewPart.h index 466cad2075..68ad3551f2 100644 --- a/src/Mod/Drawing/App/FeatureViewPart.h +++ b/src/Mod/Drawing/App/FeatureViewPart.h @@ -52,6 +52,7 @@ public: App::PropertyVector Direction; App::PropertyBool ShowHiddenLines; App::PropertyBool ShowSmoothLines; + App::PropertyFloat LineWidth; /** @name methods overide Feature */ diff --git a/src/Mod/Drawing/App/Makefile.am b/src/Mod/Drawing/App/Makefile.am index 790f1ddccb..098b9b786a 100644 --- a/src/Mod/Drawing/App/Makefile.am +++ b/src/Mod/Drawing/App/Makefile.am @@ -13,6 +13,10 @@ libDrawing_la_SOURCES=\ FeatureView.h \ FeatureViewPart.cpp \ FeatureViewPart.h \ + FeatureViewAnnotation.cpp \ + FeatureViewAnnotation.h \ + FeatureClip.cpp \ + FeatureClip.h \ PageGroup.cpp \ PageGroup.h \ ProjectionAlgos.cpp \ diff --git a/src/Mod/Drawing/App/ProjectionAlgos.cpp b/src/Mod/Drawing/App/ProjectionAlgos.cpp index cb82c3e8ea..a5f8446194 100644 --- a/src/Mod/Drawing/App/ProjectionAlgos.cpp +++ b/src/Mod/Drawing/App/ProjectionAlgos.cpp @@ -153,8 +153,10 @@ std::string ProjectionAlgos::getSVG(SvgExtractionType type, float scale) { std::stringstream result; SVGOutput output; + float hfactor = 0.5f; // hidden line size factor, was 0.15f / 0.35f; + if (!H.IsNull() && (type & WithHidden)) { - float width = 0.15f/scale; + float width = hfactor * scale; BRepMesh::Mesh(H,0.1); result << "" << endl << output.exportEdges(H) << "" << endl; } if (!HO.IsNull() && (type & WithHidden)) { - float width = 0.15f/scale; + float width = hfactor * scale; BRepMesh::Mesh(HO,0.1); result << "" << endl << output.exportEdges(HO) << "" << endl; } if (!VO.IsNull()) { - float width = 0.35f/scale; + float width = scale; BRepMesh::Mesh(VO,0.1); result << "" << endl; } if (!V.IsNull()) { - float width = 0.35f/scale; + float width = scale; BRepMesh::Mesh(V,0.1); result << "" << endl; } if (!V1.IsNull() && (type & WithSmooth)) { - float width = 0.35f/scale; + float width = scale; BRepMesh::Mesh(V1,0.1); result << "" << endl; } if (!H1.IsNull() && (type & WithSmooth) && (type & WithHidden)) { - float width = 0.15f/scale; + float width = hfactor * scale; BRepMesh::Mesh(H1,0.1); result << "" << endl << output.exportEdges(H1) diff --git a/src/Mod/Drawing/Gui/AppDrawingGuiPy.cpp b/src/Mod/Drawing/Gui/AppDrawingGuiPy.cpp index 363e45e614..a4cb65ef90 100644 --- a/src/Mod/Drawing/Gui/AppDrawingGuiPy.cpp +++ b/src/Mod/Drawing/Gui/AppDrawingGuiPy.cpp @@ -55,7 +55,7 @@ open(PyObject *self, PyObject *args) if (file.hasExtension("svg") || file.hasExtension("svgz")) { QString fileName = QString::fromUtf8(Name); // Displaying the image in a view - DrawingView* view = new DrawingView(Gui::getMainWindow()); + DrawingView* view = new DrawingView(0, Gui::getMainWindow()); view->load(fileName); view->setWindowIcon(Gui::BitmapFactory().pixmap("actions/drawing-landscape")); view->setWindowTitle(QObject::tr("Drawing viewer")); @@ -85,7 +85,7 @@ importer(PyObject *self, PyObject *args) if (file.hasExtension("svg") || file.hasExtension("svgz")) { QString fileName = QString::fromUtf8(Name); // Displaying the image in a view - DrawingView* view = new DrawingView(Gui::getMainWindow()); + DrawingView* view = new DrawingView(0, Gui::getMainWindow()); view->load(fileName); view->setWindowIcon(Gui::BitmapFactory().pixmap("actions/drawing-landscape")); view->setWindowTitle(QObject::tr("Drawing viewer")); @@ -139,6 +139,10 @@ exporter(PyObject *self, PyObject *args) str_out.close(); break; } + else { + PyErr_SetString(PyExc_TypeError, "Export as SVG of this object type is not supported by Drawing module"); + return 0; + } } } } PY_CATCH; diff --git a/src/Mod/Drawing/Gui/Command.cpp b/src/Mod/Drawing/Gui/Command.cpp index 2dc1a49576..7ed5a4641a 100644 --- a/src/Mod/Drawing/Gui/Command.cpp +++ b/src/Mod/Drawing/Gui/Command.cpp @@ -354,6 +354,91 @@ bool CmdDrawingOpenBrowserView::isActive(void) return (getActiveGuiDocument() ? true : false); } +//=========================================================================== +// Drawing_Annotation +//=========================================================================== + +DEF_STD_CMD_A(CmdDrawingAnnotation); + +CmdDrawingAnnotation::CmdDrawingAnnotation() + : Command("Drawing_Annotation") +{ + // seting the + sGroup = QT_TR_NOOP("Drawing"); + sMenuText = QT_TR_NOOP("&Annotation"); + sToolTipText = QT_TR_NOOP("Inserts an Annotation view in the active drawing"); + sWhatsThis = "Drawing_Annotation"; + sStatusTip = QT_TR_NOOP("Inserts an Annotation view in the active drawing"); + sPixmap = "actions/drawing-annotation"; +} + +void CmdDrawingAnnotation::activated(int iMsg) +{ + + std::vector pages = this->getDocument()->getObjectsOfType(Drawing::FeaturePage::getClassTypeId()); + if (pages.empty()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No page to insert"), + QObject::tr("Create a page to insert.")); + return; + } + std::string PageName = pages.front()->getNameInDocument(); + std::string FeatName = getUniqueObjectName("Annotation"); + openCommand("Create Annotation"); + doCommand(Doc,"App.activeDocument().addObject('Drawing::FeatureViewAnnotation','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.X = 10.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Y = 10.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.Scale = 7.0",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdDrawingAnnotation::isActive(void) +{ + return (getActiveGuiDocument() ? true : false); +} + + +//=========================================================================== +// Drawing_Clip +//=========================================================================== + +DEF_STD_CMD_A(CmdDrawingClip); + +CmdDrawingClip::CmdDrawingClip() + : Command("Drawing_Clip") +{ + // seting the + sGroup = QT_TR_NOOP("Drawing"); + sMenuText = QT_TR_NOOP("&Clip"); + sToolTipText = QT_TR_NOOP("Inserts a clip group in the active drawing"); + sWhatsThis = "Drawing_Annotation"; + sStatusTip = QT_TR_NOOP("Inserts a clip group in the active drawing"); + sPixmap = "actions/drawing-clip"; +} + +void CmdDrawingClip::activated(int iMsg) +{ + + std::vector pages = this->getDocument()->getObjectsOfType(Drawing::FeaturePage::getClassTypeId()); + if (pages.empty()){ + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("No page to insert"), + QObject::tr("Create a page to insert.")); + return; + } + std::string PageName = pages.front()->getNameInDocument(); + std::string FeatName = getUniqueObjectName("Clip"); + openCommand("Create Clip"); + doCommand(Doc,"App.activeDocument().addObject('Drawing::FeatureClip','%s')",FeatName.c_str()); + doCommand(Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)",PageName.c_str(),FeatName.c_str()); + updateActive(); + commitCommand(); +} + +bool CmdDrawingClip::isActive(void) +{ + return (getActiveGuiDocument() ? true : false); +} //=========================================================================== // Drawing_ExportPage @@ -451,6 +536,8 @@ void CreateDrawingCommands(void) rcCmdMgr.addCommand(new CmdDrawingNewView()); rcCmdMgr.addCommand(new CmdDrawingOrthoViews()); rcCmdMgr.addCommand(new CmdDrawingOpenBrowserView()); + rcCmdMgr.addCommand(new CmdDrawingAnnotation()); + rcCmdMgr.addCommand(new CmdDrawingClip()); rcCmdMgr.addCommand(new CmdDrawingExportPage()); rcCmdMgr.addCommand(new CmdDrawingProjectShape()); } diff --git a/src/Mod/Drawing/Gui/DrawingView.cpp b/src/Mod/Drawing/Gui/DrawingView.cpp index 7ae0e59841..6e9923a519 100644 --- a/src/Mod/Drawing/Gui/DrawingView.cpp +++ b/src/Mod/Drawing/Gui/DrawingView.cpp @@ -57,6 +57,7 @@ #include "DrawingView.h" #include #include +#include #include #include @@ -200,8 +201,8 @@ void SvgView::wheelEvent(QWheelEvent *event) /* TRANSLATOR DrawingGui::DrawingView */ -DrawingView::DrawingView(QWidget* parent) - : Gui::MDIView(0, parent), m_view(new SvgView) +DrawingView::DrawingView(Gui::Document* doc, QWidget* parent) + : Gui::MDIView(doc, parent), m_view(new SvgView) { m_backgroundAction = new QAction(tr("&Background"), this); m_backgroundAction->setEnabled(false); @@ -434,4 +435,9 @@ void DrawingView::viewAll() m_view->fitInView(m_view->scene()->sceneRect(), Qt::KeepAspectRatio); } +PyObject* DrawingView::getPyObject() +{ + Py_Return; +} + #include "moc_DrawingView.cpp" diff --git a/src/Mod/Drawing/Gui/DrawingView.h b/src/Mod/Drawing/Gui/DrawingView.h index 8e1e84f2d4..47f8ee852b 100644 --- a/src/Mod/Drawing/Gui/DrawingView.h +++ b/src/Mod/Drawing/Gui/DrawingView.h @@ -79,7 +79,7 @@ class DrawingGuiExport DrawingView : public Gui::MDIView Q_OBJECT public: - DrawingView(QWidget* parent = 0); + DrawingView(Gui::Document* doc, QWidget* parent = 0); public Q_SLOTS: void load(const QString &path = QString()); @@ -92,9 +92,8 @@ public: void print(); void printPdf(); void printPreview(); - -protected Q_SLOTS: void print(QPrinter* printer); + PyObject* getPyObject(); protected: void contextMenuEvent(QContextMenuEvent *event); diff --git a/src/Mod/Drawing/Gui/Resources/Drawing.qrc b/src/Mod/Drawing/Gui/Resources/Drawing.qrc index 853d6aa5e5..bc0ae4cdfe 100644 --- a/src/Mod/Drawing/Gui/Resources/Drawing.qrc +++ b/src/Mod/Drawing/Gui/Resources/Drawing.qrc @@ -16,6 +16,8 @@ icons/actions/drawing-view.svg icons/actions/drawing-orthoviews.svg icons/actions/drawing-openbrowser.svg + icons/actions/drawing-annotation.svg + icons/actions/drawing-clip.svg translations/Drawing_af.qm translations/Drawing_de.qm translations/Drawing_es.qm @@ -25,6 +27,7 @@ translations/Drawing_it.qm translations/Drawing_nl.qm translations/Drawing_no.qm + translations/Drawing_pl.qm translations/Drawing_pt.qm translations/Drawing_ru.qm translations/Drawing_se.qm diff --git a/src/Mod/Drawing/Gui/Resources/Makefile.am b/src/Mod/Drawing/Gui/Resources/Makefile.am index dbca09f2ec..69b335394c 100644 --- a/src/Mod/Drawing/Gui/Resources/Makefile.am +++ b/src/Mod/Drawing/Gui/Resources/Makefile.am @@ -20,6 +20,8 @@ EXTRA_DIST = \ icons/actions/drawing-portrait-A4.svg \ icons/actions/drawing-orthoviews.svg \ icons/actions/drawing-openbrowser.svg \ + icons/actions/drawing-annotation.svg \ + icons/actions/drawing-clip.svg \ icons/Page.svg \ icons/Pages.svg \ icons/View.svg \ @@ -32,6 +34,7 @@ EXTRA_DIST = \ translations/Drawing_it.qm \ translations/Drawing_nl.qm \ translations/Drawing_no.qm \ + translations/Drawing_pl.qm \ translations/Drawing_pt.qm \ translations/Drawing_ru.qm \ translations/Drawing_se.qm \ @@ -46,6 +49,7 @@ EXTRA_DIST = \ translations/Drawing_it.ts \ translations/Drawing_nl.ts \ translations/Drawing_no.ts \ + translations/Drawing_pl.ts \ translations/Drawing_pt.ts \ translations/Drawing_ru.ts \ translations/Drawing_se.ts \ diff --git a/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-annotation.svg b/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-annotation.svg new file mode 100755 index 0000000000..b45e42a483 --- /dev/null +++ b/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-annotation.svg @@ -0,0 +1,722 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Ab + + + diff --git a/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg b/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg new file mode 100644 index 0000000000..dd58ec78ad --- /dev/null +++ b/src/Mod/Drawing/Gui/Resources/icons/actions/drawing-clip.svg @@ -0,0 +1,710 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/Mod/Drawing/Gui/ViewProviderPage.cpp b/src/Mod/Drawing/Gui/ViewProviderPage.cpp index 55528e9cb4..e7f054cfc9 100644 --- a/src/Mod/Drawing/Gui/ViewProviderPage.cpp +++ b/src/Mod/Drawing/Gui/ViewProviderPage.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -131,9 +132,11 @@ bool ViewProviderDrawingPage::doubleClicked(void) DrawingView* ViewProviderDrawingPage::showDrawingView() { if (!view){ - view = new DrawingView(Gui::getMainWindow()); + Gui::Document* doc = Gui::Application::Instance->getDocument + (this->pcObject->getDocument()); + view = new DrawingView(doc, Gui::getMainWindow()); view->setWindowIcon(Gui::BitmapFactory().pixmap("actions/drawing-landscape")); - view->setWindowTitle(QObject::tr("Drawing viewer")); + view->setWindowTitle(QObject::tr("Drawing viewer") + QString::fromAscii("[*]")); Gui::getMainWindow()->addWindow(view); } diff --git a/src/Mod/Drawing/Gui/Workbench.cpp b/src/Mod/Drawing/Gui/Workbench.cpp index d4816ada24..e74f510e67 100644 --- a/src/Mod/Drawing/Gui/Workbench.cpp +++ b/src/Mod/Drawing/Gui/Workbench.cpp @@ -62,6 +62,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const *part << "Drawing_NewView"; *part << "Drawing_OrthoViews"; *part << "Drawing_OpenBrowserView"; + *part << "Drawing_Annotation"; + *part << "Drawing_Clip"; *part << "Drawing_ExportPage"; return root; @@ -78,6 +80,8 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *part << "Drawing_NewView"; *part << "Drawing_OrthoViews"; *part << "Drawing_OpenBrowserView"; + *part << "Drawing_Annotation"; + *part << "Drawing_Clip"; *part << "Drawing_ExportPage"; return root; } @@ -95,6 +99,8 @@ Gui::ToolBarItem* Workbench::setupCommandBars() const *img << "Drawing_NewPage"; *img << "Drawing_OrthoViews"; *img << "Drawing_OpenBrowserView"; + *img << "Drawing_Annotation"; + *img << "Drawing_Clip"; img = new Gui::ToolBarItem(root); img->setCommand("Views"); *img << "Drawing_NewView"; diff --git a/src/Mod/Fem/App/HypothesisPy.cpp b/src/Mod/Fem/App/HypothesisPy.cpp index 207488bbaf..7dbe2f7224 100644 --- a/src/Mod/Fem/App/HypothesisPy.cpp +++ b/src/Mod/Fem/App/HypothesisPy.cpp @@ -1,1047 +1,1056 @@ -/*************************************************************************** - * Copyright (c) 2010 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" -#include "HypothesisPy.h" -#include "FemMeshPy.h" -#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 - -using namespace Fem; - - -HypothesisPy::HypothesisPy(boost::shared_ptr h) - : hyp(h) -{ -} - -HypothesisPy::~HypothesisPy() -{ -} - -// ---------------------------------------------------------------------------- - -template -void SMESH_HypothesisPy::init_type(PyObject* module) -{ - // you must have overwritten the virtual functions - SMESH_HypothesisPy::behaviors().supportRepr(); - SMESH_HypothesisPy::behaviors().supportGetattr(); - SMESH_HypothesisPy::behaviors().supportSetattr(); - SMESH_HypothesisPy::behaviors().type_object()->tp_new = &PyMake; - - add_varargs_method("setLibName", &SMESH_HypothesisPy::setLibName, "setLibName(String)"); - add_varargs_method("getLibName", &SMESH_HypothesisPy::getLibName, "String getLibName()"); - add_varargs_method("setParameters", &SMESH_HypothesisPy::setParameters, "setParameters(String)"); - add_varargs_method("getParameters", &SMESH_HypothesisPy::getParameters, "String getParameters()"); - add_varargs_method("setLastParameters", &SMESH_HypothesisPy::setLastParameters, "setLastParameters(String)"); - add_varargs_method("getLastParameters", &SMESH_HypothesisPy::getLastParameters, "String getLastParameters()"); - add_varargs_method("clearParameters", &SMESH_HypothesisPy::clearParameters, "clearParameters()"); - add_varargs_method("isAuxiliary", &SMESH_HypothesisPy::isAuxiliary, "Bool isAuxiliary()"); - add_varargs_method("setParametersByMesh", &SMESH_HypothesisPy::setParametersByMesh, "setParametersByMesh(Mesh,Shape)"); - Base::Interpreter().addType(SMESH_HypothesisPy::behaviors().type_object(), - module,SMESH_HypothesisPy::behaviors().getName()); -} - -template -SMESH_HypothesisPy::SMESH_HypothesisPy(SMESH_Hypothesis* h) : hyp(h) -{ -} - -template -SMESH_HypothesisPy::~SMESH_HypothesisPy() -{ -} - -template -Py::Object SMESH_HypothesisPy::getattr(const char *name) -{ - if (strcmp(name,"this") == 0) - return Hypothesis(Py::asObject(new HypothesisPy(this->getHypothesis()))); - return Py::PythonExtension::getattr(name); -} - -template -Py::Object SMESH_HypothesisPy::repr() -{ - std::stringstream str; - str << hyp->GetName() << ", " << hyp->GetID(); - return Py::String(str.str()); -} - -template -Py::Object SMESH_HypothesisPy::setLibName(const Py::Tuple& args) -{ - std::string libName = (std::string)Py::String(args[0]); - hypothesis()->SetLibName(libName.c_str()); - return Py::None(); -} - -template -Py::Object SMESH_HypothesisPy::getLibName(const Py::Tuple& args) -{ - return Py::String(hypothesis()->GetLibName()); -} - -template -Py::Object SMESH_HypothesisPy::setParameters(const Py::Tuple& args) -{ - std::string paramName = (std::string)Py::String(args[0]); - hypothesis()->SetParameters(paramName.c_str()); - return Py::None(); -} - -template -Py::Object SMESH_HypothesisPy::getParameters(const Py::Tuple& args) -{ - return Py::String(hypothesis()->GetParameters()); -} - -template -Py::Object SMESH_HypothesisPy::setLastParameters(const Py::Tuple& args) -{ - std::string paramName = (std::string)Py::String(args[0]); - hypothesis()->SetLastParameters(paramName.c_str()); - return Py::None(); -} - -template -Py::Object SMESH_HypothesisPy::getLastParameters(const Py::Tuple& args) -{ - return Py::String(hypothesis()->GetLastParameters()); -} - -template -Py::Object SMESH_HypothesisPy::clearParameters(const Py::Tuple& args) -{ - hypothesis()->ClearParameters(); - return Py::None(); -} - -template -Py::Object SMESH_HypothesisPy::setParametersByMesh(const Py::Tuple& args) -{ - PyObject *mesh, *shape; - if (!PyArg_ParseTuple(args.ptr(), "O!O!", - &(Fem::FemMeshPy::Type), &mesh, - &(Part::TopoShapePy::Type), &shape)) - throw Py::Exception(); - Fem::FemMesh* m = static_cast(mesh)->getFemMeshPtr(); - const TopoDS_Shape& s = static_cast(shape)->getTopoShapePtr()->_Shape; - return Py::Boolean(hypothesis()->SetParametersByMesh(m->getSMesh(), s)); -} - -template -Py::Object SMESH_HypothesisPy::isAuxiliary(const Py::Tuple& args) -{ - return Py::Boolean(hypothesis()->IsAuxiliary()); -} - -template -PyObject *SMESH_HypothesisPy::PyMake(struct _typeobject *type, PyObject * args, PyObject * kwds) -{ - int hypId; - PyObject* obj; - if (!PyArg_ParseTuple(args, "iO!",&hypId,&(FemMeshPy::Type),&obj)) - return 0; - FemMesh* mesh = static_cast(obj)->getFemMeshPtr(); - return new T(hypId, 1, mesh->getGenerator()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Arithmetic1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Arithmetic1D"); - behaviors().doc("StdMeshers_Arithmetic1D"); - - add_varargs_method("setLength", &StdMeshers_Arithmetic1DPy::setLength, "setLength()"); - add_varargs_method("getLength", &StdMeshers_Arithmetic1DPy::getLength, "getLength()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Arithmetic1DPy::StdMeshers_Arithmetic1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Arithmetic1D(hypId, studyId, gen)) -{ -} - -StdMeshers_Arithmetic1DPy::~StdMeshers_Arithmetic1DPy() -{ -} - -Py::Object StdMeshers_Arithmetic1DPy::setLength(const Py::Tuple& args) -{ - hypothesis()-> - SetLength((double)Py::Float(args[0]), (bool)Py::Boolean(args[1])); - return Py::None(); -} - -Py::Object StdMeshers_Arithmetic1DPy::getLength(const Py::Tuple& args) -{ - int start; - if (!PyArg_ParseTuple(args.ptr(), "i",&start)) - throw Py::Exception(); - return Py::Float(hypothesis()-> - GetLength(start ? true : false)); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_AutomaticLengthPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_AutomaticLength"); - behaviors().doc("StdMeshers_AutomaticLength"); - - add_varargs_method("setFineness", &StdMeshers_AutomaticLengthPy::setFineness, "setFineness()"); - add_varargs_method("getFineness", &StdMeshers_AutomaticLengthPy::getFineness, "getFineness()"); - add_varargs_method("getLength", &StdMeshers_AutomaticLengthPy::getLength, "getLength()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_AutomaticLengthPy::StdMeshers_AutomaticLengthPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(0) -{ -} - -StdMeshers_AutomaticLengthPy::~StdMeshers_AutomaticLengthPy() -{ -} - -Py::Object StdMeshers_AutomaticLengthPy::setFineness(const Py::Tuple& args) -{ - double fine = (double)Py::Float(args[0]); - hypothesis()->SetFineness(fine); - return Py::None(); -} - -Py::Object StdMeshers_AutomaticLengthPy::getFineness(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetFineness()); -} - -namespace Py { - typedef ExtensionObject FemMesh; - typedef ExtensionObject TopoShape; - template<> bool FemMesh::accepts (PyObject *pyob) const - { - return (pyob && PyObject_TypeCheck(pyob, &(Fem::FemMeshPy::Type))); - } - template<> bool TopoShape::accepts (PyObject *pyob) const - { - return (pyob && PyObject_TypeCheck(pyob, &(Part::TopoShapePy::Type))); - } -} - -Py::Object StdMeshers_AutomaticLengthPy::getLength(const Py::Tuple& args) -{ - Py::FemMesh mesh(args[0]); - Py::Object shape_or_double(args[1]); - - Fem::FemMesh* m = mesh.extensionObject()->getFemMeshPtr(); - if (shape_or_double.type() == Py::Float().type()) { - double len = (double)Py::Float(shape_or_double); - return Py::Float(hypothesis()->GetLength(m->getSMesh(),len)); - } - else { - Py::TopoShape shape(shape_or_double); - const TopoDS_Shape& s = shape.extensionObject()->getTopoShapePtr()->_Shape; - return Py::Float(hypothesis()->GetLength(m->getSMesh(),s)); - } - - throw Py::Exception(); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_NotConformAllowedPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_NotConformAllowed"); - behaviors().doc("StdMeshers_NotConformAllowed"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_NotConformAllowedPy::StdMeshers_NotConformAllowedPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_NotConformAllowed(hypId, studyId, gen)) -{ -} - -StdMeshers_NotConformAllowedPy::~StdMeshers_NotConformAllowedPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_MaxLengthPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_MaxLength"); - behaviors().doc("StdMeshers_MaxLength"); - - add_varargs_method("setLength", &StdMeshers_MaxLengthPy::setLength, "setLength()"); - add_varargs_method("getLength", &StdMeshers_MaxLengthPy::getLength, "getLength()"); - add_varargs_method("havePreestimatedLength", &StdMeshers_MaxLengthPy::havePreestimatedLength, "havePreestimatedLength()"); - add_varargs_method("getPreestimatedLength", &StdMeshers_MaxLengthPy::getPreestimatedLength, "getPreestimatedLength()"); - add_varargs_method("setPreestimatedLength", &StdMeshers_MaxLengthPy::setPreestimatedLength, "setPreestimatedLength()"); - add_varargs_method("setUsePreestimatedLength", &StdMeshers_MaxLengthPy::setUsePreestimatedLength, "setUsePreestimatedLength()"); - add_varargs_method("getUsePreestimatedLength", &StdMeshers_MaxLengthPy::getUsePreestimatedLength, "getUsePreestimatedLength()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_MaxLengthPy::StdMeshers_MaxLengthPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_MaxLength(hypId, studyId, gen)) -{ -} - -StdMeshers_MaxLengthPy::~StdMeshers_MaxLengthPy() -{ -} - -Py::Object StdMeshers_MaxLengthPy::setLength(const Py::Tuple& args) -{ - hypothesis()->SetLength((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_MaxLengthPy::getLength(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetLength()); -} - -Py::Object StdMeshers_MaxLengthPy::havePreestimatedLength(const Py::Tuple& args) -{ - return Py::Boolean(hypothesis()->HavePreestimatedLength()); -} - -Py::Object StdMeshers_MaxLengthPy::getPreestimatedLength(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetPreestimatedLength()); -} - -Py::Object StdMeshers_MaxLengthPy::setPreestimatedLength(const Py::Tuple& args) -{ - hypothesis()->SetPreestimatedLength((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_MaxLengthPy::setUsePreestimatedLength(const Py::Tuple& args) -{ - hypothesis()->SetUsePreestimatedLength((bool)Py::Boolean(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_MaxLengthPy::getUsePreestimatedLength(const Py::Tuple& args) -{ - return Py::Boolean(hypothesis()->GetUsePreestimatedLength()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_LocalLengthPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_LocalLength"); - behaviors().doc("StdMeshers_LocalLength"); - - add_varargs_method("setLength", &StdMeshers_LocalLengthPy::setLength, "setLength()"); - add_varargs_method("getLength", &StdMeshers_LocalLengthPy::getLength, "getLength()"); - add_varargs_method("setPrecision", &StdMeshers_LocalLengthPy::setPrecision, "setPrecision()"); - add_varargs_method("getPrecision", &StdMeshers_LocalLengthPy::getPrecision, "getPrecision()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_LocalLengthPy::StdMeshers_LocalLengthPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_LocalLength(hypId, studyId, gen)) -{ -} - -StdMeshers_LocalLengthPy::~StdMeshers_LocalLengthPy() -{ -} - -Py::Object StdMeshers_LocalLengthPy::setLength(const Py::Tuple& args) -{ - hypothesis()->SetLength((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_LocalLengthPy::getLength(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetLength()); -} - -Py::Object StdMeshers_LocalLengthPy::setPrecision(const Py::Tuple& args) -{ - hypothesis()->SetPrecision((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_LocalLengthPy::getPrecision(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetPrecision()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_MaxElementAreaPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_MaxElementArea"); - behaviors().doc("StdMeshers_MaxElementArea"); - - add_varargs_method("setMaxArea", &StdMeshers_MaxElementAreaPy::setMaxArea, "setMaxArea()"); - add_varargs_method("getMaxArea", &StdMeshers_MaxElementAreaPy::getMaxArea, "getMaxArea()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_MaxElementAreaPy::StdMeshers_MaxElementAreaPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_MaxElementArea(hypId, studyId, gen)) -{ -} - -StdMeshers_MaxElementAreaPy::~StdMeshers_MaxElementAreaPy() -{ -} - -Py::Object StdMeshers_MaxElementAreaPy::setMaxArea(const Py::Tuple& args) -{ - hypothesis()->SetMaxArea((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_MaxElementAreaPy::getMaxArea(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetMaxArea()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_QuadranglePreferencePy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_QuadranglePreference"); - behaviors().doc("StdMeshers_QuadranglePreference"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_QuadranglePreferencePy::StdMeshers_QuadranglePreferencePy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_QuadranglePreference(hypId, studyId, gen)) -{ -} - -StdMeshers_QuadranglePreferencePy::~StdMeshers_QuadranglePreferencePy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Quadrangle_2DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Quadrangle_2D"); - behaviors().doc("StdMeshers_Quadrangle_2D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Quadrangle_2DPy::StdMeshers_Quadrangle_2DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Quadrangle_2D(hypId, studyId, gen)) -{ -} - -StdMeshers_Quadrangle_2DPy::~StdMeshers_Quadrangle_2DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Regular_1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Regular_1D"); - behaviors().doc("StdMeshers_Regular_1D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Regular_1DPy::StdMeshers_Regular_1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Regular_1D(hypId, studyId, gen)) -{ -} - -StdMeshers_Regular_1DPy::~StdMeshers_Regular_1DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_UseExisting_1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_UseExisting_1D"); - behaviors().doc("StdMeshers_UseExisting_1D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_UseExisting_1DPy::StdMeshers_UseExisting_1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_UseExisting_1D(hypId, studyId, gen)) -{ -} - -StdMeshers_UseExisting_1DPy::~StdMeshers_UseExisting_1DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_UseExisting_2DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_UseExisting_2D"); - behaviors().doc("StdMeshers_UseExisting_2D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_UseExisting_2DPy::StdMeshers_UseExisting_2DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_UseExisting_2D(hypId, studyId, gen)) -{ -} - -StdMeshers_UseExisting_2DPy::~StdMeshers_UseExisting_2DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_CompositeSegment_1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_CompositeSegment_1D"); - behaviors().doc("StdMeshers_CompositeSegment_1D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_CompositeSegment_1DPy::StdMeshers_CompositeSegment_1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_CompositeSegment_1D(hypId, studyId, gen)) -{ -} - -StdMeshers_CompositeSegment_1DPy::~StdMeshers_CompositeSegment_1DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Deflection1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Deflection1D"); - behaviors().doc("StdMeshers_Deflection1D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Deflection1DPy::StdMeshers_Deflection1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Deflection1D(hypId, studyId, gen)) -{ -} - -StdMeshers_Deflection1DPy::~StdMeshers_Deflection1DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Hexa_3DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Hexa_3D"); - behaviors().doc("StdMeshers_Hexa_3D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Hexa_3DPy::StdMeshers_Hexa_3DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Hexa_3D(hypId, studyId, gen)) -{ -} - -StdMeshers_Hexa_3DPy::~StdMeshers_Hexa_3DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_TrianglePreferencePy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_TrianglePreference"); - behaviors().doc("StdMeshers_TrianglePreference"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_TrianglePreferencePy::StdMeshers_TrianglePreferencePy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_TrianglePreference(hypId, studyId, gen)) -{ -} - -StdMeshers_TrianglePreferencePy::~StdMeshers_TrianglePreferencePy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_StartEndLengthPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_StartEndLength"); - behaviors().doc("StdMeshers_StartEndLength"); - add_varargs_method("setLength", &StdMeshers_StartEndLengthPy::setLength, "setLength()"); - add_varargs_method("getLength", &StdMeshers_StartEndLengthPy::getLength, "getLength()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_StartEndLengthPy::StdMeshers_StartEndLengthPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_StartEndLength(hypId, studyId, gen)) -{ -} - -StdMeshers_StartEndLengthPy::~StdMeshers_StartEndLengthPy() -{ -} - -Py::Object StdMeshers_StartEndLengthPy::setLength(const Py::Tuple& args) -{ - hypothesis()->SetLength((double)Py::Float(args[0]),(bool)Py::Boolean(args[1])); - return Py::None(); -} - -Py::Object StdMeshers_StartEndLengthPy::getLength(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetLength((bool)Py::Boolean(args[0]))); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_SegmentLengthAroundVertexPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_SegmentLengthAroundVertex"); - behaviors().doc("StdMeshers_SegmentLengthAroundVertex"); - add_varargs_method("setLength", &StdMeshers_SegmentLengthAroundVertexPy::setLength, "setLength()"); - add_varargs_method("getLength", &StdMeshers_SegmentLengthAroundVertexPy::getLength, "getLength()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_SegmentLengthAroundVertexPy::StdMeshers_SegmentLengthAroundVertexPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_SegmentLengthAroundVertex(hypId, studyId, gen)) -{ -} - -StdMeshers_SegmentLengthAroundVertexPy::~StdMeshers_SegmentLengthAroundVertexPy() -{ -} - -Py::Object StdMeshers_SegmentLengthAroundVertexPy::setLength(const Py::Tuple& args) -{ - hypothesis()->SetLength((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_SegmentLengthAroundVertexPy::getLength(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetLength()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_SegmentAroundVertex_0DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_SegmentAroundVertex_0D"); - behaviors().doc("StdMeshers_SegmentAroundVertex_0D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_SegmentAroundVertex_0DPy::StdMeshers_SegmentAroundVertex_0DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_SegmentAroundVertex_0D(hypId, studyId, gen)) -{ -} - -StdMeshers_SegmentAroundVertex_0DPy::~StdMeshers_SegmentAroundVertex_0DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_RadialPrism_3DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_RadialPrism_3D"); - behaviors().doc("StdMeshers_RadialPrism_3D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_RadialPrism_3DPy::StdMeshers_RadialPrism_3DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_RadialPrism_3D(hypId, studyId, gen)) -{ -} - -StdMeshers_RadialPrism_3DPy::~StdMeshers_RadialPrism_3DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_QuadraticMeshPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_QuadraticMesh"); - behaviors().doc("StdMeshers_QuadraticMesh"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_QuadraticMeshPy::StdMeshers_QuadraticMeshPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_QuadraticMesh(hypId, studyId, gen)) -{ -} - -StdMeshers_QuadraticMeshPy::~StdMeshers_QuadraticMeshPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_ProjectionSource3DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_ProjectionSource3D"); - behaviors().doc("StdMeshers_ProjectionSource3D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_ProjectionSource3DPy::StdMeshers_ProjectionSource3DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_ProjectionSource3D(hypId, studyId, gen)) -{ -} - -StdMeshers_ProjectionSource3DPy::~StdMeshers_ProjectionSource3DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_ProjectionSource2DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_ProjectionSource2D"); - behaviors().doc("StdMeshers_ProjectionSource2D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_ProjectionSource2DPy::StdMeshers_ProjectionSource2DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_ProjectionSource2D(hypId, studyId, gen)) -{ -} - -StdMeshers_ProjectionSource2DPy::~StdMeshers_ProjectionSource2DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_ProjectionSource1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_ProjectionSource1D"); - behaviors().doc("StdMeshers_ProjectionSource1D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_ProjectionSource1DPy::StdMeshers_ProjectionSource1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_ProjectionSource1D(hypId, studyId, gen)) -{ -} - -StdMeshers_ProjectionSource1DPy::~StdMeshers_ProjectionSource1DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Projection_3DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Projection_3D"); - behaviors().doc("StdMeshers_Projection_3D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Projection_3DPy::StdMeshers_Projection_3DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Projection_3D(hypId, studyId, gen)) -{ -} - -StdMeshers_Projection_3DPy::~StdMeshers_Projection_3DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Projection_2DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Projection_2D"); - behaviors().doc("StdMeshers_Projection_2D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Projection_2DPy::StdMeshers_Projection_2DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Projection_2D(hypId, studyId, gen)) -{ -} - -StdMeshers_Projection_2DPy::~StdMeshers_Projection_2DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Projection_1DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Projection_1D"); - behaviors().doc("StdMeshers_Projection_1D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Projection_1DPy::StdMeshers_Projection_1DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Projection_1D(hypId, studyId, gen)) -{ -} - -StdMeshers_Projection_1DPy::~StdMeshers_Projection_1DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_Prism_3DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_Prism_3D"); - behaviors().doc("StdMeshers_Prism_3D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_Prism_3DPy::StdMeshers_Prism_3DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_Prism_3D(hypId, studyId, gen)) -{ -} - -StdMeshers_Prism_3DPy::~StdMeshers_Prism_3DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_NumberOfSegmentsPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_NumberOfSegments"); - behaviors().doc("StdMeshers_NumberOfSegments"); - add_varargs_method("setNumberOfSegments",&StdMeshers_NumberOfSegmentsPy::setNumSegm,"setNumberOfSegments()"); - add_varargs_method("getNumberOfSegments",&StdMeshers_NumberOfSegmentsPy::getNumSegm,"getNumberOfSegments()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_NumberOfSegmentsPy::StdMeshers_NumberOfSegmentsPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_NumberOfSegments(hypId, studyId, gen)) -{ -} - -StdMeshers_NumberOfSegmentsPy::~StdMeshers_NumberOfSegmentsPy() -{ -} - -Py::Object StdMeshers_NumberOfSegmentsPy::setNumSegm(const Py::Tuple& args) -{ - hypothesis()->SetNumberOfSegments((int)Py::Int(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_NumberOfSegmentsPy::getNumSegm(const Py::Tuple& args) -{ - return Py::Int(hypothesis()->GetNumberOfSegments()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_NumberOfLayersPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_NumberOfLayers"); - behaviors().doc("StdMeshers_NumberOfLayers"); - add_varargs_method("setNumberOfLayers",&StdMeshers_NumberOfLayersPy::setNumLayers,"setNumberOfLayers()"); - add_varargs_method("getNumberOfLayers",&StdMeshers_NumberOfLayersPy::getNumLayers,"getNumberOfLayers()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_NumberOfLayersPy::StdMeshers_NumberOfLayersPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_NumberOfLayers(hypId, studyId, gen)) -{ -} - -StdMeshers_NumberOfLayersPy::~StdMeshers_NumberOfLayersPy() -{ -} - -Py::Object StdMeshers_NumberOfLayersPy::setNumLayers(const Py::Tuple& args) -{ - hypothesis()->SetNumberOfLayers((int)Py::Int(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_NumberOfLayersPy::getNumLayers(const Py::Tuple& args) -{ - return Py::Int(hypothesis()->GetNumberOfLayers()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_MEFISTO_2DPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_MEFISTO_2D"); - behaviors().doc("StdMeshers_MEFISTO_2D"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_MEFISTO_2DPy::StdMeshers_MEFISTO_2DPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_MEFISTO_2D(hypId, studyId, gen)) -{ -} - -StdMeshers_MEFISTO_2DPy::~StdMeshers_MEFISTO_2DPy() -{ -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_MaxElementVolumePy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_MaxElementVolume"); - behaviors().doc("StdMeshers_MaxElementVolume"); - add_varargs_method("setMaxVolume",&StdMeshers_MaxElementVolumePy::setMaxVolume,"setMaxVolume()"); - add_varargs_method("getMaxVolume",&StdMeshers_MaxElementVolumePy::getMaxVolume,"getMaxVolume()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_MaxElementVolumePy::StdMeshers_MaxElementVolumePy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_MaxElementVolume(hypId, studyId, gen)) -{ -} - -StdMeshers_MaxElementVolumePy::~StdMeshers_MaxElementVolumePy() -{ -} - -Py::Object StdMeshers_MaxElementVolumePy::setMaxVolume(const Py::Tuple& args) -{ - hypothesis()->SetMaxVolume((double)Py::Float(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_MaxElementVolumePy::getMaxVolume(const Py::Tuple& args) -{ - return Py::Float(hypothesis()->GetMaxVolume()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_LengthFromEdgesPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_LengthFromEdges"); - behaviors().doc("StdMeshers_LengthFromEdges"); - add_varargs_method("setMode",&StdMeshers_LengthFromEdgesPy::setMode,"setMode()"); - add_varargs_method("getMode",&StdMeshers_LengthFromEdgesPy::getMode,"getMode()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_LengthFromEdgesPy::StdMeshers_LengthFromEdgesPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_LengthFromEdges(hypId, studyId, gen)) -{ -} - -StdMeshers_LengthFromEdgesPy::~StdMeshers_LengthFromEdgesPy() -{ -} - -Py::Object StdMeshers_LengthFromEdgesPy::setMode(const Py::Tuple& args) -{ - hypothesis()->SetMode((int)Py::Int(args[0])); - return Py::None(); -} - -Py::Object StdMeshers_LengthFromEdgesPy::getMode(const Py::Tuple& args) -{ - return Py::Int(hypothesis()->GetMode()); -} - -// ---------------------------------------------------------------------------- - -void StdMeshers_LayerDistributionPy::init_type(PyObject* module) -{ - behaviors().name("StdMeshers_LayerDistribution"); - behaviors().doc("StdMeshers_LayerDistribution"); - add_varargs_method("setLayerDistribution", - &StdMeshers_LayerDistributionPy::setLayerDistribution, - "setLayerDistribution()"); - add_varargs_method("getLayerDistribution", - &StdMeshers_LayerDistributionPy::getLayerDistribution, - "getLayerDistribution()"); - SMESH_HypothesisPyBase::init_type(module); -} - -StdMeshers_LayerDistributionPy::StdMeshers_LayerDistributionPy(int hypId, int studyId, SMESH_Gen* gen) - : SMESH_HypothesisPyBase(new StdMeshers_LayerDistribution(hypId, studyId, gen)) -{ -} - -StdMeshers_LayerDistributionPy::~StdMeshers_LayerDistributionPy() -{ -} - -Py::Object StdMeshers_LayerDistributionPy::setLayerDistribution(const Py::Tuple& args) -{ - return Py::None(); -} - -Py::Object StdMeshers_LayerDistributionPy::getLayerDistribution(const Py::Tuple& args) -{ - //return hypothesis()->GetLayerDistribution(); - return Py::None(); -} +/*************************************************************************** + * Copyright (c) 2010 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" +#include "HypothesisPy.h" +#include "FemMeshPy.h" +#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 + +using namespace Fem; + + +HypothesisPy::HypothesisPy(boost::shared_ptr h) + : hyp(h) +{ +} + +HypothesisPy::~HypothesisPy() +{ +} + +// ---------------------------------------------------------------------------- + +template +void SMESH_HypothesisPy::init_type(PyObject* module) +{ + // you must have overwritten the virtual functions + SMESH_HypothesisPy::behaviors().supportRepr(); + SMESH_HypothesisPy::behaviors().supportGetattr(); + SMESH_HypothesisPy::behaviors().supportSetattr(); + SMESH_HypothesisPy::behaviors().type_object()->tp_new = &PyMake; + + SMESH_HypothesisPy::add_varargs_method("setLibName", &SMESH_HypothesisPy::setLibName, "setLibName(String)"); + SMESH_HypothesisPy::add_varargs_method("getLibName", &SMESH_HypothesisPy::getLibName, "String getLibName()"); + SMESH_HypothesisPy::add_varargs_method("setParameters", &SMESH_HypothesisPy::setParameters, "setParameters(String)"); + SMESH_HypothesisPy::add_varargs_method("getParameters", &SMESH_HypothesisPy::getParameters, "String getParameters()"); + SMESH_HypothesisPy::add_varargs_method("setLastParameters", &SMESH_HypothesisPy::setLastParameters, "setLastParameters(String)"); + SMESH_HypothesisPy::add_varargs_method("getLastParameters", &SMESH_HypothesisPy::getLastParameters, "String getLastParameters()"); + SMESH_HypothesisPy::add_varargs_method("clearParameters", &SMESH_HypothesisPy::clearParameters, "clearParameters()"); + SMESH_HypothesisPy::add_varargs_method("isAuxiliary", &SMESH_HypothesisPy::isAuxiliary, "Bool isAuxiliary()"); + SMESH_HypothesisPy::add_varargs_method("setParametersByMesh", &SMESH_HypothesisPy::setParametersByMesh, "setParametersByMesh(Mesh,Shape)"); + Base::Interpreter().addType(SMESH_HypothesisPy::behaviors().type_object(), + module,SMESH_HypothesisPy::behaviors().getName()); +} + +template +SMESH_HypothesisPy::SMESH_HypothesisPy(SMESH_Hypothesis* h) : hyp(h) +{ +} + +template +SMESH_HypothesisPy::~SMESH_HypothesisPy() +{ +} + +template +Py::Object SMESH_HypothesisPy::getattr(const char *name) +{ + if (strcmp(name,"this") == 0) + return Hypothesis(Py::asObject(new HypothesisPy(this->getHypothesis()))); + return Py::PythonExtension::getattr(name); +} + +template +Py::Object SMESH_HypothesisPy::repr() +{ + std::stringstream str; + str << hyp->GetName() << ", " << hyp->GetID(); + return Py::String(str.str()); +} + +template +Py::Object SMESH_HypothesisPy::setLibName(const Py::Tuple& args) +{ + std::string libName = (std::string)Py::String(args[0]); + hypothesis()->SetLibName(libName.c_str()); + return Py::None(); +} + +template +Py::Object SMESH_HypothesisPy::getLibName(const Py::Tuple& args) +{ + return Py::String(hypothesis()->GetLibName()); +} + +template +Py::Object SMESH_HypothesisPy::setParameters(const Py::Tuple& args) +{ + std::string paramName = (std::string)Py::String(args[0]); + hypothesis()->SetParameters(paramName.c_str()); + return Py::None(); +} + +template +Py::Object SMESH_HypothesisPy::getParameters(const Py::Tuple& args) +{ + return Py::String(hypothesis()->GetParameters()); +} + +template +Py::Object SMESH_HypothesisPy::setLastParameters(const Py::Tuple& args) +{ + std::string paramName = (std::string)Py::String(args[0]); + hypothesis()->SetLastParameters(paramName.c_str()); + return Py::None(); +} + +template +Py::Object SMESH_HypothesisPy::getLastParameters(const Py::Tuple& args) +{ + return Py::String(hypothesis()->GetLastParameters()); +} + +template +Py::Object SMESH_HypothesisPy::clearParameters(const Py::Tuple& args) +{ + hypothesis()->ClearParameters(); + return Py::None(); +} + +template +Py::Object SMESH_HypothesisPy::setParametersByMesh(const Py::Tuple& args) +{ + PyObject *mesh, *shape; + if (!PyArg_ParseTuple(args.ptr(), "O!O!", + &(Fem::FemMeshPy::Type), &mesh, + &(Part::TopoShapePy::Type), &shape)) + throw Py::Exception(); + Fem::FemMesh* m = static_cast(mesh)->getFemMeshPtr(); + const TopoDS_Shape& s = static_cast(shape)->getTopoShapePtr()->_Shape; + return Py::Boolean(hypothesis()->SetParametersByMesh(m->getSMesh(), s)); +} + +template +Py::Object SMESH_HypothesisPy::isAuxiliary(const Py::Tuple& args) +{ + return Py::Boolean(hypothesis()->IsAuxiliary()); +} + +template +PyObject *SMESH_HypothesisPy::PyMake(struct _typeobject *type, PyObject * args, PyObject * kwds) +{ + int hypId; + PyObject* obj; + if (!PyArg_ParseTuple(args, "iO!",&hypId,&(FemMeshPy::Type),&obj)) + return 0; + FemMesh* mesh = static_cast(obj)->getFemMeshPtr(); + return new T(hypId, 1, mesh->getGenerator()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Arithmetic1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Arithmetic1D"); + behaviors().doc("StdMeshers_Arithmetic1D"); + + add_varargs_method("setLength", &StdMeshers_Arithmetic1DPy::setLength, "setLength()"); + add_varargs_method("getLength", &StdMeshers_Arithmetic1DPy::getLength, "getLength()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Arithmetic1DPy::StdMeshers_Arithmetic1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Arithmetic1D(hypId, studyId, gen)) +{ +} + +StdMeshers_Arithmetic1DPy::~StdMeshers_Arithmetic1DPy() +{ +} + +Py::Object StdMeshers_Arithmetic1DPy::setLength(const Py::Tuple& args) +{ + hypothesis()-> + SetLength((double)Py::Float(args[0]), (bool)Py::Boolean(args[1])); + return Py::None(); +} + +Py::Object StdMeshers_Arithmetic1DPy::getLength(const Py::Tuple& args) +{ + int start; + if (!PyArg_ParseTuple(args.ptr(), "i",&start)) + throw Py::Exception(); + return Py::Float(hypothesis()-> + GetLength(start ? true : false)); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_AutomaticLengthPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_AutomaticLength"); + behaviors().doc("StdMeshers_AutomaticLength"); + + add_varargs_method("setFineness", &StdMeshers_AutomaticLengthPy::setFineness, "setFineness()"); + add_varargs_method("getFineness", &StdMeshers_AutomaticLengthPy::getFineness, "getFineness()"); + add_varargs_method("getLength", &StdMeshers_AutomaticLengthPy::getLength, "getLength()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_AutomaticLengthPy::StdMeshers_AutomaticLengthPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(0) +{ +} + +StdMeshers_AutomaticLengthPy::~StdMeshers_AutomaticLengthPy() +{ +} + +Py::Object StdMeshers_AutomaticLengthPy::setFineness(const Py::Tuple& args) +{ + double fine = (double)Py::Float(args[0]); + hypothesis()->SetFineness(fine); + return Py::None(); +} + +Py::Object StdMeshers_AutomaticLengthPy::getFineness(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetFineness()); +} + +namespace Py { + typedef ExtensionObject FemMesh; + typedef ExtensionObject TopoShape; + template<> bool FemMesh::accepts (PyObject *pyob) const + { + return (pyob && PyObject_TypeCheck(pyob, &(Fem::FemMeshPy::Type))); + } + template<> bool TopoShape::accepts (PyObject *pyob) const + { + return (pyob && PyObject_TypeCheck(pyob, &(Part::TopoShapePy::Type))); + } +} + +Py::Object StdMeshers_AutomaticLengthPy::getLength(const Py::Tuple& args) +{ + Py::FemMesh mesh(args[0]); + Py::Object shape_or_double(args[1]); + + Fem::FemMesh* m = mesh.extensionObject()->getFemMeshPtr(); + if (shape_or_double.type() == Py::Float().type()) { + double len = (double)Py::Float(shape_or_double); + return Py::Float(hypothesis()->GetLength(m->getSMesh(),len)); + } + else { + Py::TopoShape shape(shape_or_double); + const TopoDS_Shape& s = shape.extensionObject()->getTopoShapePtr()->_Shape; + return Py::Float(hypothesis()->GetLength(m->getSMesh(),s)); + } + + throw Py::Exception(); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_NotConformAllowedPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_NotConformAllowed"); + behaviors().doc("StdMeshers_NotConformAllowed"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_NotConformAllowedPy::StdMeshers_NotConformAllowedPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_NotConformAllowed(hypId, studyId, gen)) +{ +} + +StdMeshers_NotConformAllowedPy::~StdMeshers_NotConformAllowedPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_MaxLengthPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_MaxLength"); + behaviors().doc("StdMeshers_MaxLength"); + + add_varargs_method("setLength", &StdMeshers_MaxLengthPy::setLength, "setLength()"); + add_varargs_method("getLength", &StdMeshers_MaxLengthPy::getLength, "getLength()"); + add_varargs_method("havePreestimatedLength", &StdMeshers_MaxLengthPy::havePreestimatedLength, "havePreestimatedLength()"); + add_varargs_method("getPreestimatedLength", &StdMeshers_MaxLengthPy::getPreestimatedLength, "getPreestimatedLength()"); + add_varargs_method("setPreestimatedLength", &StdMeshers_MaxLengthPy::setPreestimatedLength, "setPreestimatedLength()"); + add_varargs_method("setUsePreestimatedLength", &StdMeshers_MaxLengthPy::setUsePreestimatedLength, "setUsePreestimatedLength()"); + add_varargs_method("getUsePreestimatedLength", &StdMeshers_MaxLengthPy::getUsePreestimatedLength, "getUsePreestimatedLength()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_MaxLengthPy::StdMeshers_MaxLengthPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_MaxLength(hypId, studyId, gen)) +{ +} + +StdMeshers_MaxLengthPy::~StdMeshers_MaxLengthPy() +{ +} + +Py::Object StdMeshers_MaxLengthPy::setLength(const Py::Tuple& args) +{ + hypothesis()->SetLength((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_MaxLengthPy::getLength(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetLength()); +} + +Py::Object StdMeshers_MaxLengthPy::havePreestimatedLength(const Py::Tuple& args) +{ + return Py::Boolean(hypothesis()->HavePreestimatedLength()); +} + +Py::Object StdMeshers_MaxLengthPy::getPreestimatedLength(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetPreestimatedLength()); +} + +Py::Object StdMeshers_MaxLengthPy::setPreestimatedLength(const Py::Tuple& args) +{ + hypothesis()->SetPreestimatedLength((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_MaxLengthPy::setUsePreestimatedLength(const Py::Tuple& args) +{ + hypothesis()->SetUsePreestimatedLength((bool)Py::Boolean(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_MaxLengthPy::getUsePreestimatedLength(const Py::Tuple& args) +{ + return Py::Boolean(hypothesis()->GetUsePreestimatedLength()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_LocalLengthPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_LocalLength"); + behaviors().doc("StdMeshers_LocalLength"); + + add_varargs_method("setLength", &StdMeshers_LocalLengthPy::setLength, "setLength()"); + add_varargs_method("getLength", &StdMeshers_LocalLengthPy::getLength, "getLength()"); + add_varargs_method("setPrecision", &StdMeshers_LocalLengthPy::setPrecision, "setPrecision()"); + add_varargs_method("getPrecision", &StdMeshers_LocalLengthPy::getPrecision, "getPrecision()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_LocalLengthPy::StdMeshers_LocalLengthPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_LocalLength(hypId, studyId, gen)) +{ +} + +StdMeshers_LocalLengthPy::~StdMeshers_LocalLengthPy() +{ +} + +Py::Object StdMeshers_LocalLengthPy::setLength(const Py::Tuple& args) +{ + hypothesis()->SetLength((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_LocalLengthPy::getLength(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetLength()); +} + +Py::Object StdMeshers_LocalLengthPy::setPrecision(const Py::Tuple& args) +{ + hypothesis()->SetPrecision((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_LocalLengthPy::getPrecision(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetPrecision()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_MaxElementAreaPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_MaxElementArea"); + behaviors().doc("StdMeshers_MaxElementArea"); + + add_varargs_method("setMaxArea", &StdMeshers_MaxElementAreaPy::setMaxArea, "setMaxArea()"); + add_varargs_method("getMaxArea", &StdMeshers_MaxElementAreaPy::getMaxArea, "getMaxArea()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_MaxElementAreaPy::StdMeshers_MaxElementAreaPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_MaxElementArea(hypId, studyId, gen)) +{ +} + +StdMeshers_MaxElementAreaPy::~StdMeshers_MaxElementAreaPy() +{ +} + +Py::Object StdMeshers_MaxElementAreaPy::setMaxArea(const Py::Tuple& args) +{ + hypothesis()->SetMaxArea((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_MaxElementAreaPy::getMaxArea(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetMaxArea()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_QuadranglePreferencePy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_QuadranglePreference"); + behaviors().doc("StdMeshers_QuadranglePreference"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_QuadranglePreferencePy::StdMeshers_QuadranglePreferencePy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_QuadranglePreference(hypId, studyId, gen)) +{ +} + +StdMeshers_QuadranglePreferencePy::~StdMeshers_QuadranglePreferencePy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Quadrangle_2DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Quadrangle_2D"); + behaviors().doc("StdMeshers_Quadrangle_2D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Quadrangle_2DPy::StdMeshers_Quadrangle_2DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Quadrangle_2D(hypId, studyId, gen)) +{ +} + +StdMeshers_Quadrangle_2DPy::~StdMeshers_Quadrangle_2DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Regular_1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Regular_1D"); + behaviors().doc("StdMeshers_Regular_1D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Regular_1DPy::StdMeshers_Regular_1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Regular_1D(hypId, studyId, gen)) +{ +} + +StdMeshers_Regular_1DPy::~StdMeshers_Regular_1DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_UseExisting_1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_UseExisting_1D"); + behaviors().doc("StdMeshers_UseExisting_1D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_UseExisting_1DPy::StdMeshers_UseExisting_1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_UseExisting_1D(hypId, studyId, gen)) +{ +} + +StdMeshers_UseExisting_1DPy::~StdMeshers_UseExisting_1DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_UseExisting_2DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_UseExisting_2D"); + behaviors().doc("StdMeshers_UseExisting_2D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_UseExisting_2DPy::StdMeshers_UseExisting_2DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_UseExisting_2D(hypId, studyId, gen)) +{ +} + +StdMeshers_UseExisting_2DPy::~StdMeshers_UseExisting_2DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_CompositeSegment_1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_CompositeSegment_1D"); + behaviors().doc("StdMeshers_CompositeSegment_1D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_CompositeSegment_1DPy::StdMeshers_CompositeSegment_1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_CompositeSegment_1D(hypId, studyId, gen)) +{ +} + +StdMeshers_CompositeSegment_1DPy::~StdMeshers_CompositeSegment_1DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Deflection1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Deflection1D"); + behaviors().doc("StdMeshers_Deflection1D"); + + add_varargs_method("setDeflection", &StdMeshers_Deflection1DPy::setDeflection, "setDeflection()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Deflection1DPy::StdMeshers_Deflection1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Deflection1D(hypId, studyId, gen)) +{ +} + +StdMeshers_Deflection1DPy::~StdMeshers_Deflection1DPy() +{ +} + +Py::Object StdMeshers_Deflection1DPy::setDeflection(const Py::Tuple& args) +{ + double fine = (double)Py::Float(args[0]); + hypothesis()->SetDeflection(fine); + return Py::None(); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Hexa_3DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Hexa_3D"); + behaviors().doc("StdMeshers_Hexa_3D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Hexa_3DPy::StdMeshers_Hexa_3DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Hexa_3D(hypId, studyId, gen)) +{ +} + +StdMeshers_Hexa_3DPy::~StdMeshers_Hexa_3DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_TrianglePreferencePy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_TrianglePreference"); + behaviors().doc("StdMeshers_TrianglePreference"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_TrianglePreferencePy::StdMeshers_TrianglePreferencePy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_TrianglePreference(hypId, studyId, gen)) +{ +} + +StdMeshers_TrianglePreferencePy::~StdMeshers_TrianglePreferencePy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_StartEndLengthPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_StartEndLength"); + behaviors().doc("StdMeshers_StartEndLength"); + add_varargs_method("setLength", &StdMeshers_StartEndLengthPy::setLength, "setLength()"); + add_varargs_method("getLength", &StdMeshers_StartEndLengthPy::getLength, "getLength()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_StartEndLengthPy::StdMeshers_StartEndLengthPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_StartEndLength(hypId, studyId, gen)) +{ +} + +StdMeshers_StartEndLengthPy::~StdMeshers_StartEndLengthPy() +{ +} + +Py::Object StdMeshers_StartEndLengthPy::setLength(const Py::Tuple& args) +{ + hypothesis()->SetLength((double)Py::Float(args[0]),(bool)Py::Boolean(args[1])); + return Py::None(); +} + +Py::Object StdMeshers_StartEndLengthPy::getLength(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetLength((bool)Py::Boolean(args[0]))); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_SegmentLengthAroundVertexPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_SegmentLengthAroundVertex"); + behaviors().doc("StdMeshers_SegmentLengthAroundVertex"); + add_varargs_method("setLength", &StdMeshers_SegmentLengthAroundVertexPy::setLength, "setLength()"); + add_varargs_method("getLength", &StdMeshers_SegmentLengthAroundVertexPy::getLength, "getLength()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_SegmentLengthAroundVertexPy::StdMeshers_SegmentLengthAroundVertexPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_SegmentLengthAroundVertex(hypId, studyId, gen)) +{ +} + +StdMeshers_SegmentLengthAroundVertexPy::~StdMeshers_SegmentLengthAroundVertexPy() +{ +} + +Py::Object StdMeshers_SegmentLengthAroundVertexPy::setLength(const Py::Tuple& args) +{ + hypothesis()->SetLength((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_SegmentLengthAroundVertexPy::getLength(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetLength()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_SegmentAroundVertex_0DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_SegmentAroundVertex_0D"); + behaviors().doc("StdMeshers_SegmentAroundVertex_0D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_SegmentAroundVertex_0DPy::StdMeshers_SegmentAroundVertex_0DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_SegmentAroundVertex_0D(hypId, studyId, gen)) +{ +} + +StdMeshers_SegmentAroundVertex_0DPy::~StdMeshers_SegmentAroundVertex_0DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_RadialPrism_3DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_RadialPrism_3D"); + behaviors().doc("StdMeshers_RadialPrism_3D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_RadialPrism_3DPy::StdMeshers_RadialPrism_3DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_RadialPrism_3D(hypId, studyId, gen)) +{ +} + +StdMeshers_RadialPrism_3DPy::~StdMeshers_RadialPrism_3DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_QuadraticMeshPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_QuadraticMesh"); + behaviors().doc("StdMeshers_QuadraticMesh"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_QuadraticMeshPy::StdMeshers_QuadraticMeshPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_QuadraticMesh(hypId, studyId, gen)) +{ +} + +StdMeshers_QuadraticMeshPy::~StdMeshers_QuadraticMeshPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_ProjectionSource3DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_ProjectionSource3D"); + behaviors().doc("StdMeshers_ProjectionSource3D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_ProjectionSource3DPy::StdMeshers_ProjectionSource3DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_ProjectionSource3D(hypId, studyId, gen)) +{ +} + +StdMeshers_ProjectionSource3DPy::~StdMeshers_ProjectionSource3DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_ProjectionSource2DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_ProjectionSource2D"); + behaviors().doc("StdMeshers_ProjectionSource2D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_ProjectionSource2DPy::StdMeshers_ProjectionSource2DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_ProjectionSource2D(hypId, studyId, gen)) +{ +} + +StdMeshers_ProjectionSource2DPy::~StdMeshers_ProjectionSource2DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_ProjectionSource1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_ProjectionSource1D"); + behaviors().doc("StdMeshers_ProjectionSource1D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_ProjectionSource1DPy::StdMeshers_ProjectionSource1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_ProjectionSource1D(hypId, studyId, gen)) +{ +} + +StdMeshers_ProjectionSource1DPy::~StdMeshers_ProjectionSource1DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Projection_3DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Projection_3D"); + behaviors().doc("StdMeshers_Projection_3D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Projection_3DPy::StdMeshers_Projection_3DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Projection_3D(hypId, studyId, gen)) +{ +} + +StdMeshers_Projection_3DPy::~StdMeshers_Projection_3DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Projection_2DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Projection_2D"); + behaviors().doc("StdMeshers_Projection_2D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Projection_2DPy::StdMeshers_Projection_2DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Projection_2D(hypId, studyId, gen)) +{ +} + +StdMeshers_Projection_2DPy::~StdMeshers_Projection_2DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Projection_1DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Projection_1D"); + behaviors().doc("StdMeshers_Projection_1D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Projection_1DPy::StdMeshers_Projection_1DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Projection_1D(hypId, studyId, gen)) +{ +} + +StdMeshers_Projection_1DPy::~StdMeshers_Projection_1DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_Prism_3DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_Prism_3D"); + behaviors().doc("StdMeshers_Prism_3D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_Prism_3DPy::StdMeshers_Prism_3DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_Prism_3D(hypId, studyId, gen)) +{ +} + +StdMeshers_Prism_3DPy::~StdMeshers_Prism_3DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_NumberOfSegmentsPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_NumberOfSegments"); + behaviors().doc("StdMeshers_NumberOfSegments"); + add_varargs_method("setNumberOfSegments",&StdMeshers_NumberOfSegmentsPy::setNumSegm,"setNumberOfSegments()"); + add_varargs_method("getNumberOfSegments",&StdMeshers_NumberOfSegmentsPy::getNumSegm,"getNumberOfSegments()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_NumberOfSegmentsPy::StdMeshers_NumberOfSegmentsPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_NumberOfSegments(hypId, studyId, gen)) +{ +} + +StdMeshers_NumberOfSegmentsPy::~StdMeshers_NumberOfSegmentsPy() +{ +} + +Py::Object StdMeshers_NumberOfSegmentsPy::setNumSegm(const Py::Tuple& args) +{ + hypothesis()->SetNumberOfSegments((int)Py::Int(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_NumberOfSegmentsPy::getNumSegm(const Py::Tuple& args) +{ + return Py::Int(hypothesis()->GetNumberOfSegments()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_NumberOfLayersPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_NumberOfLayers"); + behaviors().doc("StdMeshers_NumberOfLayers"); + add_varargs_method("setNumberOfLayers",&StdMeshers_NumberOfLayersPy::setNumLayers,"setNumberOfLayers()"); + add_varargs_method("getNumberOfLayers",&StdMeshers_NumberOfLayersPy::getNumLayers,"getNumberOfLayers()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_NumberOfLayersPy::StdMeshers_NumberOfLayersPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_NumberOfLayers(hypId, studyId, gen)) +{ +} + +StdMeshers_NumberOfLayersPy::~StdMeshers_NumberOfLayersPy() +{ +} + +Py::Object StdMeshers_NumberOfLayersPy::setNumLayers(const Py::Tuple& args) +{ + hypothesis()->SetNumberOfLayers((int)Py::Int(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_NumberOfLayersPy::getNumLayers(const Py::Tuple& args) +{ + return Py::Int(hypothesis()->GetNumberOfLayers()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_MEFISTO_2DPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_MEFISTO_2D"); + behaviors().doc("StdMeshers_MEFISTO_2D"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_MEFISTO_2DPy::StdMeshers_MEFISTO_2DPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_MEFISTO_2D(hypId, studyId, gen)) +{ +} + +StdMeshers_MEFISTO_2DPy::~StdMeshers_MEFISTO_2DPy() +{ +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_MaxElementVolumePy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_MaxElementVolume"); + behaviors().doc("StdMeshers_MaxElementVolume"); + add_varargs_method("setMaxVolume",&StdMeshers_MaxElementVolumePy::setMaxVolume,"setMaxVolume()"); + add_varargs_method("getMaxVolume",&StdMeshers_MaxElementVolumePy::getMaxVolume,"getMaxVolume()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_MaxElementVolumePy::StdMeshers_MaxElementVolumePy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_MaxElementVolume(hypId, studyId, gen)) +{ +} + +StdMeshers_MaxElementVolumePy::~StdMeshers_MaxElementVolumePy() +{ +} + +Py::Object StdMeshers_MaxElementVolumePy::setMaxVolume(const Py::Tuple& args) +{ + hypothesis()->SetMaxVolume((double)Py::Float(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_MaxElementVolumePy::getMaxVolume(const Py::Tuple& args) +{ + return Py::Float(hypothesis()->GetMaxVolume()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_LengthFromEdgesPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_LengthFromEdges"); + behaviors().doc("StdMeshers_LengthFromEdges"); + add_varargs_method("setMode",&StdMeshers_LengthFromEdgesPy::setMode,"setMode()"); + add_varargs_method("getMode",&StdMeshers_LengthFromEdgesPy::getMode,"getMode()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_LengthFromEdgesPy::StdMeshers_LengthFromEdgesPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_LengthFromEdges(hypId, studyId, gen)) +{ +} + +StdMeshers_LengthFromEdgesPy::~StdMeshers_LengthFromEdgesPy() +{ +} + +Py::Object StdMeshers_LengthFromEdgesPy::setMode(const Py::Tuple& args) +{ + hypothesis()->SetMode((int)Py::Int(args[0])); + return Py::None(); +} + +Py::Object StdMeshers_LengthFromEdgesPy::getMode(const Py::Tuple& args) +{ + return Py::Int(hypothesis()->GetMode()); +} + +// ---------------------------------------------------------------------------- + +void StdMeshers_LayerDistributionPy::init_type(PyObject* module) +{ + behaviors().name("StdMeshers_LayerDistribution"); + behaviors().doc("StdMeshers_LayerDistribution"); + add_varargs_method("setLayerDistribution", + &StdMeshers_LayerDistributionPy::setLayerDistribution, + "setLayerDistribution()"); + add_varargs_method("getLayerDistribution", + &StdMeshers_LayerDistributionPy::getLayerDistribution, + "getLayerDistribution()"); + SMESH_HypothesisPyBase::init_type(module); +} + +StdMeshers_LayerDistributionPy::StdMeshers_LayerDistributionPy(int hypId, int studyId, SMESH_Gen* gen) + : SMESH_HypothesisPyBase(new StdMeshers_LayerDistribution(hypId, studyId, gen)) +{ +} + +StdMeshers_LayerDistributionPy::~StdMeshers_LayerDistributionPy() +{ +} + +Py::Object StdMeshers_LayerDistributionPy::setLayerDistribution(const Py::Tuple& args) +{ + return Py::None(); +} + +Py::Object StdMeshers_LayerDistributionPy::getLayerDistribution(const Py::Tuple& args) +{ + //return hypothesis()->GetLayerDistribution(); + return Py::None(); +} diff --git a/src/Mod/Fem/App/HypothesisPy.h b/src/Mod/Fem/App/HypothesisPy.h index 51d06bb25b..776c80c8ca 100644 --- a/src/Mod/Fem/App/HypothesisPy.h +++ b/src/Mod/Fem/App/HypothesisPy.h @@ -208,6 +208,8 @@ public: static void init_type(PyObject*); StdMeshers_Deflection1DPy(int hypId, int studyId, SMESH_Gen* gen); ~StdMeshers_Deflection1DPy(); + + Py::Object setDeflection(const Py::Tuple& args); }; class StdMeshers_Hexa_3DPy : public SMESH_HypothesisPy diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 8774505f48..5343beb2b7 100644 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -28,6 +28,24 @@ if(SMESH_FOUND) include_directories( ${SMESH_INCLUDE_DIR} ) list( APPEND FemGui_LIBS ${SMESH_LIBRARIES} ) endif(SMESH_FOUND) + +set(FemGui_MOC_HDRS + Hypothesis.h +) +fc_wrap_cpp(FemGui_MOC_SRCS ${FemGui_MOC_HDRS}) +SOURCE_GROUP("Moc" FILES ${FemGui_MOC_SRCS}) + +set(FemGui_UIC_SRCS + Hypothesis.ui +) +qt4_wrap_ui(FemGui_UIC_HDRS ${FemGui_UIC_SRCS}) +SET(FemGui_DLG_SRCS + ${FemGui_UIC_HDRS} + Hypothesis.ui + Hypothesis.cpp + Hypothesis.h +) +SOURCE_GROUP("Dialogs" FILES ${FemGui_DLG_SRCS}) qt4_add_resources(FemResource_SRCS Resources/Fem.qrc) @@ -35,7 +53,7 @@ SOURCE_GROUP("Resources" FILES ${FemResource_SRCS}) SET(FemGui_SRCS - #${FemGui_UIC_HDRS} + ${FemGui_DLG_SRCS} ${FemResource_SRCS} AppFemGui.cpp AppFemGuiPy.cpp diff --git a/src/Mod/Fem/Gui/Command.cpp b/src/Mod/Fem/Gui/Command.cpp index 54b2086d7f..61e033fc29 100644 --- a/src/Mod/Fem/Gui/Command.cpp +++ b/src/Mod/Fem/Gui/Command.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include +#include "Hypothesis.h" using namespace std; @@ -57,46 +59,14 @@ CmdFemCreateFromShape::CmdFemCreateFromShape() void CmdFemCreateFromShape::activated(int iMsg) { - Base::Type type = Base::Type::fromName("Part::Feature"); - std::vector obj = Gui::Selection().getObjectsOfType(type); - - openCommand("Create FEM"); - doCommand(Doc, "import Fem"); - for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) { - App::Document* doc = (*it)->getDocument(); - QString name = QString::fromAscii((*it)->getNameInDocument()); - QString cmd = QString::fromAscii( - "__fem__=Fem.FemMesh()\n" - "__fem__.setShape(FreeCAD.getDocument(\"%1\").%2.Shape)\n" - "h1=Fem.StdMeshers_MaxLength(0,__fem__)\n" - "h1.setLength(1.0)\n" - "h2=Fem.StdMeshers_LocalLength(1,__fem__)\n" - "h2.setLength(1.0)\n" - "h3=Fem.StdMeshers_QuadranglePreference(2,__fem__)\n" - "h4=Fem.StdMeshers_Quadrangle_2D(3,__fem__)\n" - "h5=Fem.StdMeshers_MaxElementArea(4,__fem__)\n" - "h5.setMaxArea(1.0)\n" - "h6=Fem.StdMeshers_Regular_1D(5,__fem__)\n" - "__fem__.addHypothesis(h1)\n" - "__fem__.addHypothesis(h2)\n" - "__fem__.addHypothesis(h3)\n" - "__fem__.addHypothesis(h4)\n" - "__fem__.addHypothesis(h5)\n" - "__fem__.addHypothesis(h6)\n" - "__fem__.compute()\n" - "FreeCAD.getDocument(\"%1\").addObject" - "(\"Fem::FemMeshObject\",\"%2\").FemMesh=__fem__\n" - "del __fem__,h1,h2,h3,h4,h5,h6\n" - ) - .arg(QString::fromAscii(doc->getName())) - .arg(name); - doCommand(Doc, "%s", (const char*)cmd.toAscii()); - } - commitCommand(); + FemGui::TaskHypothesis* dlg = new FemGui::TaskHypothesis(); + Gui::Control().showDialog(dlg); } bool CmdFemCreateFromShape::isActive(void) { + if (Gui::Control().activeDialog()) + return false; Base::Type type = Base::Type::fromName("Part::Feature"); return Gui::Selection().countObjectsOfType(type) > 0; } diff --git a/src/Mod/Fem/Gui/Hypothesis.cpp b/src/Mod/Fem/Gui/Hypothesis.cpp new file mode 100644 index 0000000000..3625b438f8 --- /dev/null +++ b/src/Mod/Fem/Gui/Hypothesis.cpp @@ -0,0 +1,186 @@ +/*************************************************************************** + * Copyright (c) 2012 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 +#endif + +#include "Hypothesis.h" +#include "ui_Hypothesis.h" + +#include +#include +#include + +using namespace FemGui; + +HypothesisWidget::HypothesisWidget(QWidget* parent) + : QWidget(parent), ui(new Ui_HypothesisWidget) +{ + ui->setupUi(this); +} + +HypothesisWidget::~HypothesisWidget() +{ + delete ui; +} + +bool HypothesisWidget::accept() +{ + Base::Type type = Base::Type::fromName("Part::Feature"); + std::vector obj = Gui::Selection().getObjectsOfType(type); + + Gui::Command::openCommand("Create FEM"); + Gui::Command::doCommand(Gui::Command::Doc, "import Fem"); + for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) { + QString cmd; + QTextStream str(&cmd); + App::Document* doc = (*it)->getDocument(); + QString doc_name = QString::fromAscii(doc->getName()); + QString obj_name = QString::fromAscii((*it)->getNameInDocument()); + str << QString::fromAscii( + "__fem__=Fem.FemMesh()\n" + "__fem__.setShape(FreeCAD.getDocument('%1').%2.Shape)\n") + .arg(doc_name).arg(obj_name); + int hyp=0; + + if (ui->maxLength->isChecked()) { + str << QString::fromAscii( + "hyp=Fem.StdMeshers_MaxLength(%1,__fem__)\n" + "hyp.setLength(%2)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++).arg(ui->valMaxLength->value()); + } + + if (ui->localLength->isChecked()) { + str << QString::fromAscii( + "hyp=Fem.StdMeshers_LocalLength(%1,__fem__)\n" + "hyp.setLength(%2)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++).arg(ui->valLocalLength->value()); + } + + if (ui->maxArea->isChecked()) { + str << QString::fromAscii( + "hyp=Fem.StdMeshers_MaxElementArea(%1,__fem__)\n" + "hyp.setMaxArea(%2)\n" + "__fem__.addHypothesis(hyp)\n"). + arg(hyp++).arg(ui->valMaxArea->value()); + } +#if 0 + str << QString::fromAscii( + "hyp=Fem.StdMeshers_NumberOfSegments(%1,__fem__)\n" + "hyp.setNumberOfSegments(1)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++); + + str << QString::fromAscii( + "hyp=Fem.StdMeshers_Deflection1D(%1,__fem__)\n" + "hyp.setDeflection(0.02)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++); +#endif + str << QString::fromAscii( + "hyp=Fem.StdMeshers_Regular_1D(%1,__fem__)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++); + + if (ui->quadPref->isChecked()) { + str << QString::fromAscii( + "hyp=Fem.StdMeshers_QuadranglePreference(%1,__fem__)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++); + } + + str << QString::fromAscii( + "hyp=Fem.StdMeshers_Quadrangle_2D(%1,__fem__)\n" + "__fem__.addHypothesis(hyp)\n") + .arg(hyp++); + + str << QString::fromAscii( + "__fem__.compute()\n" + "FreeCAD.getDocument('%1').addObject" + "(\"Fem::FemMeshObject\",'%2').FemMesh=__fem__\n" + "del __fem__, hyp\n") + .arg(doc_name).arg(obj_name); + Gui::Command::doCommand(Gui::Command::Doc, "%s", (const char*)cmd.toAscii()); + } + Gui::Command::commitCommand(); + return true; +} + +bool HypothesisWidget::reject() +{ + return true; +} + +void HypothesisWidget::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } +} + +// ----------------------------------------------- + +TaskHypothesis::TaskHypothesis() +{ + widget = new HypothesisWidget(); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), + widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskHypothesis::~TaskHypothesis() +{ +} + +void TaskHypothesis::open() +{ +} + +bool TaskHypothesis::accept() +{ + try { + return widget->accept(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + return false; + } + catch (...) { + Base::Console().Error("Unknown error\n"); + return false; + } +} + +bool TaskHypothesis::reject() +{ + return widget->reject(); +} + +#include "moc_Hypothesis.cpp" diff --git a/src/Mod/Fem/Gui/Hypothesis.h b/src/Mod/Fem/Gui/Hypothesis.h new file mode 100644 index 0000000000..c3edfe9bfd --- /dev/null +++ b/src/Mod/Fem/Gui/Hypothesis.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (c) 2012 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 * + * * + ***************************************************************************/ + + +#ifndef FEMGUI_HYPOTHESIS_H +#define FEMGUI_HYPOTHESIS_H + +#include +#include + +namespace FemGui { + +class Ui_HypothesisWidget; +class HypothesisWidget : public QWidget +{ + Q_OBJECT + +public: + HypothesisWidget(QWidget* parent = 0); + ~HypothesisWidget(); + bool accept(); + bool reject(); + +private: + void changeEvent(QEvent *e); + +private: + Ui_HypothesisWidget* ui; +}; + +class TaskHypothesis : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskHypothesis(); + ~TaskHypothesis(); + +public: + void open(); + bool accept(); + bool reject(); + + QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + bool needsFullSpace() const + { return true; } + +private: + HypothesisWidget* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace FemGui + +#endif // FEMGUI_HYPOTHESIS_H diff --git a/src/Mod/Fem/Gui/Hypothesis.ui b/src/Mod/Fem/Gui/Hypothesis.ui new file mode 100644 index 0000000000..c5ecd67d2c --- /dev/null +++ b/src/Mod/Fem/Gui/Hypothesis.ui @@ -0,0 +1,166 @@ + + + FemGui::HypothesisWidget + + + + 0 + 0 + 299 + 238 + + + + Hypothesis + + + + + + + + Quadrangle + + + true + + + + + + + Maximum length + + + true + + + + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Local length + + + true + + + + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Maximum element area + + + true + + + + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + + Qt::Vertical + + + + 20 + 65 + + + + + + + + quadPref + maxLength + valMaxLength + localLength + valLocalLength + maxArea + valMaxArea + + + + + maxLength + toggled(bool) + valMaxLength + setEnabled(bool) + + + 73 + 92 + + + 172 + 88 + + + + + localLength + toggled(bool) + valLocalLength + setEnabled(bool) + + + 44 + 116 + + + 186 + 118 + + + + + maxArea + toggled(bool) + valMaxArea + setEnabled(bool) + + + 61 + 144 + + + 197 + 145 + + + + + diff --git a/src/Mod/Fem/Gui/Makefile.am b/src/Mod/Fem/Gui/Makefile.am index 6a009e648e..8c54a61947 100644 --- a/src/Mod/Fem/Gui/Makefile.am +++ b/src/Mod/Fem/Gui/Makefile.am @@ -2,9 +2,15 @@ SUBDIRS=Resources lib_LTLIBRARIES=libFemGui.la FemGui.la +BUILT_SOURCES=\ + ui_Hypothesis.h \ + moc_Hypothesis.cpp + libFemGui_la_SOURCES=\ AppFemGuiPy.cpp \ Command.cpp \ + Hypothesis.cpp \ + Hypothesis.h \ PreCompiled.cpp \ PreCompiled.h \ ViewProviderFemMesh.cpp \ @@ -78,5 +84,6 @@ libdir = $(prefix)/Mod/Fem CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = \ - CMakeLists.txt + CMakeLists.txt \ + Hypothesis.ui diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index 660112d807..db072a5bfd 100644 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -10,6 +10,7 @@ translations/Fem_it.qm translations/Fem_nl.qm translations/Fem_no.qm + translations/Fem_pl.qm translations/Fem_pt.qm translations/Fem_ru.qm translations/Fem_se.qm diff --git a/src/Mod/Fem/Gui/Resources/Makefile.am b/src/Mod/Fem/Gui/Resources/Makefile.am index f915bc77ed..742affb819 100644 --- a/src/Mod/Fem/Gui/Resources/Makefile.am +++ b/src/Mod/Fem/Gui/Resources/Makefile.am @@ -26,6 +26,8 @@ EXTRA_DIST = \ translations/Fem_nl.ts \ translations/Fem_no.qm \ translations/Fem_no.ts \ + translations/Fem_pl.qm \ + translations/Fem_pl.ts \ translations/Fem_pt.qm \ translations/Fem_pt.ts \ translations/Fem_ru.qm \ diff --git a/src/Mod/Fem/Init.py b/src/Mod/Fem/Init.py index c14018810d..c8b99743d8 100644 --- a/src/Mod/Fem/Init.py +++ b/src/Mod/Fem/Init.py @@ -45,4 +45,4 @@ ParGrp = App.ParamGet("System parameter:Modules").GetGroup("Fem") FreeCAD.addExportType("TetGen file (*.poly)","convert2TetGen") FreeCAD.addImportType("FEM formats (*.unv *.med *.dat *.bdf)","Fem") -FreeCAD.addExportType("FEM formats (*.unv *.med *.dat)","Fem") +FreeCAD.addExportType("FEM formats (*.unv *.med *.dat *.inp)","Fem") diff --git a/src/Mod/Image/Gui/Makefile.am b/src/Mod/Image/Gui/Makefile.am index 0d09c514a3..b24c50a5c6 100644 --- a/src/Mod/Image/Gui/Makefile.am +++ b/src/Mod/Image/Gui/Makefile.am @@ -107,6 +107,8 @@ EXTRA_DIST = \ Resources/translations/Image_nl.ts \ Resources/translations/Image_no.qm \ Resources/translations/Image_no.ts \ + Resources/translations/Image_pl.qm \ + Resources/translations/Image_pl.ts \ Resources/translations/Image_pt.qm \ Resources/translations/Image_pt.ts \ Resources/translations/Image_ru.qm \ diff --git a/src/Mod/Image/Gui/Resources/Image.qrc b/src/Mod/Image/Gui/Resources/Image.qrc index fd16dcdfab..41122d6b2a 100644 --- a/src/Mod/Image/Gui/Resources/Image.qrc +++ b/src/Mod/Image/Gui/Resources/Image.qrc @@ -10,6 +10,7 @@ translations/Image_it.qm translations/Image_nl.qm translations/Image_no.qm + translations/Image_pl.qm translations/Image_pt.qm translations/Image_ru.qm translations/Image_se.qm diff --git a/src/Mod/Makefile.am b/src/Mod/Makefile.am index 7fe7c39734..bc7e873c54 100644 --- a/src/Mod/Makefile.am +++ b/src/Mod/Makefile.am @@ -31,10 +31,18 @@ SUBDIRS += ReverseEngineering MeshPart Fem Inspection endif #endif +if BUILD_ASSEMBLY +SUBDIRS += Assembly +endif + if BUILD_SANDBOX SUBDIRS += Sandbox endif +if BUILD_CAM +SUBDIRS += Cam +endif + EXTRA_DIST = \ __init__.py \ CMakeLists.txt \ diff --git a/src/Mod/Mesh/App/CMakeLists.txt b/src/Mod/Mesh/App/CMakeLists.txt index ee813be7bc..97e2856804 100644 --- a/src/Mod/Mesh/App/CMakeLists.txt +++ b/src/Mod/Mesh/App/CMakeLists.txt @@ -1,20 +1,26 @@ if(WIN32) - add_definitions(-DFCAppMesh -DWM4_FOUNDATION_DLL_EXPORT) + add_definitions(-DFCAppMesh -DWM4_FOUNDATION_DLL_EXPORT -DEIGEN2_SUPPORT) +else (Win32) + add_definitions(-DEIGEN2_SUPPORT) endif(WIN32) include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src/3rdParty ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_PATH} ${XERCESC_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} - ${EIGEN2_INCLUDE_DIR} + ${EIGEN3_INCLUDE_DIR} ) set(Mesh_LIBS ${Boost_LIBRARIES} + ${QT_QTCORE_LIBRARY} + ${QT_QTCORE_LIBRARY_DEBUG} FreeCADBase FreeCADApp ) @@ -41,6 +47,8 @@ SET(Core_SRCS Core/Approximation.h Core/Builder.cpp Core/Builder.h + Core/Curvature.cpp + Core/Curvature.h Core/Definitions.cpp Core/Definitions.h Core/Degeneration.cpp @@ -61,6 +69,8 @@ SET(Core_SRCS Core/MeshKernel.h Core/Projection.cpp Core/Projection.h + Core/Segmentation.cpp + Core/Segmentation.h Core/SetOperations.cpp Core/SetOperations.h Core/Smoothing.cpp diff --git a/src/Mod/Mesh/App/Core/Algorithm.cpp b/src/Mod/Mesh/App/Core/Algorithm.cpp index 40d4907d4a..281fba7f7a 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.cpp +++ b/src/Mod/Mesh/App/Core/Algorithm.cpp @@ -1156,7 +1156,6 @@ void MeshAlgorithm::CheckFacets(const Base::ViewProjMethod* pclProj, const Base: { const MeshPointArray& p = _rclMesh.GetPoints(); const MeshFacetArray& f = _rclMesh.GetFacets(); - Base::SequencerLauncher seq("Check facets", f.size()); Base::Vector3f pt2d; unsigned long index=0; for (MeshFacetArray::_TConstIterator it = f.begin(); it != f.end(); ++it,++index) { @@ -1167,7 +1166,6 @@ void MeshAlgorithm::CheckFacets(const Base::ViewProjMethod* pclProj, const Base: break; } } - seq.next(); } } @@ -1743,47 +1741,38 @@ std::set MeshRefPointToFacets::NeighbourPoints(const std::vector< return nb; } -// ermittelt alle Nachbarn zum Facet deren Schwerpunkt unterhalb der mpx. Distanz befindet. -// Facet deren VISIT-Flag gesetzt ist werden nicht beruecksichtig. -/// @todo -void MeshRefPointToFacets::Neighbours (unsigned long ulFacetInd, float fMpxDist, std::vector &rclNb) +void MeshRefPointToFacets::Neighbours (unsigned long ulFacetInd, float fMaxDist, MeshCollector& collect) const { - rclNb.clear(); + std::set visited; Base::Vector3f clCenter = _rclMesh.GetFacet(ulFacetInd).GetGravityPoint(); const MeshFacetArray& rFacets = _rclMesh.GetFacets(); - SearchNeighbours(rFacets.begin() + ulFacetInd, clCenter, fMpxDist * fMpxDist, rclNb); - - for (std::vector::iterator i = rclNb.begin(); i != rclNb.end(); i++) - (*i)->ResetFlag(MeshFacet::VISIT); + SearchNeighbours(rFacets, ulFacetInd, clCenter, fMaxDist * fMaxDist, visited, collect); } -/// @todo -void MeshRefPointToFacets::SearchNeighbours(MeshFacetArray::_TConstIterator f_it, const Base::Vector3f &rclCenter, float fMpxDist, std::vector &rclNb) +void MeshRefPointToFacets::SearchNeighbours(const MeshFacetArray& rFacets, unsigned long index, const Base::Vector3f &rclCenter, + float fMaxDist2, std::set& visited, MeshCollector& collect) const { - if (f_it->IsFlag(MeshFacet::VISIT) == true) + if (visited.find(index) != visited.end()) return; - if (Base::DistanceP2(rclCenter, _rclMesh.GetFacet(*f_it).GetGravityPoint()) > fMpxDist) + const MeshFacet& face = rFacets[index]; + if (Base::DistanceP2(rclCenter, _rclMesh.GetFacet(face).GetGravityPoint()) > fMaxDist2) return; - rclNb.push_back(f_it); - f_it->SetFlag(MeshFacet::VISIT); - - MeshPointArray::_TConstIterator p_beg = _rclMesh.GetPoints().begin(); - MeshFacetArray::_TConstIterator f_beg = _rclMesh.GetFacets().begin(); - + visited.insert(index); + collect.Append(_rclMesh, index); for (int i = 0; i < 3; i++) { - const std::set &f = (*this)[f_it->_aulPoints[i]]; + const std::set &f = (*this)[face._aulPoints[i]]; for (std::set::const_iterator j = f.begin(); j != f.end(); ++j) { - SearchNeighbours(f_beg+*j, rclCenter, fMpxDist, rclNb); + SearchNeighbours(rFacets, *j, rclCenter, fMaxDist2, visited, collect); } } } MeshFacetArray::_TConstIterator -MeshRefPointToFacets::getFacet (unsigned long index) const +MeshRefPointToFacets::GetFacet (unsigned long index) const { return _rclMesh.GetFacets().begin() + index; } diff --git a/src/Mod/Mesh/App/Core/Algorithm.h b/src/Mod/Mesh/App/Core/Algorithm.h index 9baa667e21..78a4caf5b7 100644 --- a/src/Mod/Mesh/App/Core/Algorithm.h +++ b/src/Mod/Mesh/App/Core/Algorithm.h @@ -310,6 +310,43 @@ protected: const MeshKernel &_rclMesh; /**< The mesh kernel. */ }; +class MeshExport MeshCollector +{ +public: + MeshCollector(){} + virtual void Append(const MeshCore::MeshKernel&, unsigned long index) = 0; +}; + +class MeshExport PointCollector : public MeshCollector +{ +public: + PointCollector(std::vector& ind) : indices(ind){} + virtual void Append(const MeshCore::MeshKernel& kernel, unsigned long index) + { + unsigned long ulP1, ulP2, ulP3; + kernel.GetFacetPoints(index, ulP1, ulP2, ulP3); + indices.push_back(ulP1); + indices.push_back(ulP2); + indices.push_back(ulP3); + } + +private: + std::vector& indices; +}; + +class MeshExport FacetCollector : public MeshCollector +{ +public: + FacetCollector(std::vector& ind) : indices(ind){} + void Append(const MeshCore::MeshKernel&, unsigned long index) + { + indices.push_back(index); + } + +private: + std::vector& indices; +}; + /** * The MeshRefPointToFacets builds up a structure to have access to all facets indexing * a point. @@ -329,14 +366,14 @@ public: /// Rebuilds up data structure void Rebuild (void); const std::set& operator[] (unsigned long) const; - MeshFacetArray::_TConstIterator getFacet (unsigned long) const; + MeshFacetArray::_TConstIterator GetFacet (unsigned long) const; std::set NeighbourPoints(const std::vector& , int level) const; - void Neighbours (unsigned long ulFacetInd, float fMaxDist, std::vector &rclNb); + void Neighbours (unsigned long ulFacetInd, float fMaxDist, MeshCollector& collect) const; Base::Vector3f GetNormal(unsigned long) const; protected: - void SearchNeighbours(MeshFacetArray::_TConstIterator pFIter, const Base::Vector3f &rclCenter, - float fMaxDist, std::vector &rclNb); + void SearchNeighbours(const MeshFacetArray& rFacets, unsigned long index, const Base::Vector3f &rclCenter, + float fMaxDist, std::set &visit, MeshCollector& collect) const; protected: const MeshKernel &_rclMesh; /**< The mesh kernel. */ diff --git a/src/Mod/Mesh/App/Core/Approximation.cpp b/src/Mod/Mesh/App/Core/Approximation.cpp index ace1a796e3..15b0c522f5 100644 --- a/src/Mod/Mesh/App/Core/Approximation.cpp +++ b/src/Mod/Mesh/App/Core/Approximation.cpp @@ -37,6 +37,7 @@ #include //#define FC_USE_EIGEN +//#define FC_USE_BOOST #if defined(FC_USE_BOOST) #include #include @@ -54,25 +55,26 @@ extern "C" void LAPACK_DGESV (int const* n, int const* nrhs, #elif defined(FC_USE_EIGEN) # include #endif +# include using namespace MeshCore; -void Approximation::Convert( const Wm4::Vector3& Wm4, Base::Vector3f& pt) +void Approximation::Convert( const Wm4::Vector3& Wm4, Base::Vector3f& pt) { - pt.Set( Wm4.X(), Wm4.Y(), Wm4.Z() ); + pt.Set( (float)Wm4.X(), (float)Wm4.Y(), (float)Wm4.Z() ); } -void Approximation::Convert( const Base::Vector3f& pt, Wm4::Vector3& Wm4) +void Approximation::Convert( const Base::Vector3f& pt, Wm4::Vector3& Wm4) { Wm4.X() = pt.x; Wm4.Y() = pt.y; Wm4.Z() = pt.z; } -void Approximation::GetMgcVectorArray(std::vector< Wm4::Vector3 >& rcPts) const +void Approximation::GetMgcVectorArray(std::vector< Wm4::Vector3 >& rcPts) const { std::list< Base::Vector3f >::const_iterator It; for (It = _vPoints.begin(); It != _vPoints.end(); ++It) { - Wm4::Vector3 pt( (*It).x, (*It).y, (*It).z ); + Wm4::Vector3 pt( (*It).x, (*It).y, (*It).z ); rcPts.push_back( pt ); } } @@ -176,7 +178,7 @@ float PlaneFit::Fit() int r = lapack::syev('V','U',A,eigenval,lapack::optimal_workspace()); if (r) { } - float sigma; + float sigma = 0; #elif defined(FC_USE_EIGEN) Eigen::Matrix3d covMat = Eigen::Matrix3d::Zero(); covMat(0,0) = sxx; @@ -360,17 +362,15 @@ void PlaneFit::ProjectToPlane () // ------------------------------------------------------------------------------- -float FunctionContainer::dKoeff[]; // Koeffizienten der Quadrik - -bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance) +bool QuadraticFit::GetCurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance) { assert( _bIsFitted ); bool bResult = false; if (_bIsFitted) { - Wm4::Vector3 Dir0, Dir1; + Wm4::Vector3 Dir0, Dir1; FunctionContainer clFuncCont( _fCoeff ); bResult = clFuncCont.CurvatureInfo( x, y, z, rfCurv0, rfCurv1, Dir0, Dir1, dDistance ); @@ -382,7 +382,7 @@ bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, return bResult; } -bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1) +bool QuadraticFit::GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1) { bool bResult = false; @@ -394,12 +394,12 @@ bool QuadraticFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, f return bResult; } -const float& QuadraticFit::GetCoeffArray() const +const double& QuadraticFit::GetCoeffArray() const { return _fCoeff[0]; } -float QuadraticFit::GetCoeff(unsigned long ulIndex) const +double QuadraticFit::GetCoeff(unsigned long ulIndex) const { assert( ulIndex >= 0 && ulIndex < 10 ); @@ -414,9 +414,9 @@ float QuadraticFit::Fit() float fResult = FLOAT_MAX; if (CountPoints() > 0) { - std::vector< Wm4::Vector3 > cPts; + std::vector< Wm4::Vector3 > cPts; GetMgcVectorArray( cPts ); - fResult = Wm4::QuadraticFit3( CountPoints(), &(cPts[0]), _fCoeff ); + fResult = Wm4::QuadraticFit3( CountPoints(), &(cPts[0]), _fCoeff ); _fLastResult = fResult; _bIsFitted = true; @@ -425,7 +425,7 @@ float QuadraticFit::Fit() return fResult; } -void QuadraticFit::CalcEigenValues(float &dLambda1, float &dLambda2, float &dLambda3, +void QuadraticFit::CalcEigenValues(double &dLambda1, double &dLambda2, double &dLambda3, Base::Vector3f &clEV1, Base::Vector3f &clEV2, Base::Vector3f &clEV3) const { assert( _bIsFitted ); @@ -451,16 +451,16 @@ void QuadraticFit::CalcEigenValues(float &dLambda1, float &dLambda2, float &dLam * */ - Wm4::Matrix3 akMat(_fCoeff[4], _fCoeff[7]/2.0f, _fCoeff[8]/2.0f, + Wm4::Matrix3 akMat(_fCoeff[4], _fCoeff[7]/2.0f, _fCoeff[8]/2.0f, _fCoeff[7]/2.0f, _fCoeff[5], _fCoeff[9]/2.0f, _fCoeff[8]/2.0f, _fCoeff[9]/2.0f, _fCoeff[6] ); - Wm4::Matrix3 rkRot, rkDiag; + Wm4::Matrix3 rkRot, rkDiag; akMat.EigenDecomposition( rkRot, rkDiag ); - Wm4::Vector3 vEigenU = rkRot.GetColumn(0); - Wm4::Vector3 vEigenV = rkRot.GetColumn(1); - Wm4::Vector3 vEigenW = rkRot.GetColumn(2); + Wm4::Vector3 vEigenU = rkRot.GetColumn(0); + Wm4::Vector3 vEigenV = rkRot.GetColumn(1); + Wm4::Vector3 vEigenW = rkRot.GetColumn(2); Convert( vEigenU, clEV1 ); Convert( vEigenV, clEV2 ); @@ -471,11 +471,11 @@ void QuadraticFit::CalcEigenValues(float &dLambda1, float &dLambda2, float &dLam dLambda3 = rkDiag[2][2]; } -void QuadraticFit::CalcZValues( float x, float y, float &dZ1, float &dZ2 ) const +void QuadraticFit::CalcZValues( double x, double y, double &dZ1, double &dZ2 ) const { assert( _bIsFitted ); - float dDisk = _fCoeff[3]*_fCoeff[3]+2*_fCoeff[3]*_fCoeff[8]*x+2*_fCoeff[3]*_fCoeff[9]*y+ + double dDisk = _fCoeff[3]*_fCoeff[3]+2*_fCoeff[3]*_fCoeff[8]*x+2*_fCoeff[3]*_fCoeff[9]*y+ _fCoeff[8]*_fCoeff[8]*x*x+2*_fCoeff[8]*x*_fCoeff[9]*y+_fCoeff[9]*_fCoeff[9]*y*y- 4*_fCoeff[6]*_fCoeff[0]-4*_fCoeff[6]*_fCoeff[1]*x-4*_fCoeff[6]*_fCoeff[2]*y- 4*_fCoeff[6]*_fCoeff[7]*x*y-4*_fCoeff[6]*_fCoeff[4]*x*x-4*_fCoeff[6]*_fCoeff[5]*y*y; @@ -494,8 +494,8 @@ void QuadraticFit::CalcZValues( float x, float y, float &dZ1, float &dZ2 ) const else dDisk = sqrt( dDisk ); - dZ1 = 0.5f * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y + dDisk ) / _fCoeff[6] ); - dZ2 = 0.5f * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y - dDisk ) / _fCoeff[6] ); + dZ1 = 0.5 * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y + dDisk ) / _fCoeff[6] ); + dZ2 = 0.5 * ( ( -_fCoeff[3] - _fCoeff[8]*x - _fCoeff[9]*y - dDisk ) / _fCoeff[6] ); } // ------------------------------------------------------------------------------- @@ -529,13 +529,13 @@ float SurfaceFit::Fit() return fResult; } -bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance ) +bool SurfaceFit::GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance ) { bool bResult = false; if (_bIsFitted) { - Wm4::Vector3 Dir0, Dir1; + Wm4::Vector3 Dir0, Dir1; FunctionContainer clFuncCont( _fCoeff ); bResult = clFuncCont.CurvatureInfo( x, y, z, rfCurv0, rfCurv1, Dir0, Dir1, dDistance ); @@ -547,7 +547,7 @@ bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, flo return bResult; } -bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1) +bool SurfaceFit::GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1) { assert( _bIsFitted ); bool bResult = false; @@ -560,18 +560,17 @@ bool SurfaceFit::GetCurvatureInfo(float x, float y, float z, float &rfCurv0, flo return bResult; } -float SurfaceFit::PolynomFit() +double SurfaceFit::PolynomFit() { if (PlaneFit::Fit() == FLOAT_MAX) return FLOAT_MAX; -#if 0 -#if defined(FC_USE_BOOST) Base::Vector3d bs(this->_vBase.x,this->_vBase.y,this->_vBase.z); Base::Vector3d ex(this->_vDirU.x,this->_vDirU.y,this->_vDirU.z); Base::Vector3d ey(this->_vDirV.x,this->_vDirV.y,this->_vDirV.z); Base::Vector3d ez(this->_vDirW.x,this->_vDirW.y,this->_vDirW.z); +#if defined(FC_USE_BOOST) ublas::matrix A(6,6); ublas::vector b(6); for (int i=0; i<6; i++) { @@ -580,6 +579,11 @@ float SurfaceFit::PolynomFit() } b(i) = 0.0; } +#else + Eigen::Matrix A = Eigen::Matrix::Zero(); + Eigen::Matrix b = Eigen::Matrix::Zero(); + Eigen::Matrix x = Eigen::Matrix::Zero(); +#endif for (std::list::const_iterator it = _vPoints.begin(); it != _vPoints.end(); it++) { Base::Vector3d clPoint(it->x,it->y,it->z); @@ -648,29 +652,34 @@ float SurfaceFit::PolynomFit() A(5,4) = A(4,5); - +#if defined(FC_USE_BOOST) namespace lapack= boost::numeric::bindings::lapack; //std::clog << A << std::endl; //std::clog << b << std::endl; - lapack::gesv(A,b); + //lapack::gesv(A,b); + ublas::vector x(6); + x = b; //std::clog << b << std::endl; +#else + // A.llt().solve(b,&x); // not sure if always positive definite + A.qr().solve(b,&x); +#endif - _fCoeff[0] = (float)(-b(5)); - _fCoeff[1] = (float)(-b(3)); - _fCoeff[2] = (float)(-b(4)); + _fCoeff[0] = (float)(-x(5)); + _fCoeff[1] = (float)(-x(3)); + _fCoeff[2] = (float)(-x(4)); _fCoeff[3] = 1.0f; - _fCoeff[4] = (float)(-b(0)); - _fCoeff[5] = (float)(-b(1)); + _fCoeff[4] = (float)(-x(0)); + _fCoeff[5] = (float)(-x(1)); _fCoeff[6] = 0.0f; - _fCoeff[7] = (float)(-b(2)); + _fCoeff[7] = (float)(-x(2)); _fCoeff[8] = 0.0f; _fCoeff[9] = 0.0f; -#endif -#endif + return 0.0f; } -float SurfaceFit::Value(float x, float y) const +double SurfaceFit::Value(double x, double y) const { float z = 0.0f; if (_bIsFitted) { diff --git a/src/Mod/Mesh/App/Core/Approximation.h b/src/Mod/Mesh/App/Core/Approximation.h index 74124f35eb..623a17daca 100644 --- a/src/Mod/Mesh/App/Core/Approximation.h +++ b/src/Mod/Mesh/App/Core/Approximation.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,64 @@ #include #include -namespace MeshCore { +namespace Wm4 +{ +/** + * An implicit surface is defined by F(x,y,z) = 0. + * This polynomial surface is actually defined as z = f(x,y) = ax^2 + by^2 + cx + dy + exy + g. + * To use Wm3 routines for implicit surfaces we can write the surface also as F(x,y,z) = f(x,y) - z = 0. + * @author Werner Mayer + */ +template +class PolynomialSurface : public ImplicitSurface +{ +public: + PolynomialSurface (const Real afCoeff[6]) + { for (int i=0; i<6; i++) m_afCoeff[i] = afCoeff[i]; } + + virtual ~PolynomialSurface () {} + + // the function + virtual Real F (const Vector3& rkP) const + { + return ( m_afCoeff[0]*rkP.X()*rkP.X() + + m_afCoeff[1]*rkP.Y()*rkP.Y() + + m_afCoeff[2]*rkP.X() + + m_afCoeff[3]*rkP.Y() + + m_afCoeff[4]*rkP.X()*rkP.Y() + + m_afCoeff[5]-rkP.Z()) ; + } + + // first-order partial derivatives + virtual Real FX (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[0]*rkP.X() + m_afCoeff[2] + m_afCoeff[4]*rkP.Y()); } + virtual Real FY (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[1]*rkP.Y() + m_afCoeff[3] + m_afCoeff[4]*rkP.X()); } + virtual Real FZ (const Vector3& rkP) const + { return (Real)-1.0; } + + // second-order partial derivatives + virtual Real FXX (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[0]); } + virtual Real FXY (const Vector3& rkP) const + { return (Real)(m_afCoeff[4]); } + virtual Real FXZ (const Vector3& rkP) const + { return (Real)0.0; } + virtual Real FYY (const Vector3& rkP) const + { return (Real)(2.0*m_afCoeff[1]); } + virtual Real FYZ (const Vector3& rkP) const + { return (Real)0.0; } + virtual Real FZZ (const Vector3& rkP) const + { return (Real)0.0; } + +protected: + Real m_afCoeff[6]; +}; + +} + +namespace MeshCore { /** * Abstract base class for approximation of a geometry to a given set of points. @@ -104,15 +161,15 @@ protected: /** * Converts point from Wm4::Vector3 to Base::Vector3f. */ - static void Convert( const Wm4::Vector3&, Base::Vector3f&); + static void Convert( const Wm4::Vector3&, Base::Vector3f&); /** * Converts point from Base::Vector3f to Wm4::Vector3. */ - static void Convert( const Base::Vector3f&, Wm4::Vector3&); + static void Convert( const Base::Vector3f&, Wm4::Vector3&); /** * Creates a vector of Wm4::Vector3 elements. */ - void GetMgcVectorArray( std::vector< Wm4::Vector3 >& rcPts ) const; + void GetMgcVectorArray( std::vector< Wm4::Vector3 >& rcPts ) const; protected: std::list< Base::Vector3f > _vPoints; /**< Holds the points for the fit algorithm. */ @@ -201,22 +258,22 @@ public: /** * bertragen der Quadric-Koeffizienten * @param ulIndex Nummer des Koeffizienten (0..9) - * @return float Wert des Koeffizienten + * @return double Wert des Koeffizienten */ - float GetCoeff(unsigned long ulIndex) const; + double GetCoeff(unsigned long ulIndex) const; /** * bertragen der Koeffizientan als Referenz * auf das interne Array - * @return const float& Referenz auf das float-Array + * @return const double& Referenz auf das double-Array */ - const float& GetCoeffArray() const; + const double& GetCoeffArray() const; /** * Aufruf des Fit-Algorithmus * @return float Qualitt des Fits. */ float Fit(); - void CalcZValues(float x, float y, float &dZ1, float &dZ2) const; + void CalcZValues(double x, double y, double &dZ1, double &dZ2) const; /** * Berechnen der Krmmungswerte der Quadric in einem bestimmten Punkt. * @param x X-Koordinate @@ -229,12 +286,12 @@ public: * @param dDistance * @return bool Fehlerfreie Ausfrhung = true, ansonsten false */ - bool GetCurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance); + bool GetCurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance); - bool GetCurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfcurv1); + bool GetCurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfcurv1); /** * Aufstellen der Formanmatrix A und Berechnen der Eigenwerte. * @param dLambda1 Eigenwert 1 @@ -244,11 +301,11 @@ public: * @param clEV2 Eigenvektor 2 * @param clEV3 Eigenvektor 3 */ - void CalcEigenValues(float &dLambda1, float &dLambda2, float &dLambda3, + void CalcEigenValues(double &dLambda1, double &dLambda2, double &dLambda3, Base::Vector3f &clEV1, Base::Vector3f &clEV2, Base::Vector3f &clEV3) const; protected: - float _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ + double _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ }; // ------------------------------------------------------------------------------- @@ -275,15 +332,15 @@ public: */ virtual ~SurfaceFit(){}; - bool GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfCurv1, - Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, float &dDistance); - bool GetCurvatureInfo(float x, float y, float z, float &rfCurv0, float &rfcurv1); + bool GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfCurv1, + Base::Vector3f &rkDir0, Base::Vector3f &rkDir1, double &dDistance); + bool GetCurvatureInfo(double x, double y, double z, double &rfCurv0, double &rfcurv1); float Fit(); - float Value(float x, float y) const; + double Value(double x, double y) const; protected: - float PolynomFit(); - float _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ + double PolynomFit(); + double _fCoeff[ 10 ]; /**< Ziel der Koeffizienten aus dem Fit */ }; // ------------------------------------------------------------------------------- @@ -300,42 +357,24 @@ public: * Die MGC-Algorithmen arbeiten mit Funktionen dieses * Types */ - typedef float (*Function)(float,float,float); + typedef double (*Function)(double,double,double); /** * Der parametrisierte Konstruktor. Erwartet ein Array * mit den Quadric-Koeffizienten. * @param pKoef Zeiger auf die Quadric-Parameter - * (float [10]) + * (double [10]) */ - FunctionContainer(const float *pKoef) + FunctionContainer(const double *pKoef) { Assign( pKoef ); -/* - Function oF; - Function aoDF[3]; - Function aoD2F[6]; - - oF = &F; - aoDF[0] = &Fx; - aoDF[1] = &Fy; - aoDF[2] = &Fz; - aoD2F[0] = &Fxx; - aoD2F[1] = &Fxy; - aoD2F[2] = &Fxz; - aoD2F[3] = &Fyy; - aoD2F[4] = &Fyz; - aoD2F[5] = &Fzz; - - pImplSurf = new Wm4::QuadricSurface( oF, aoDF, aoD2F );*/ - - pImplSurf = new Wm4::QuadricSurface( dKoeff ); + pImplSurf = new Wm4::QuadricSurface( dKoeff ); } /** * bernehmen der Quadric-Parameter * @param pKoef Zeiger auf die Quadric-Parameter - * (doube [10]) + * (double [10]) */ - void Assign( const float *pKoef ) + void Assign( const double *pKoef ) { for (long ct=0; ct < 10; ct++) dKoeff[ ct ] = pKoef[ ct ]; @@ -344,13 +383,13 @@ public: * Destruktor. Lscht die ImpicitSurface Klasse * der MGC-Bibliothek wieder */ - virtual ~FunctionContainer(){ delete pImplSurf; } + ~FunctionContainer(){ delete pImplSurf; } /** * Zugriff auf die Koeffizienten der Quadric * @param idx Index des Parameters - * @return float& Der Koeffizient + * @return double& Der Koeffizient */ - float& operator[](int idx){ return dKoeff[ idx ]; } + double& operator[](int idx){ return dKoeff[ idx ]; } /** * Redirector auf eine Methode der MGC Bibliothek. Ermittelt * die Hauptkrmmungen und ihre Richtungen im angegebenen Punkt. @@ -364,22 +403,22 @@ public: * @param dDistance Ergebnis das die Entfernung des Punktes von der Quadrik angibt. * @return bool Fehlerfreie Ausfrhung = true, ansonsten false */ - bool CurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1, - Wm4::Vector3 &rkDir0, Wm4::Vector3 &rkDir1, float &dDistance) + bool CurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1, + Wm4::Vector3 &rkDir0, Wm4::Vector3 &rkDir1, double &dDistance) { - return pImplSurf->ComputePrincipalCurvatureInfo( Wm4::Vector3(x, y, z),rfCurv0, rfCurv1, rkDir0, rkDir1 ); + return pImplSurf->ComputePrincipalCurvatureInfo( Wm4::Vector3(x, y, z),rfCurv0, rfCurv1, rkDir0, rkDir1 ); } - Base::Vector3f GetGradient( float x, float y, float z ) const + Base::Vector3f GetGradient( double x, double y, double z ) const { - Wm4::Vector3 grad = pImplSurf->GetGradient( Wm4::Vector3(x, y, z) ); + Wm4::Vector3 grad = pImplSurf->GetGradient( Wm4::Vector3(x, y, z) ); return Base::Vector3f( grad.X(), grad.Y(), grad.Z() ); } - Base::Matrix4D GetHessian( float x, float y, float z ) const + Base::Matrix4D GetHessian( double x, double y, double z ) const { - Wm4::Matrix3 hess = pImplSurf->GetHessian( Wm4::Vector3(x, y, z) ); + Wm4::Matrix3 hess = pImplSurf->GetHessian( Wm4::Vector3(x, y, z) ); Base::Matrix4D cMat; cMat.setToUnity(); cMat[0][0] = hess[0][0]; cMat[0][1] = hess[0][1]; cMat[0][2] = hess[0][2]; cMat[1][0] = hess[1][0]; cMat[1][1] = hess[1][1]; cMat[1][2] = hess[1][2]; @@ -387,23 +426,23 @@ public: return cMat; } - bool CurvatureInfo(float x, float y, float z, - float &rfCurv0, float &rfCurv1) + bool CurvatureInfo(double x, double y, double z, + double &rfCurv0, double &rfCurv1) { - float dQuot = Fz(x,y,z); - float zx = - ( Fx(x,y,z) / dQuot ); - float zy = - ( Fy(x,y,z) / dQuot ); + double dQuot = Fz(x,y,z); + double zx = - ( Fx(x,y,z) / dQuot ); + double zy = - ( Fy(x,y,z) / dQuot ); - float zxx = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zx * zx + dKoeff[8] * zx ) ) / dQuot; - float zyy = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zy * zy + dKoeff[9] * zy ) ) / dQuot; - float zxy = - ( dKoeff[6] * zx * zy + dKoeff[7] + dKoeff[8] * zy + dKoeff[9] * zx ) / dQuot; + double zxx = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zx * zx + dKoeff[8] * zx ) ) / dQuot; + double zyy = - ( 2.0f * ( dKoeff[5] + dKoeff[6] * zy * zy + dKoeff[9] * zy ) ) / dQuot; + double zxy = - ( dKoeff[6] * zx * zy + dKoeff[7] + dKoeff[8] * zy + dKoeff[9] * zx ) / dQuot; - float dNen = 1 + zx*zx + zy*zy; - float dNenSqrt = (float)sqrt( dNen ); - float K = ( zxx * zyy - zxy * zxy ) / ( dNen * dNen ); - float H = 0.5f * ( ( 1.0f+zx*zx - 2*zx*zy*zxy + (1.0f+zy*zy)*zxx ) / ( dNenSqrt * dNenSqrt * dNenSqrt ) ) ; + double dNen = 1 + zx*zx + zy*zy; + double dNenSqrt = (double)sqrt( dNen ); + double K = ( zxx * zyy - zxy * zxy ) / ( dNen * dNen ); + double H = 0.5f * ( ( 1.0f+zx*zx - 2*zx*zy*zxy + (1.0f+zy*zy)*zxx ) / ( dNenSqrt * dNenSqrt * dNenSqrt ) ) ; - float dDiscr = (float)sqrt(fabs(H*H-K)); + double dDiscr = (double)sqrt(fabs(H*H-K)); rfCurv0 = H - dDiscr; rfCurv1 = H + dDiscr; @@ -411,7 +450,7 @@ public: } //+++++++++ Quadric +++++++++++++++++++++++++++++++++++++++ - static float F ( float x, float y, float z ) + double F ( double x, double y, double z ) { return (dKoeff[0] + dKoeff[1]*x + dKoeff[2]*y + dKoeff[3]*z + dKoeff[4]*x*x + dKoeff[5]*y*y + dKoeff[6]*z*z + @@ -419,48 +458,48 @@ public: } //+++++++++ 1. derivations ++++++++++++++++++++++++++++++++ - static float Fx ( float x, float y, float z ) + double Fx ( double x, double y, double z ) { return( dKoeff[1] + 2.0f*dKoeff[4]*x + dKoeff[7]*y + dKoeff[8]*z ); } - static float Fy ( float x, float y, float z ) + double Fy ( double x, double y, double z ) { return( dKoeff[2] + 2.0f*dKoeff[5]*y + dKoeff[7]*x + dKoeff[9]*z ); } - static float Fz ( float x, float y, float z ) + double Fz ( double x, double y, double z ) { return( dKoeff[3] + 2.0f*dKoeff[6]*z + dKoeff[8]*x + dKoeff[9]*y ); } //+++++++++ 2. derivations ++++++++++++++++++++++++++++++++ - static float Fxx( float x, float y, float z ) + double Fxx( double x, double y, double z ) { return( 2.0f*dKoeff[4] ); } - static float Fxy( float x, float y, float z ) + double Fxy( double x, double y, double z ) { return( dKoeff[7] ); } - static float Fxz( float x, float y, float z ) + double Fxz( double x, double y, double z ) { return( dKoeff[8] ); } - static float Fyy( float x, float y, float z ) + double Fyy( double x, double y, double z ) { return( 2.0f*dKoeff[5] ); } - static float Fyz( float x, float y, float z ) + double Fyz( double x, double y, double z ) { return( dKoeff[9] ); } - static float Fzz( float x, float y, float z ) + double Fzz( double x, double y, double z ) { return( 2.0f*dKoeff[6] ); } protected: - static float dKoeff[ 10 ]; /**< Koeffizienten der Quadric */ - Wm4::ImplicitSurface *pImplSurf; /**< Zugriff auf die MGC-Bibliothek */ + double dKoeff[ 10 ]; /**< Koeffizienten der Quadric */ + Wm4::ImplicitSurface *pImplSurf; /**< Zugriff auf die MGC-Bibliothek */ private: /** diff --git a/src/Mod/Mesh/App/Core/Curvature.cpp b/src/Mod/Mesh/App/Core/Curvature.cpp new file mode 100644 index 0000000000..d0371da4b8 --- /dev/null +++ b/src/Mod/Mesh/App/Core/Curvature.cpp @@ -0,0 +1,236 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * 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 +#include + +#include +#include + +#include "Curvature.h" +#include "Algorithm.h" +#include "Approximation.h" +#include "MeshKernel.h" +#include "Iterator.h" +#include "Tools.h" +#include +#include + +using namespace MeshCore; + +MeshCurvature::MeshCurvature(const MeshKernel& kernel) + : myKernel(kernel), myMinPoints(20), myRadius(0.5f) +{ + mySegment.resize(kernel.CountFacets()); + std::generate(mySegment.begin(), mySegment.end(), Base::iotaGen(0)); +} + +MeshCurvature::MeshCurvature(const MeshKernel& kernel, const std::vector& segm) + : myKernel(kernel), myMinPoints(20), myRadius(0.5f), mySegment(segm) +{ +} + +void MeshCurvature::ComputePerFace(bool parallel) +{ + Base::Vector3f rkDir0, rkDir1, rkPnt; + Base::Vector3f rkNormal; + myCurvature.clear(); + MeshRefPointToFacets search(myKernel); + FacetCurvature face(myKernel, search, myRadius, myMinPoints); + + if (!parallel) { + Base::SequencerLauncher seq("Curvature estimation", mySegment.size()); + for (std::vector::iterator it = mySegment.begin(); it != mySegment.end(); ++it) { + CurvatureInfo info = face.Compute(*it); + myCurvature.push_back(info); + seq.next(); + } + } + else { + QFuture future = QtConcurrent::mapped + (mySegment, boost::bind(&FacetCurvature::Compute, &face, _1)); + QFutureWatcher watcher; + watcher.setFuture(future); + watcher.waitForFinished(); + for (QFuture::const_iterator it = future.begin(); it != future.end(); ++it) { + myCurvature.push_back(*it); + } + } +} + +void MeshCurvature::ComputePerVertex() +{ + myCurvature.clear(); + + // get all points + std::vector< Wm4::Vector3 > aPnts; + aPnts.reserve(myKernel.CountPoints()); + MeshPointIterator cPIt(myKernel); + for (cPIt.Init(); cPIt.More(); cPIt.Next()) { + Wm4::Vector3 cP(cPIt->x, cPIt->y, cPIt->z); + aPnts.push_back(cP); + } + + // get all point connections + std::vector aIdx; + aIdx.reserve(3*myKernel.CountFacets()); + const MeshFacetArray& raFts = myKernel.GetFacets(); + for (MeshFacetArray::const_iterator jt = raFts.begin(); jt != raFts.end(); ++jt) { + for (int i=0; i<3; i++) { + aIdx.push_back((int)jt->_aulPoints[i]); + } + } + + // compute vertex based curvatures + Wm4::MeshCurvature meshCurv(myKernel.CountPoints(), &(aPnts[0]), myKernel.CountFacets(), &(aIdx[0])); + + // get curvature information now + const Wm4::Vector3* aMaxCurvDir = meshCurv.GetMaxDirections(); + const Wm4::Vector3* aMinCurvDir = meshCurv.GetMinDirections(); + const double* aMaxCurv = meshCurv.GetMaxCurvatures(); + const double* aMinCurv = meshCurv.GetMinCurvatures(); + + myCurvature.reserve(myKernel.CountPoints()); + for (unsigned long i=0; i& ind) : indices(ind){} + virtual void Append(const MeshCore::MeshKernel& kernel, unsigned long index) + { + unsigned long ulP1, ulP2, ulP3; + kernel.GetFacetPoints(index, ulP1, ulP2, ulP3); + indices.insert(ulP1); + indices.insert(ulP2); + indices.insert(ulP3); + } + +private: + std::set& indices; +}; +} + +// -------------------------------------------------------- + +FacetCurvature::FacetCurvature(const MeshKernel& kernel, const MeshRefPointToFacets& search, float r, unsigned long pt) + : myKernel(kernel), mySearch(search), myRadius(r), myMinPoints(pt) +{ +} + +CurvatureInfo FacetCurvature::Compute(unsigned long index) const +{ + Base::Vector3f rkDir0, rkDir1, rkPnt; + Base::Vector3f rkNormal; + + MeshGeomFacet face = myKernel.GetFacet(index); + Base::Vector3f face_gravity = face.GetGravityPoint(); + Base::Vector3f face_normal = face.GetNormal(); + std::set point_indices; + FitPointCollector collect(point_indices); + + float searchDist = myRadius; + int attempts=0; + do { + mySearch.Neighbours(index, searchDist, collect); + if (point_indices.empty()) + break; + float min_points = myMinPoints; + float use_points = point_indices.size(); + searchDist = searchDist * sqrt(min_points/use_points); + } + while((point_indices.size() < myMinPoints) && (attempts++ < 3)); + + std::vector fitPoints; + const MeshPointArray& verts = myKernel.GetPoints(); + fitPoints.reserve(point_indices.size()); + for (std::set::iterator it = point_indices.begin(); it != point_indices.end(); ++it) { + fitPoints.push_back(verts[*it] - face_gravity); + } + + float fMin, fMax; + if (fitPoints.size() >= myMinPoints) { + SurfaceFit surf_fit; + surf_fit.AddPoints(fitPoints); + surf_fit.Fit(); + rkNormal = surf_fit.GetNormal(); + double dMin, dMax, dDistance; + if (surf_fit.GetCurvatureInfo(0.0, 0.0, 0.0, dMin, dMax, rkDir1, rkDir0, dDistance)) { + fMin = (float)dMin; + fMax = (float)dMax; + } + else { + fMin = FLT_MAX; + fMax = FLT_MAX; + } + } + else { + // too few points => cannot calc any properties + fMin = FLT_MAX; + fMax = FLT_MAX; + } + + CurvatureInfo info; + if (fMin < fMax) { + info.fMaxCurvature = fMax; + info.fMinCurvature = fMin; + info.cMaxCurvDir = rkDir1; + info.cMinCurvDir = rkDir0; + } + else { + info.fMaxCurvature = fMin; + info.fMinCurvature = fMax; + info.cMaxCurvDir = rkDir0; + info.cMinCurvDir = rkDir1; + } + + // Reverse the direction of the normal vector if required + // (Z component of "local" normal vectors should be opposite in sign to the "local" view vector) + if (rkNormal * face_normal < 0.0) { + // Note: Changing the normal directions is similar to flipping over the object. + // In this case we must adjust the curvature information as well. + std::swap(info.cMaxCurvDir,info.cMinCurvDir); + std::swap(info.fMaxCurvature,info.fMinCurvature); + info.fMaxCurvature *= (-1.0); + info.fMinCurvature *= (-1.0); + } + + return info; +} diff --git a/src/Mod/Mesh/App/Core/Curvature.h b/src/Mod/Mesh/App/Core/Curvature.h new file mode 100644 index 0000000000..7c200946a4 --- /dev/null +++ b/src/Mod/Mesh/App/Core/Curvature.h @@ -0,0 +1,75 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * 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 MESHCORE_CURVATURE_H +#define MESHCORE_CURVATURE_H + +#include +#include + +namespace MeshCore { + +class MeshKernel; +class MeshRefPointToFacets; + +/** Curvature information. */ +struct MeshExport CurvatureInfo +{ + float fMaxCurvature, fMinCurvature; + Base::Vector3f cMaxCurvDir, cMinCurvDir; +}; + +class MeshExport FacetCurvature +{ +public: + FacetCurvature(const MeshKernel& kernel, const MeshRefPointToFacets& search, float, unsigned long); + CurvatureInfo Compute(unsigned long index) const; + +private: + const MeshKernel& myKernel; + const MeshRefPointToFacets& mySearch; + unsigned long myMinPoints; + float myRadius; +}; + +class MeshExport MeshCurvature +{ +public: + MeshCurvature(const MeshKernel& kernel); + MeshCurvature(const MeshKernel& kernel, const std::vector& segm); + float GetRadius() const { return myRadius; } + void SetRadius(float r) { myRadius = r; } + void ComputePerFace(bool parallel); + void ComputePerVertex(); + const std::vector& GetCurvature() const { return myCurvature; } + +private: + const MeshKernel& myKernel; + unsigned long myMinPoints; + float myRadius; + std::vector mySegment; + std::vector myCurvature; +}; + +} // MeshCore + +#endif // MESHCORE_CURVATURE_H diff --git a/src/Mod/Mesh/App/Core/Degeneration.cpp b/src/Mod/Mesh/App/Core/Degeneration.cpp index fd48104e65..81bc9e6e31 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.cpp +++ b/src/Mod/Mesh/App/Core/Degeneration.cpp @@ -38,6 +38,7 @@ #include "Grid.h" #include "TopoAlgorithm.h" +#include #include using namespace MeshCore; @@ -228,6 +229,47 @@ bool MeshFixDuplicatePoints::Fixup() // ---------------------------------------------------------------------- +bool MeshEvalNaNPoints::Evaluate() +{ + const MeshPointArray& rPoints = _rclMesh.GetPoints(); + for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) { + if (boost::math::isnan(it->x) || boost::math::isnan(it->y) || boost::math::isnan(it->z)) + return false; + } + + return true; +} + +std::vector MeshEvalNaNPoints::GetIndices() const +{ + std::vector aInds; + const MeshPointArray& rPoints = _rclMesh.GetPoints(); + for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) { + if (boost::math::isnan(it->x) || boost::math::isnan(it->y) || boost::math::isnan(it->z)) + aInds.push_back(it - rPoints.begin()); + } + + return aInds; +} + +bool MeshFixNaNPoints::Fixup() +{ + std::vector aInds; + const MeshPointArray& rPoints = _rclMesh.GetPoints(); + for (MeshPointArray::_TConstIterator it = rPoints.begin(); it != rPoints.end(); ++it) { + if (boost::math::isnan(it->x) || boost::math::isnan(it->y) || boost::math::isnan(it->z)) + aInds.push_back(it - rPoints.begin()); + } + + // remove invalid indices + _rclMesh.DeletePoints(aInds); + _rclMesh.RebuildNeighbours(); + + return true; +} + +// ---------------------------------------------------------------------- + namespace MeshCore { typedef MeshFacetArray::_TConstIterator FaceIterator; diff --git a/src/Mod/Mesh/App/Core/Degeneration.h b/src/Mod/Mesh/App/Core/Degeneration.h index f2b28ffd74..db6c3d0100 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.h +++ b/src/Mod/Mesh/App/Core/Degeneration.h @@ -138,6 +138,54 @@ public: bool Fixup (); }; +/** + * The MeshEvalNaNPoints class searches for points with a coordinate that is NaN. + * @see MeshFixNaNPoints + * @author Werner Mayer + */ +class MeshExport MeshEvalNaNPoints : public MeshEvaluation +{ +public: + /** + * Construction. + */ + MeshEvalNaNPoints (const MeshKernel &rclM) : MeshEvaluation( rclM ) { } + /** + * Destruction. + */ + ~MeshEvalNaNPoints () { } + /** + * Returns false if a point with NaN coordinate is found. + */ + bool Evaluate (); + /** + * Returns the indices of all NaN points. + */ + std::vector GetIndices() const; +}; + +/** + * The MeshFixNaNPoints class removes all points with a coordinate that is NaN. + * @see MeshEvalNaNPoints + * @author Werner Mayer + */ +class MeshExport MeshFixNaNPoints : public MeshValidation +{ +public: + /** + * Construction. + */ + MeshFixNaNPoints (MeshKernel &rclM) : MeshValidation( rclM ) { } + /** + * Destruction. + */ + ~MeshFixNaNPoints () { } + /** + * Merges duplicated points. + */ + bool Fixup (); +}; + /** * The MeshEvalDuplicateFacets class searches for duplicated facets. * A facet is regarded as duplicated if all its point indices refer to the same location in the point array of the mesh kernel. diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index 6017172a27..4003e019c0 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -42,6 +42,7 @@ #include #include #include +#include using namespace MeshCore; @@ -330,6 +331,9 @@ bool MeshInput::LoadAny(const char* FileName) else if (fi.hasExtension("obj")) { ok = LoadOBJ( str ); } + else if (fi.hasExtension("off")) { + ok = LoadOFF( str ); + } else if (fi.hasExtension("ply")) { ok = LoadPLY( str ); } @@ -512,6 +516,124 @@ bool MeshInput::LoadOBJ (std::istream &rstrIn) return true; } +/** Loads an OFF file. */ +bool MeshInput::LoadOFF (std::istream &rstrIn) +{ + boost::regex rx_n("^\\s*([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s*$"); + boost::regex rx_p("^\\s*([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$"); + boost::regex rx_f3("^\\s*([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s*$"); + boost::regex rx_f4("^\\s*([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s*$"); + + boost::cmatch what; + + MeshPointArray meshPoints; + MeshFacetArray meshFacets; + + std::string line; + float fX, fY, fZ; + unsigned int i1=1,i2=1,i3=1,i4=1; + MeshGeomFacet clFacet; + MeshFacet item; + + if (!rstrIn || rstrIn.bad() == true) + return false; + + std::streambuf* buf = rstrIn.rdbuf(); + if (!buf) + return false; + + bool readvertices=false; + std::getline(rstrIn, line); + boost::algorithm::to_lower(line); + if (line.find("off") == std::string::npos) + return false; // not an OFF file + + // get number of vertices and faces + int numPoints=0, numFaces=0; + std::getline(rstrIn, line); + boost::algorithm::to_lower(line); + if (boost::regex_match(line.c_str(), what, rx_n)) { + numPoints = std::atoi(what[1].first); + numFaces = std::atoi(what[2].first); + } + else { + // Cannot read number of elements + return false; + } + + meshPoints.reserve(numPoints); + meshFacets.reserve(numFaces); + + for (int i=0; i_rclMesh.Clear(); // remove all data before + // Don't use Assign() because Merge() checks which points are really needed. + // This method sets already the correct neighbourhood + unsigned long ct = meshPoints.size(); + std::list removeFaces; + for (MeshFacetArray::_TConstIterator it = meshFacets.begin(); it != meshFacets.end(); ++it) { + bool ok = true; + for (int i=0;i<3;i++) { + if (it->_aulPoints[i] >= ct) { + Base::Console().Warning("Face index %ld out of range\n", it->_aulPoints[i]); + ok = false; + } + } + + if (!ok) + removeFaces.push_front(it-meshFacets.begin()); + } + + for (std::list::iterator it = removeFaces.begin(); it != removeFaces.end(); ++it) + meshFacets.erase(meshFacets.begin() + *it); + + MeshKernel tmp; + tmp.Adopt(meshPoints,meshFacets); + this->_rclMesh.Merge(tmp); + + return true; +} + bool MeshInput::LoadPLY (std::istream &inp) { // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ @@ -539,7 +661,8 @@ bool MeshInput::LoadPLY (std::istream &inp) return false; // wrong header std::string line, element; - bool xyz_float=false,xyz_double=false,rgb_value=false; + bool xyz_float=false,xyz_double=false; + MeshIO::Binding rgb_value = MeshIO::OVERALL; while (std::getline(inp, line)) { std::istringstream str(line); str.unsetf(std::ios_base::skipws); @@ -616,7 +739,11 @@ bool MeshInput::LoadPLY (std::istream &inp) xyz_double = true; } else if (name == "red") { - rgb_value = true; + rgb_value = MeshIO::PER_VERTEX; + if (_material) { + _material->binding = MeshIO::PER_VERTEX; + _material->diffuseColor.reserve(v_count); + } } } else if (element == "face") { @@ -631,9 +758,38 @@ bool MeshInput::LoadPLY (std::istream &inp) boost::regex rx_p("^([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$"); + boost::regex rx_c("^([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)" + "\\s+([0-9]{1,3})\\s+([0-9]{1,3})\\s+([0-9]{1,3})\\s*$"); boost::regex rx_f("^\\s*3\\s+([0-9]+)\\s+([0-9]+)\\s+([0-9]+)\\s*$"); boost::cmatch what; Base::Vector3f pt; + + if (rgb_value == MeshIO::PER_VERTEX) { + int r,g,b; + for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) { + if (boost::regex_match(line.c_str(), what, rx_c)) { + pt.x = (float)std::atof(what[1].first); + pt.y = (float)std::atof(what[4].first); + pt.z = (float)std::atof(what[7].first); + meshPoints.push_back(pt); + if (_material) { + r = std::min(std::atoi(what[10].first),255); + g = std::min(std::atoi(what[11].first),255); + b = std::min(std::atoi(what[12].first),255); + float fr = (float)r/255.0f; + float fg = (float)g/255.0f; + float fb = (float)b/255.0f; + _material->diffuseColor.push_back(App::Color(fr, fg, fb)); + } + } + else { + return false; + } + } + } + else { for (std::size_t i = 0; i < v_count && std::getline(inp, line); i++) { if (boost::regex_match(line.c_str(), what, rx_p)) { pt.x = (float)std::atof(what[1].first); @@ -645,6 +801,7 @@ bool MeshInput::LoadPLY (std::istream &inp) return false; } } + } int f1, f2, f3; for (std::size_t i = 0; i < f_count && std::getline(inp, line); i++) { if (boost::regex_match(line.c_str(), what, rx_f)) { @@ -655,6 +812,7 @@ bool MeshInput::LoadPLY (std::istream &inp) } } } + // binary else { Base::InputStream is(inp); if (format == binary_little_endian) @@ -667,16 +825,31 @@ bool MeshInput::LoadPLY (std::istream &inp) for (std::size_t i = 0; i < v_count; i++) { is >> pt.x >> pt.y >> pt.z; meshPoints.push_back(pt); - if (rgb_value) + if (rgb_value == MeshIO::PER_VERTEX) { is >> r >> g >> b; + if (_material) { + float fr = (float)r/255.0f; + float fg = (float)g/255.0f; + float fb = (float)b/255.0f; + _material->diffuseColor.push_back(App::Color(fr, fg, fb)); + } + } } } else if (xyz_double) { Base::Vector3d pt; for (std::size_t i = 0; i < v_count; i++) { is >> pt.x >> pt.y >> pt.z; - is >> r >> g >> b; meshPoints.push_back(Base::Vector3f((float)pt.x,(float)pt.y,(float)pt.z)); + if (rgb_value == MeshIO::PER_VERTEX) { + is >> r >> g >> b; + if (_material) { + float fr = (float)r/255.0f; + float fg = (float)g/255.0f; + float fb = (float)b/255.0f; + _material->diffuseColor.push_back(App::Color(fr, fg, fb)); + } + } } } unsigned char n; @@ -786,7 +959,7 @@ bool MeshInput::LoadAsciiSTL (std::istream &rstrIn) if (line.find("ENDFACET") != std::string::npos) ulFacetCt++; // prevent from reading EOF (as I don't know how to reread the file then) - else if (rstrIn.tellg() > ulSize) + if (rstrIn.tellg() > ulSize) break; else if (line.find("ENDSOLID") != std::string::npos) break; @@ -1306,7 +1479,12 @@ bool MeshOutput::SaveAny(const char* FileName, MeshIO::Format format) const } else if (fileformat == MeshIO::PLY) { // write file - if (!SavePLY(str)) + if (!SaveBinaryPLY(str)) + throw Base::FileException("Export of PLY mesh failed",FileName); + } + else if (fileformat == MeshIO::APLY) { + // write file + if (!SaveAsciiPLY(str)) throw Base::FileException("Export of PLY mesh failed",FileName); } else if (fileformat == MeshIO::IV) { @@ -1524,7 +1702,7 @@ bool MeshOutput::SaveOFF (std::ostream &out) const return true; } -bool MeshOutput::SavePLY (std::ostream &out) const +bool MeshOutput::SaveBinaryPLY (std::ostream &out) const { const MeshPointArray& rPoints = _rclMesh.GetPoints(); const MeshFacetArray& rFacets = _rclMesh.GetFacets(); @@ -1584,6 +1762,81 @@ bool MeshOutput::SavePLY (std::ostream &out) const return true; } +bool MeshOutput::SaveAsciiPLY (std::ostream &out) const +{ + const MeshPointArray& rPoints = _rclMesh.GetPoints(); + const MeshFacetArray& rFacets = _rclMesh.GetFacets(); + std::size_t v_count = rPoints.size(); + std::size_t f_count = rFacets.size(); + if (!out || out.bad() == true) + return false; + + bool saveVertexColor = (_material && _material->binding == MeshIO::PER_VERTEX + && _material->diffuseColor.size() == rPoints.size()); + out << "ply" << std::endl + << "format ascii 1.0" << std::endl + << "comment Created by FreeCAD " << std::endl + << "element vertex " << v_count << std::endl + << "property float32 x" << std::endl + << "property float32 y" << std::endl + << "property float32 z" << std::endl; + if (saveVertexColor) { + out << "property uchar red" << std::endl + << "property uchar green" << std::endl + << "property uchar blue" << std::endl; + } + out << "element face " << f_count << std::endl + << "property list uchar int vertex_index" << std::endl + << "end_header" << std::endl; + + Base::Vector3f pt; + + out.precision(6); + out.setf(std::ios::fixed | std::ios::showpoint); + if (saveVertexColor) { + for (std::size_t i = 0; i < v_count; i++) { + const MeshPoint& p = rPoints[i]; + if (this->apply_transform) { + Base::Vector3f pt = this->_transform * p; + out << pt.x << " " << pt.y << " " << pt.z; + } + else { + out << p.x << " " << p.y << " " << p.z; + } + + const App::Color& c = _material->diffuseColor[i]; + int r = (int)(255.0f * c.r); + int g = (int)(255.0f * c.g); + int b = (int)(255.0f * c.b); + out << " " << r << " " << g << " " << b << std::endl; + } + } + else { + for (std::size_t i = 0; i < v_count; i++) { + const MeshPoint& p = rPoints[i]; + if (this->apply_transform) { + Base::Vector3f pt = this->_transform * p; + out << pt.x << " " << pt.y << " " << pt.z << std::endl; + } + else { + out << p.x << " " << p.y << " " << p.z << std::endl; + } + } + } + + unsigned int n = 3; + int f1, f2, f3; + for (std::size_t i = 0; i < f_count; i++) { + const MeshFacet& f = rFacets[i]; + f1 = (int)f._aulPoints[0]; + f2 = (int)f._aulPoints[1]; + f3 = (int)f._aulPoints[2]; + out << n << " " << f1 << " " << f2 << " " << f3 << std::endl; + } + + return true; +} + bool MeshOutput::SaveMeshNode (std::ostream &rstrOut) { const MeshPointArray& rPoints = _rclMesh.GetPoints(); diff --git a/src/Mod/Mesh/App/Core/MeshIO.h b/src/Mod/Mesh/App/Core/MeshIO.h index a056b17a4d..b439f1bd2a 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.h +++ b/src/Mod/Mesh/App/Core/MeshIO.h @@ -51,6 +51,7 @@ namespace MeshIO { WRZ, NAS, PLY, + APLY, PY }; enum Binding { @@ -74,7 +75,10 @@ struct MeshExport Material class MeshExport MeshInput { public: - MeshInput (MeshKernel &rclM): _rclMesh(rclM){}; + MeshInput (MeshKernel &rclM) + : _rclMesh(rclM), _material(0){} + MeshInput (MeshKernel &rclM, Material* m) + : _rclMesh(rclM), _material(m){} virtual ~MeshInput (void) { } /// Loads the file, decided by extension @@ -89,6 +93,8 @@ public: bool LoadBinarySTL (std::istream &rstrIn); /** Loads an OBJ Mesh file. */ bool LoadOBJ (std::istream &rstrIn); + /** Loads an OFF Mesh file. */ + bool LoadOFF (std::istream &rstrIn); /** Loads a PLY Mesh file. */ bool LoadPLY (std::istream &rstrIn); /** Loads the mesh object from an XML file. */ @@ -104,6 +110,7 @@ public: protected: MeshKernel &_rclMesh; /**< reference to mesh data structure */ + Material* _material; }; /** @@ -136,8 +143,10 @@ public: bool SaveOBJ (std::ostream &rstrOut) const; /** Saves the mesh object into an OFF file. */ bool SaveOFF (std::ostream &rstrOut) const; - /** Saves the mesh object into a PLY file. */ - bool SavePLY (std::ostream &rstrOut) const; + /** Saves the mesh object into a binary PLY file. */ + bool SaveBinaryPLY (std::ostream &rstrOut) const; + /** Saves the mesh object into an ASCII PLY file. */ + bool SaveAsciiPLY (std::ostream &rstrOut) const; /** Saves the mesh object into an XML file. */ void SaveXML (Base::Writer &writer) const; /** Saves a node to an OpenInventor file. */ diff --git a/src/Mod/Mesh/App/Core/Segmentation.cpp b/src/Mod/Mesh/App/Core/Segmentation.cpp new file mode 100644 index 0000000000..9d0d69f325 --- /dev/null +++ b/src/Mod/Mesh/App/Core/Segmentation.cpp @@ -0,0 +1,238 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * 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 "Segmentation.h" +#include "Algorithm.h" +#include "Approximation.h" + +using namespace MeshCore; + +void MeshSurfaceSegment::Initialize(unsigned long) +{ +} + +void MeshSurfaceSegment::AddFacet(const MeshFacet&) +{ +} + +void MeshSurfaceSegment::AddSegment(const std::vector& segm) +{ + if (segm.size() >= minFacets) { + segments.push_back(segm); + } +} + +MeshSegment MeshSurfaceSegment::FindSegment(unsigned long index) const +{ + for (std::vector::const_iterator it = segments.begin(); it != segments.end(); ++it) { + if (std::find(it->begin(), it->end(), index) != it->end()) + return *it; + } + + return MeshSegment(); +} + +// -------------------------------------------------------- + +MeshDistancePlanarSegment::MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol) + : MeshDistanceSurfaceSegment(mesh, minFacets, tol), fitter(new PlaneFit) +{ +} + +MeshDistancePlanarSegment::~MeshDistancePlanarSegment() +{ + delete fitter; +} + +void MeshDistancePlanarSegment::Initialize(unsigned long index) +{ + fitter->Clear(); + + MeshGeomFacet triangle = kernel.GetFacet(index); + basepoint = triangle.GetGravityPoint(); + normal = triangle.GetNormal(); + fitter->AddPoint(triangle._aclPoints[0]); + fitter->AddPoint(triangle._aclPoints[1]); + fitter->AddPoint(triangle._aclPoints[2]); +} + +bool MeshDistancePlanarSegment::TestFacet (const MeshFacet& face) const +{ + if (!fitter->Done()) + fitter->Fit(); + MeshGeomFacet triangle = kernel.GetFacet(face); + for (int i=0; i<3; i++) { + if (fabs(fitter->GetDistanceToPlane(triangle._aclPoints[i])) > tolerance) + return false; + } + + return true; +} + +void MeshDistancePlanarSegment::AddFacet(const MeshFacet& face) +{ + MeshGeomFacet triangle = kernel.GetFacet(face); + fitter->AddPoint(triangle.GetGravityPoint()); +} + +// -------------------------------------------------------- + +bool MeshCurvaturePlanarSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (fabs(ci.fMinCurvature) > tolerance) + return false; + if (fabs(ci.fMaxCurvature) > tolerance) + return false; + } + + return true; +} + +bool MeshCurvatureCylindricalSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + float fMax = std::max(fabs(ci.fMaxCurvature), fabs(ci.fMinCurvature)); + float fMin = std::min(fabs(ci.fMaxCurvature), fabs(ci.fMinCurvature)); + if (fMin > toleranceMin) + return false; + if (fabs(fMax - curvature) > toleranceMax) + return false; + } + + return true; +} + +bool MeshCurvatureSphericalSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (ci.fMaxCurvature * ci.fMinCurvature < 0) + return false; + float diff; + diff = fabs(ci.fMinCurvature) - curvature; + if (fabs(diff) > tolerance) + return false; + diff = fabs(ci.fMaxCurvature) - curvature; + if (fabs(diff) > tolerance) + return false; + } + + return true; +} + +bool MeshCurvatureFreeformSegment::TestFacet (const MeshFacet &rclFacet) const +{ + for (int i=0; i<3; i++) { + const CurvatureInfo& ci = info[rclFacet._aulPoints[i]]; + if (fabs(ci.fMinCurvature-c2) > toleranceMin) + return false; + if (fabs(ci.fMaxCurvature-c1) > toleranceMax) + return false; + } + + return true; +} + +// -------------------------------------------------------- + +MeshSurfaceVisitor::MeshSurfaceVisitor (MeshSurfaceSegment& segm, std::vector &indices) + : indices(indices), segm(segm) +{ +} + +MeshSurfaceVisitor::~MeshSurfaceVisitor () +{ +} + +bool MeshSurfaceVisitor::AllowVisit (const MeshFacet& face, const MeshFacet&, + unsigned long, unsigned long, unsigned short) +{ + return segm.TestFacet(face); +} + +bool MeshSurfaceVisitor::Visit (const MeshFacet & face, const MeshFacet &, + unsigned long ulFInd, unsigned long) +{ + indices.push_back(ulFInd); + segm.AddFacet(face); + return true; +} + +// -------------------------------------------------------- + +void MeshSegmentAlgorithm::FindSegments(std::vector& segm) +{ + // reset VISIT flags + unsigned long startFacet; + MeshCore::MeshAlgorithm cAlgo(myKernel); + cAlgo.ResetFacetFlag(MeshCore::MeshFacet::VISIT); + + const MeshCore::MeshFacetArray& rFAry = myKernel.GetFacets(); + MeshCore::MeshFacetArray::_TConstIterator iCur = rFAry.begin(); + MeshCore::MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); + MeshCore::MeshFacetArray::_TConstIterator iEnd = rFAry.end(); + + // start from the first not visited facet + cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); + std::vector resetVisited; + + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + cAlgo.ResetFacetsFlag(resetVisited, MeshCore::MeshFacet::VISIT); + resetVisited.clear(); + + iCur = std::find_if(iBeg, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), + MeshCore::MeshFacet::VISIT)); + startFacet = iCur - iBeg; + while (startFacet != ULONG_MAX) { + // collect all facets of the same geometry + std::vector indices; + indices.push_back(startFacet); + (*it)->Initialize(startFacet); + MeshSurfaceVisitor pv(**it, indices); + myKernel.VisitNeighbourFacets(pv, startFacet); + + // add or discard the segment + if (indices.size() == 1) { + resetVisited.push_back(startFacet); + } + else { + (*it)->AddSegment(indices); + } + + // search for the next start facet + iCur = std::find_if(iCur, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), + MeshCore::MeshFacet::VISIT)); + if (iCur < iEnd) + startFacet = iCur - iBeg; + else + startFacet = ULONG_MAX; + } + } +} diff --git a/src/Mod/Mesh/App/Core/Segmentation.h b/src/Mod/Mesh/App/Core/Segmentation.h new file mode 100644 index 0000000000..9416028b69 --- /dev/null +++ b/src/Mod/Mesh/App/Core/Segmentation.h @@ -0,0 +1,180 @@ +/*************************************************************************** + * Copyright (c) 2012 Imetric 3D GmbH * + * * + * 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 MESHCORE_SEGMENTATION_H +#define MESHCORE_SEGMENTATION_H + +#include "MeshKernel.h" +#include "Curvature.h" +#include "Visitor.h" +#include + +namespace MeshCore { + +class PlaneFit; +class MeshFacet; +typedef std::vector MeshSegment; + +class MeshExport MeshSurfaceSegment +{ +public: + MeshSurfaceSegment(unsigned long minFacets) + : minFacets(minFacets) {} + virtual ~MeshSurfaceSegment() {} + virtual bool TestFacet (const MeshFacet &rclFacet) const = 0; + virtual const char* GetType() const = 0; + virtual void Initialize(unsigned long); + virtual void AddFacet(const MeshFacet& rclFacet); + void AddSegment(const std::vector&); + const std::vector& GetSegments() const { return segments; } + MeshSegment FindSegment(unsigned long) const; + +protected: + std::vector segments; + unsigned long minFacets; +}; + +// -------------------------------------------------------- + +class MeshExport MeshDistanceSurfaceSegment : public MeshSurfaceSegment +{ +public: + MeshDistanceSurfaceSegment(const MeshKernel& mesh, unsigned long minFacets, float tol) + : MeshSurfaceSegment(minFacets), kernel(mesh), tolerance(tol) {} + +protected: + const MeshKernel& kernel; + float tolerance; +}; + +class MeshExport MeshDistancePlanarSegment : public MeshDistanceSurfaceSegment +{ +public: + MeshDistancePlanarSegment(const MeshKernel& mesh, unsigned long minFacets, float tol); + virtual ~MeshDistancePlanarSegment(); + bool TestFacet (const MeshFacet& rclFacet) const; + const char* GetType() const { return "Plane"; } + void Initialize(unsigned long); + void AddFacet(const MeshFacet& rclFacet); + +protected: + Base::Vector3f basepoint; + Base::Vector3f normal; + PlaneFit* fitter; +}; + +// -------------------------------------------------------- + +class MeshExport MeshCurvatureSurfaceSegment : public MeshSurfaceSegment +{ +public: + MeshCurvatureSurfaceSegment(const std::vector& ci, unsigned long minFacets) + : MeshSurfaceSegment(minFacets), info(ci) {} + +protected: + const std::vector& info; +}; + +class MeshExport MeshCurvaturePlanarSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvaturePlanarSegment(const std::vector& ci, unsigned long minFacets, float tol) + : MeshCurvatureSurfaceSegment(ci, minFacets), tolerance(tol) {} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Plane"; } + +private: + float tolerance; +}; + +class MeshExport MeshCurvatureCylindricalSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvatureCylindricalSegment(const std::vector& ci, unsigned long minFacets, + float tolMin, float tolMax, float radius) + : MeshCurvatureSurfaceSegment(ci, minFacets), toleranceMin(tolMin), toleranceMax(tolMax) { curvature = 1/radius;} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Cylinder"; } + +private: + float curvature; + float toleranceMin; + float toleranceMax; +}; + +class MeshExport MeshCurvatureSphericalSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvatureSphericalSegment(const std::vector& ci, unsigned long minFacets, float tol, float radius) + : MeshCurvatureSurfaceSegment(ci, minFacets), tolerance(tol) { curvature = 1/radius;} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Sphere"; } + +private: + float curvature; + float tolerance; +}; + +class MeshExport MeshCurvatureFreeformSegment : public MeshCurvatureSurfaceSegment +{ +public: + MeshCurvatureFreeformSegment(const std::vector& ci, unsigned long minFacets, + float tolMin, float tolMax, float c1, float c2) + : MeshCurvatureSurfaceSegment(ci, minFacets), c1(c1), c2(c2), + toleranceMin(tolMin), toleranceMax(tolMax) {} + virtual bool TestFacet (const MeshFacet &rclFacet) const; + virtual const char* GetType() const { return "Freeform"; } + +private: + float c1, c2; + float toleranceMin; + float toleranceMax; +}; + +class MeshExport MeshSurfaceVisitor : public MeshFacetVisitor +{ +public: + MeshSurfaceVisitor (MeshSurfaceSegment& segm, std::vector &indices); + virtual ~MeshSurfaceVisitor (); + bool AllowVisit (const MeshFacet& face, const MeshFacet&, + unsigned long, unsigned long, unsigned short neighbourIndex); + bool Visit (const MeshFacet & face, const MeshFacet &, + unsigned long ulFInd, unsigned long); + +protected: + std::vector &indices; + MeshSurfaceSegment& segm; +}; + +class MeshExport MeshSegmentAlgorithm +{ +public: + MeshSegmentAlgorithm(const MeshKernel& kernel) : myKernel(kernel) {} + void FindSegments(std::vector&); + +private: + const MeshKernel& myKernel; +}; + +} // MeshCore + +#endif // MESHCORE_SEGMENTATION_H diff --git a/src/Mod/Mesh/App/Core/Triangulation.cpp b/src/Mod/Mesh/App/Core/Triangulation.cpp index 68babf99df..17896594cb 100644 --- a/src/Mod/Mesh/App/Core/Triangulation.cpp +++ b/src/Mod/Mesh/App/Core/Triangulation.cpp @@ -158,7 +158,7 @@ MeshGeomFacet AbstractPolygonTriangulator::GetTriangle(const MeshPointArray& poi bool AbstractPolygonTriangulator::TriangulatePolygon() { try { - if (this->_points.size() != this->_indices.size()) { + if (!this->_indices.empty() && this->_points.size() != this->_indices.size()) { Base::Console().Log("Triangulation: %d points <> %d indices\n", _points.size(), _indices.size()); return false; } diff --git a/src/Mod/Mesh/App/FeatureMeshCurvature.cpp b/src/Mod/Mesh/App/FeatureMeshCurvature.cpp index f618f2dea8..f7bc012058 100644 --- a/src/Mod/Mesh/App/FeatureMeshCurvature.cpp +++ b/src/Mod/Mesh/App/FeatureMeshCurvature.cpp @@ -29,18 +29,16 @@ #include #include #include -#include -#include #include "FeatureMeshCurvature.h" #include "MeshFeature.h" +#include "Core/Curvature.h" #include "Core/Elements.h" #include "Core/Iterator.h" using namespace Mesh; -using namespace MeshCore; PROPERTY_SOURCE(Mesh::Curvature, App::DocumentObject) @@ -68,42 +66,20 @@ App::DocumentObjectExecReturn *Curvature::execute(void) } // get all points - const MeshKernel& rMesh = pcFeat->Mesh.getValue().getKernel(); - std::vector< Wm4::Vector3 > aPnts; - aPnts.reserve(rMesh.CountPoints()); - MeshPointIterator cPIt( rMesh ); - for (cPIt.Init(); cPIt.More(); cPIt.Next()) { - Wm4::Vector3 cP(cPIt->x, cPIt->y, cPIt->z); - aPnts.push_back(cP); - } + const MeshCore::MeshKernel& rMesh = pcFeat->Mesh.getValue().getKernel(); + MeshCore::MeshCurvature meshCurv(rMesh); + meshCurv.ComputePerVertex(); + const std::vector& curv = meshCurv.GetCurvature(); - // get all point connections - std::vector aIdx; - aIdx.reserve(3*rMesh.CountFacets()); - const std::vector& raFts = rMesh.GetFacets(); - for (std::vector::const_iterator jt = raFts.begin(); jt != raFts.end(); ++jt) { - for (int i=0; i<3; i++) { - aIdx.push_back((int)jt->_aulPoints[i]); - } - } - - // compute vertex based curvatures - Wm4::MeshCurvature meshCurv(rMesh.CountPoints(), &(aPnts[0]), rMesh.CountFacets(), &(aIdx[0])); - - // get curvature information now - const Wm4::Vector3* aMaxCurvDir = meshCurv.GetMaxDirections(); - const Wm4::Vector3* aMinCurvDir = meshCurv.GetMinDirections(); - const float* aMaxCurv = meshCurv.GetMaxCurvatures(); - const float* aMinCurv = meshCurv.GetMinCurvatures(); - - std::vector values(rMesh.CountPoints()); - for (unsigned long i=0; i values; + values.reserve(curv.size()); + for (std::vector::const_iterator it = curv.begin(); it != curv.end(); ++it) { CurvatureInfo ci; - ci.cMaxCurvDir = Base::Vector3f(aMaxCurvDir[i].X(), aMaxCurvDir[i].Y(), aMaxCurvDir[i].Z()); - ci.cMinCurvDir = Base::Vector3f(aMinCurvDir[i].X(), aMinCurvDir[i].Y(), aMinCurvDir[i].Z()); - ci.fMaxCurvature = aMaxCurv[i]; - ci.fMinCurvature = aMinCurv[i]; - values[i] = ci; + ci.cMaxCurvDir = it->cMaxCurvDir; + ci.cMinCurvDir = it->cMinCurvDir; + ci.fMaxCurvature = it->fMaxCurvature; + ci.fMinCurvature = it->fMinCurvature; + values.push_back(ci); } CurvInfo.setValues(values); diff --git a/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h b/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h index 16f6e1a576..76c51c54b1 100644 --- a/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h +++ b/src/Mod/Mesh/App/FeatureMeshSegmentByMesh.h @@ -21,8 +21,8 @@ ***************************************************************************/ -#ifndef FEATURE_MESH_SEGMENT_H -#define FEATURE_MESH_SEGMENT_H +#ifndef FEATURE_MESH_SEGMENTBYMESH_H +#define FEATURE_MESH_SEGMENTBYMESH_H #include @@ -63,4 +63,4 @@ public: } -#endif // FEATURE_MESH_SEGMENT_H +#endif // FEATURE_MESH_SEGMENTBYMESH_H diff --git a/src/Mod/Mesh/App/Makefile.am b/src/Mod/Mesh/App/Makefile.am index 6309f0d912..5ba606444c 100644 --- a/src/Mod/Mesh/App/Makefile.am +++ b/src/Mod/Mesh/App/Makefile.am @@ -22,6 +22,8 @@ libMesh_la_SOURCES=\ Core/Approximation.h \ Core/Builder.cpp \ Core/Builder.h \ + Core/Curvature.cpp \ + Core/Curvature.h \ Core/Definitions.cpp \ Core/Definitions.h \ Core/Degeneration.cpp \ @@ -42,6 +44,8 @@ libMesh_la_SOURCES=\ Core/MeshIO.h \ Core/Projection.cpp \ Core/Projection.h \ + Core/Segmentation.cpp \ + Core/Segmentation.h \ Core/SetOperations.cpp \ Core/SetOperations.h \ Core/Smoothing.cpp \ @@ -324,9 +328,9 @@ nobase_include_HEADERS = \ # the library search path. -libMesh_la_LDFLAGS = -L../../../Base -L../../../App $(all_libraries) $(GTS_LIBS) \ +libMesh_la_LDFLAGS = -L../../../Base -L../../../App $(QT4_CORE_LIBS) $(all_libraries) $(GTS_LIBS) \ -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ -libMesh_la_CPPFLAGS = -DMeshExport= +libMesh_la_CPPFLAGS = -DMeshExport= -DEIGEN2_SUPPORT libMesh_la_LIBADD = \ @BOOST_FILESYSTEM_LIB@ @BOOST_REGEX_LIB@ @BOOST_SYSTEM_LIB@ \ @@ -354,7 +358,8 @@ Mesh_la_DEPENDENCIES = libMesh.la #-------------------------------------------------------------------------------------- # set the include path found by configure -AM_CXXFLAGS = -I$(top_srcdir)/src/3rdParty -I$(top_srcdir)/src -I$(top_builddir)/src $(GTS_CFLAGS) $(all_includes) +AM_CXXFLAGS = -I$(top_srcdir)/src/3rdParty -I$(top_srcdir)/src -I$(top_builddir)/src $(GTS_CFLAGS) \ + $(all_includes) -I$(EIGEN3_INC) $(QT4_CORE_CXXFLAGS) includedir = @includedir@/Mod/Mesh/App libdir = $(prefix)/Mod/Mesh diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 47f7a57cf2..dec5da73bc 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -44,6 +44,7 @@ #include "Core/TopoAlgorithm.h" #include "Core/Evaluation.h" #include "Core/Degeneration.h" +#include "Core/Segmentation.h" #include "Core/SetOperations.h" #include "Core/Visitor.h" @@ -311,10 +312,10 @@ void MeshObject::save(std::ostream& out) const _kernel.Write(out); } -bool MeshObject::load(const char* file) +bool MeshObject::load(const char* file, MeshCore::Material* mat) { MeshCore::MeshKernel kernel; - MeshCore::MeshInput aReader(kernel); + MeshCore::MeshInput aReader(kernel, mat); if (!aReader.LoadAny(file)) return false; @@ -631,6 +632,32 @@ void MeshObject::removeComponents(unsigned long count) deletedFacets(removeIndices); } +unsigned long MeshObject::getPointDegree(const std::vector& indices, + std::vector& point_degree) const +{ + const MeshCore::MeshFacetArray& faces = _kernel.GetFacets(); + std::vector pointDeg(_kernel.CountPoints()); + + for (MeshCore::MeshFacetArray::_TConstIterator it = faces.begin(); it != faces.end(); ++it) { + pointDeg[it->_aulPoints[0]]++; + pointDeg[it->_aulPoints[1]]++; + pointDeg[it->_aulPoints[2]]++; + } + + for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) { + const MeshCore::MeshFacet& face = faces[*it]; + pointDeg[face._aulPoints[0]]--; + pointDeg[face._aulPoints[1]]--; + pointDeg[face._aulPoints[2]]--; + } + + unsigned long countInvalids = std::count_if(pointDeg.begin(), pointDeg.end(), + std::bind2nd(std::equal_to(), 0)); + + point_degree = pointDeg; + return countInvalids; +} + void MeshObject::fillupHoles(unsigned long length, int level, MeshCore::AbstractPolygonTriangulator& cTria) { @@ -1097,6 +1124,12 @@ void MeshObject::removeFullBoundaryFacets() } } +void MeshObject::removeInvalidPoints() +{ + MeshCore::MeshEvalNaNPoints nan(_kernel); + deletePoints(nan.GetIndices()); +} + void MeshObject::validateIndices() { unsigned long count = _kernel.CountFacets(); @@ -1390,50 +1423,25 @@ MeshObject* MeshObject::meshFromSegment(const std::vector& indice return new MeshObject(kernel, _Mtrx); } -std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, const Segment& aSegment, float dev) const +std::vector MeshObject::getSegmentsFromType(MeshObject::Type type, const Segment& aSegment, + float dev, unsigned long minFacets) const { std::vector segm; - unsigned long startFacet, visited; if (this->_kernel.CountFacets() == 0) return segm; - // reset VISIT flags - MeshCore::MeshAlgorithm cAlgo(this->_kernel); - if (aSegment.isEmpty()) { - cAlgo.ResetFacetFlag(MeshCore::MeshFacet::VISIT); + MeshCore::MeshSegmentAlgorithm finder(this->_kernel); + MeshCore::MeshDistanceSurfaceSegment* surf; + surf = new MeshCore::MeshDistancePlanarSegment(this->_kernel, minFacets, dev); + std::vector surfaces; + surfaces.push_back(surf); + finder.FindSegments(surfaces); + + const std::vector& data = surf->GetSegments(); + for (std::vector::const_iterator it = data.begin(); it != data.end(); ++it) { + segm.push_back(Segment(const_cast(this), *it, false)); } - else { - cAlgo.SetFacetFlag(MeshCore::MeshFacet::VISIT); - cAlgo.ResetFacetsFlag(aSegment.getIndices(), MeshCore::MeshFacet::VISIT); - } - - const MeshCore::MeshFacetArray& rFAry = this->_kernel.GetFacets(); - MeshCore::MeshFacetArray::_TConstIterator iTri = rFAry.begin(); - MeshCore::MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); - MeshCore::MeshFacetArray::_TConstIterator iEnd = rFAry.end(); - - // start from the first not visited facet - visited = cAlgo.CountFacetFlag(MeshCore::MeshFacet::VISIT); - iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), - MeshCore::MeshFacet::VISIT)); - startFacet = iTri - iBeg; - - while (startFacet != ULONG_MAX) { - // collect all facets of the same geometry - std::vector indices; - indices.push_back(startFacet); - MeshCore::MeshPlaneVisitor pv(this->_kernel, startFacet, dev, indices); - visited += this->_kernel.VisitNeighbourFacets(pv, startFacet); - - iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshCore::MeshIsNotFlag(), - MeshCore::MeshFacet::VISIT)); - if (iTri < iEnd) - startFacet = iTri - iBeg; - else - startFacet = ULONG_MAX; - segm.push_back(Segment(const_cast(this), indices, false)); - } - + delete surf; return segm; } diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index aedc0defc0..3d884517fe 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -144,7 +144,7 @@ public: void save(const char* file,MeshCore::MeshIO::Format f=MeshCore::MeshIO::Undefined, const MeshCore::Material* mat = 0) const; void save(std::ostream&) const; - bool load(const char* file); + bool load(const char* file, MeshCore::Material* mat = 0); void load(std::istream&); //@} @@ -177,6 +177,14 @@ public: std::vector > getComponents() const; unsigned long countComponents() const; void removeComponents(unsigned long); + /** + * Checks for the given facet indices what will be the degree for each point + * when these facets are removed from the mesh kernel. + * The point degree information is stored in \a point_degree. The return value + * gices the number of points which will have a degree of zero. + */ + unsigned long getPointDegree(const std::vector& facets, + std::vector& point_degree) const; void fillupHoles(unsigned long, int, MeshCore::AbstractPolygonTriangulator&); void offset(float fSize); void offsetSpecial2(float fSize); @@ -248,6 +256,7 @@ public: void removeSelfIntersections(const std::vector&); void removeFoldsOnSurface(); void removeFullBoundaryFacets(); + void removeInvalidPoints(); //@} /** @name Mesh segments */ @@ -257,7 +266,7 @@ public: const Segment& getSegment(unsigned long) const; Segment& getSegment(unsigned long); MeshObject* meshFromSegment(const std::vector&) const; - std::vector getSegmentsFromType(Type, const Segment& aSegment, float dev) const; + std::vector getSegmentsFromType(Type, const Segment& aSegment, float dev, unsigned long minFacets) const; //@} /** @name Primitives */ diff --git a/src/Mod/Mesh/App/MeshFeaturePyImp.cpp b/src/Mod/Mesh/App/MeshFeaturePyImp.cpp index fb0d60dacb..b99e5bee1e 100644 --- a/src/Mod/Mesh/App/MeshFeaturePyImp.cpp +++ b/src/Mod/Mesh/App/MeshFeaturePyImp.cpp @@ -77,7 +77,10 @@ PyObject* MeshFeaturePy::smooth(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.smooth(iter, d_max); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->smooth(iter, d_max); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -87,7 +90,10 @@ PyObject* MeshFeaturePy::removeNonManifolds(PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; - getFeaturePtr()->Mesh.removeNonManifolds(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeNonManifolds(); + obj->Mesh.finishEditing(); Py_Return } @@ -97,7 +103,10 @@ PyObject* MeshFeaturePy::fixIndices(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.validateIndices(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->validateIndices(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -109,7 +118,10 @@ PyObject* MeshFeaturePy::fixDegenerations(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.validateDegenerations(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->validateDegenerations(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -121,7 +133,10 @@ PyObject* MeshFeaturePy::removeDuplicatedFacets(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.removeDuplicatedFacets(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeDuplicatedFacets(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -133,7 +148,10 @@ PyObject* MeshFeaturePy::removeDuplicatedPoints(PyObject *args) return NULL; PY_TRY { - getFeaturePtr()->Mesh.removeDuplicatedPoints(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeDuplicatedPoints(); + obj->Mesh.finishEditing(); } PY_CATCH; Py_Return; @@ -144,7 +162,10 @@ PyObject* MeshFeaturePy::fixSelfIntersections(PyObject *args) if (!PyArg_ParseTuple(args, "")) return NULL; try { - getFeaturePtr()->Mesh.removeSelfIntersections(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeSelfIntersections(); + obj->Mesh.finishEditing(); } catch (const Base::Exception& e) { PyErr_SetString(PyExc_Exception, e.what()); @@ -158,7 +179,10 @@ PyObject* MeshFeaturePy::removeFoldsOnSurface(PyObject *args) if (!PyArg_ParseTuple(args, "")) return NULL; try { - getFeaturePtr()->Mesh.removeFoldsOnSurface(); + Mesh::Feature* obj = getFeaturePtr(); + MeshObject* kernel = obj->Mesh.startEditing(); + kernel->removeFoldsOnSurface(); + obj->Mesh.finishEditing(); } catch (const Base::Exception& e) { PyErr_SetString(PyExc_Exception, e.what()); diff --git a/src/Mod/Mesh/App/MeshProperties.cpp b/src/Mod/Mesh/App/MeshProperties.cpp index 3c0b41190c..9e68cae10a 100644 --- a/src/Mod/Mesh/App/MeshProperties.cpp +++ b/src/Mod/Mesh/App/MeshProperties.cpp @@ -390,20 +390,6 @@ void PropertyMeshKernel::transformGeometry(const Base::Matrix4D &rclMat) hasSetValue(); } -void PropertyMeshKernel::deletePointIndices( const std::vector& inds ) -{ - aboutToSetValue(); - _meshObject->deletePoints(inds); - hasSetValue(); -} - -void PropertyMeshKernel::deleteFacetIndices( const std::vector& inds ) -{ - aboutToSetValue(); - _meshObject->deleteFacets(inds); - hasSetValue(); -} - void PropertyMeshKernel::setPointIndices(const std::vector >& inds) { aboutToSetValue(); @@ -413,99 +399,6 @@ void PropertyMeshKernel::setPointIndices(const std::vector& rFaces, - const std::vector& rPoints) -{ - aboutToSetValue(); - _meshObject->addFacets(rFaces, rPoints); - hasSetValue(); -} - -void PropertyMeshKernel::createSegment(const std::vector& segm) -{ - aboutToSetValue(); - _meshObject->addSegment(segm); - hasSetValue(); -} - -void PropertyMeshKernel::smooth(int iter, float d_max) -{ - aboutToSetValue(); - _meshObject->smooth(iter, d_max); - hasSetValue(); -} - -void PropertyMeshKernel::clear() -{ - // clear the underlying mesh kernel and free any allocated memory - aboutToSetValue(); - _meshObject->clear(); - hasSetValue(); -} - -void PropertyMeshKernel::harmonizeNormals() -{ - aboutToSetValue(); - _meshObject->harmonizeNormals(); - hasSetValue(); -} - -void PropertyMeshKernel::removeNonManifolds() -{ - aboutToSetValue(); - _meshObject->removeNonManifolds(); - hasSetValue(); -} - -void PropertyMeshKernel::validateIndices() -{ - aboutToSetValue(); - _meshObject->validateIndices(); - hasSetValue(); -} - -void PropertyMeshKernel::validateDegenerations() -{ - aboutToSetValue(); - _meshObject->validateDegenerations(); - hasSetValue(); -} - -void PropertyMeshKernel::validateDeformations(float fMaxAngle) -{ - aboutToSetValue(); - _meshObject->validateDeformations(fMaxAngle); - hasSetValue(); -} - -void PropertyMeshKernel::removeDuplicatedFacets() -{ - aboutToSetValue(); - _meshObject->removeDuplicatedFacets(); - hasSetValue(); -} - -void PropertyMeshKernel::removeDuplicatedPoints() -{ - aboutToSetValue(); - _meshObject->removeDuplicatedPoints(); - hasSetValue(); -} - -void PropertyMeshKernel::removeSelfIntersections() -{ - aboutToSetValue(); - _meshObject->removeSelfIntersections(); - hasSetValue(); -} - -void PropertyMeshKernel::removeFoldsOnSurface() -{ - aboutToSetValue(); - _meshObject->removeFoldsOnSurface(); - hasSetValue(); -} - PyObject *PropertyMeshKernel::getPyObject(void) { if (!meshPyObject) { diff --git a/src/Mod/Mesh/App/MeshProperties.h b/src/Mod/Mesh/App/MeshProperties.h index af1cd0f8b4..04bfb8dee9 100644 --- a/src/Mod/Mesh/App/MeshProperties.h +++ b/src/Mod/Mesh/App/MeshProperties.h @@ -179,27 +179,7 @@ public: void finishEditing(); /// Transform the real mesh data void transformGeometry(const Base::Matrix4D &rclMat); - void deletePointIndices ( const std::vector& ); - void deleteFacetIndices ( const std::vector& ); void setPointIndices( const std::vector >& ); - void append(const std::vector& rFaces, - const std::vector& rPoints); - void createSegment(const std::vector& segm); - void smooth(int iter, float d_max); - void clear(); - //@} - - /** @name Mesh validation */ - //@{ - void harmonizeNormals(); - void validateIndices(); - void validateDeformations(float fMaxAngle); - void validateDegenerations(); - void removeDuplicatedPoints(); - void removeDuplicatedFacets(); - void removeNonManifolds(); - void removeSelfIntersections(); - void removeFoldsOnSurface(); //@} /** @name Python interface */ diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index 6070d9fc1e..116979807f 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -370,13 +370,26 @@ an empty dictionary if there is no intersection. - + - Get all planes of the mesh as segment. + getPlanarSegments(dev,[min faces=0]) -> list +Get all planes of the mesh as segment. In the worst case each triangle can be regarded as single plane if none of its neighours is coplanar. + + + getSegmentsByCurvature(list) -> list +The argument list gives a list if tuples where it defines the preferred maximum curvature, +the preferred minumum curvature, the tolerances and the number of minimum faces for the segment. +Example: +c=(1.0, 0.0, 0.1, 0.1, 500) # search for a cylinder with radius 1.0 +p=(0.0, 0.0, 0.1, 0.1, 500) # search for a plane +mesh.getSegmentsByCurvature([c,p]) + + + A collection of the mesh points diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index ace1032894..a2a1e6302d 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -41,6 +41,8 @@ #include "Core/Grid.h" #include "Core/MeshKernel.h" #include "Core/Triangulation.h" +#include "Core/Segmentation.h" +#include "Core/Curvature.h" using namespace Mesh; @@ -165,6 +167,7 @@ PyObject* MeshPy::write(PyObject *args) ext["NAS" ] = MeshCore::MeshIO::NAS; ext["BDF" ] = MeshCore::MeshIO::NAS; ext["PLY" ] = MeshCore::MeshIO::PLY; + ext["APLY"] = MeshCore::MeshIO::APLY; ext["PY" ] = MeshCore::MeshIO::PY; if (ext.find(Ext) != ext.end()) format = ext[Ext]; @@ -490,29 +493,36 @@ PyObject* MeshPy::addFacets(PyObject *args) Py::Sequence seq(*it); if (seq.size() == 3) { if (PyFloat_Check(seq[0].ptr())) { - // always three triple build a triangle + // every three triples build a triangle facet._aclPoints[0] = Base::getVectorFromTuple((*it).ptr()); ++it; facet._aclPoints[1] = Base::getVectorFromTuple((*it).ptr()); ++it; facet._aclPoints[2] = Base::getVectorFromTuple((*it).ptr()); } - else { + else if (seq[0].isSequence()) { + // a sequence of sequence of flots for (int i=0; i<3; i++) { - if (PyObject_TypeCheck(seq[i].ptr(), &(Base::VectorPy::Type))) { - Base::Vector3d p = Py::Vector(seq[i]).toVector(); - facet._aclPoints[i].Set((float)p.x,(float)p.y,(float)p.z); - } - else if (seq[i].isSequence()){ - facet._aclPoints[i] = Base::getVectorFromTuple(seq[i].ptr()); - } + facet._aclPoints[i] = Base::getVectorFromTuple(seq[i].ptr()); } } + else if (PyObject_TypeCheck(seq[0].ptr(), &(Base::VectorPy::Type))) { + // a sequence of vectors + for (int i=0; i<3; i++) { + Base::Vector3d p = Py::Vector(seq[i]).toVector(); + facet._aclPoints[i].Set((float)p.x,(float)p.y,(float)p.z); + } + } + else { + PyErr_SetString(PyExc_Exception, "expect a sequence of floats or Vector"); + return NULL; + } facet.CalcNormal(); facets.push_back(facet); } else { + // 9 consecutive floats expected int index=0; for (int i=0; i<3; i++) { facet._aclPoints[i].x = (float)(double)Py::Float(seq[index++]); @@ -522,7 +532,7 @@ PyObject* MeshPy::addFacets(PyObject *args) facet.CalcNormal(); facets.push_back(facet); } - } + } // sequence } getMeshObjectPtr()->addFacets(facets); @@ -1348,15 +1358,16 @@ PyObject* MeshPy::nearestFacetOnRay(PyObject *args) } } -PyObject* MeshPy::getPlanes(PyObject *args) +PyObject* MeshPy::getPlanarSegments(PyObject *args) { float dev; - if (!PyArg_ParseTuple(args, "f",&dev)) + unsigned long minFacets=0; + if (!PyArg_ParseTuple(args, "f|k",&dev,&minFacets)) return NULL; Mesh::MeshObject* mesh = getMeshObjectPtr(); std::vector segments = mesh->getSegmentsFromType - (Mesh::MeshObject::PLANE, Mesh::Segment(mesh,false), dev); + (Mesh::MeshObject::PLANE, Mesh::Segment(mesh,false), dev, minFacets); Py::List s; for (std::vector::iterator it = segments.begin(); it != segments.end(); ++it) { @@ -1371,6 +1382,47 @@ PyObject* MeshPy::getPlanes(PyObject *args) return Py::new_reference_to(s); } +PyObject* MeshPy::getSegmentsByCurvature(PyObject *args) +{ + PyObject* l; + if (!PyArg_ParseTuple(args, "O!",&PyList_Type,&l)) + return NULL; + + const MeshCore::MeshKernel& kernel = getMeshObjectPtr()->getKernel(); + MeshCore::MeshSegmentAlgorithm finder(kernel); + MeshCore::MeshCurvature meshCurv(kernel); + meshCurv.ComputePerVertex(); + + Py::List func(l); + std::vector segm; + for (Py::List::iterator it = func.begin(); it != func.end(); ++it) { + Py::Tuple t(*it); + float c1 = (float)Py::Float(t[0]); + float c2 = (float)Py::Float(t[1]); + float tol1 = (float)Py::Float(t[2]); + float tol2 = (float)Py::Float(t[3]); + int num = (int)Py::Int(t[4]); + segm.push_back(new MeshCore::MeshCurvatureFreeformSegment(meshCurv.GetCurvature(), num, tol1, tol2, c1, c2)); + } + + finder.FindSegments(segm); + + Py::List list; + for (std::vector::iterator segmIt = segm.begin(); segmIt != segm.end(); ++segmIt) { + const std::vector& data = (*segmIt)->GetSegments(); + for (std::vector::const_iterator it = data.begin(); it != data.end(); ++it) { + Py::List ary; + for (MeshCore::MeshSegment::const_iterator jt = it->begin(); jt != it->end(); ++jt) { + ary.append(Py::Int((int)*jt)); + } + list.append(ary); + } + delete (*segmIt); + } + + return Py::new_reference_to(list); +} + Py::Int MeshPy::getCountPoints(void) const { return Py::Int((long)getMeshObjectPtr()->countPoints()); diff --git a/src/Mod/Mesh/App/WildMagic4/Wm4Query2Filtered.inl b/src/Mod/Mesh/App/WildMagic4/Wm4Query2Filtered.inl index 772c4c3257..8306c72c39 100644 --- a/src/Mod/Mesh/App/WildMagic4/Wm4Query2Filtered.inl +++ b/src/Mod/Mesh/App/WildMagic4/Wm4Query2Filtered.inl @@ -1,105 +1,105 @@ -// Wild Magic Source Code -// David Eberly -// http://www.geometrictools.com -// Copyright (c) 1998-2007 -// -// 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. The license is available for reading at -// either of the locations: -// http://www.gnu.org/copyleft/lgpl.html -// http://www.geometrictools.com/License/WildMagicLicense.pdf -// The license applies to versions 0 through 4 of Wild Magic. -// -// Version: 4.0.0 (2006/06/28) - -namespace Wm4 -{ -//---------------------------------------------------------------------------- -template -Query2Filtered::Query2Filtered (int iVQuantity, - const Vector2* akVertex, Real fUncertainty) - : - Query2(iVQuantity,akVertex), - m_kRQuery(iVQuantity,akVertex) -{ - assert((Real)0.0 <= fUncertainty && fUncertainty <= (Real)1.0); - m_fUncertainty = fUncertainty; -} -//---------------------------------------------------------------------------- -template -Query2Filtered::~Query2Filtered () -{ -} -//---------------------------------------------------------------------------- -template -Query::Type Query2Filtered::GetType () const -{ - return Query::QT_FILTERED; -} -//---------------------------------------------------------------------------- -template -int Query2Filtered::ToLine (const Vector2& rkP, int iV0, int iV1) - const -{ - const Vector2& rkV0 = m_akVertex[iV0]; - const Vector2& rkV1 = m_akVertex[iV1]; - - Real fX0 = rkP[0] - rkV0[0]; - Real fY0 = rkP[1] - rkV0[1]; - Real fX1 = rkV1[0] - rkV0[0]; - Real fY1 = rkV1[1] - rkV0[1]; - - Real fLen0 = Math::Sqrt(fX0*fX0 + fY0*fY0); - Real fLen1 = Math::Sqrt(fX1*fX1 + fY1*fY1); - Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1; - - Real fDet2 = Det2(fX0,fY0,fX1,fY1); - if (Math::FAbs(fDet2) >= fScaledUncertainty) - { - return (fDet2 > (Real)0.0 ? +1 : (fDet2 < (Real)0.0 ? -1 : 0)); - } - - return m_kRQuery.ToLine(rkP,iV0,iV1); -} -//---------------------------------------------------------------------------- -template -int Query2Filtered::ToCircumcircle (const Vector2& rkP, int iV0, - int iV1, int iV2) const -{ - const Vector2& rkV0 = m_akVertex[iV0]; - const Vector2& rkV1 = m_akVertex[iV1]; - const Vector2& rkV2 = m_akVertex[iV2]; - - Real fS0x = rkV0[0] + rkP[0]; - Real fD0x = rkV0[0] - rkP[0]; - Real fS0y = rkV0[1] + rkP[1]; - Real fD0y = rkV0[1] - rkP[1]; - Real fS1x = rkV1[0] + rkP[0]; - Real fD1x = rkV1[0] - rkP[0]; - Real fS1y = rkV1[1] + rkP[1]; - Real fD1y = rkV1[1] - rkP[1]; - Real fS2x = rkV2[0] + rkP[0]; - Real fD2x = rkV2[0] - rkP[0]; - Real fS2y = rkV2[1] + rkP[1]; - Real fD2y = rkV2[1] - rkP[1]; - Real fZ0 = fS0x*fD0x + fS0y*fD0y; - Real fZ1 = fS1x*fD1x + fS1y*fD1y; - Real fZ2 = fS2x*fD2x + fS2y*fD2y; - - Real fLen0 = Math::Sqrt(fD0x*fD0x + fD0y*fD0y + fZ0*fZ0); - Real fLen1 = Math::Sqrt(fD1x*fD1x + fD1y*fD1y + fZ1*fZ1); - Real fLen2 = Math::Sqrt(fD2x*fD2x + fD2y*fD2y + fZ2*fZ2); - Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1*fLen2; - - Real fDet3 = Det3(fD0x,fD0y,fZ0,fD1x,fD1y,fZ1,fD2x,fD2y,fZ2); - if (Math::FAbs(fDet3) >= fScaledUncertainty) - { - return (fDet3 < (Real)0.0 ? 1 : (fDet3 > (Real)0.0 ? -1 : 0)); - } - - return m_kRQuery.ToCircumcircle(rkP,iV0,iV1,iV2); -} -//---------------------------------------------------------------------------- -} //namespace Wm4 +// Wild Magic Source Code +// David Eberly +// http://www.geometrictools.com +// Copyright (c) 1998-2007 +// +// 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. The license is available for reading at +// either of the locations: +// http://www.gnu.org/copyleft/lgpl.html +// http://www.geometrictools.com/License/WildMagicLicense.pdf +// The license applies to versions 0 through 4 of Wild Magic. +// +// Version: 4.0.0 (2006/06/28) + +namespace Wm4 +{ +//---------------------------------------------------------------------------- +template +Query2Filtered::Query2Filtered (int iVQuantity, + const Vector2* akVertex, Real fUncertainty) + : + Query2(iVQuantity,akVertex), + m_kRQuery(iVQuantity,akVertex) +{ + assert((Real)0.0 <= fUncertainty && fUncertainty <= (Real)1.0); + m_fUncertainty = fUncertainty; +} +//---------------------------------------------------------------------------- +template +Query2Filtered::~Query2Filtered () +{ +} +//---------------------------------------------------------------------------- +template +Query::Type Query2Filtered::GetType () const +{ + return Query::QT_FILTERED; +} +//---------------------------------------------------------------------------- +template +int Query2Filtered::ToLine (const Vector2& rkP, int iV0, int iV1) + const +{ + const Vector2& rkV0 = m_akVertex[iV0]; + const Vector2& rkV1 = m_akVertex[iV1]; + + Real fX0 = rkP[0] - rkV0[0]; + Real fY0 = rkP[1] - rkV0[1]; + Real fX1 = rkV1[0] - rkV0[0]; + Real fY1 = rkV1[1] - rkV0[1]; + + Real fLen0 = Math::Sqrt(fX0*fX0 + fY0*fY0); + Real fLen1 = Math::Sqrt(fX1*fX1 + fY1*fY1); + Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1; + + Real fDet2 = this->Det2(fX0,fY0,fX1,fY1); + if (Math::FAbs(fDet2) >= fScaledUncertainty) + { + return (fDet2 > (Real)0.0 ? +1 : (fDet2 < (Real)0.0 ? -1 : 0)); + } + + return m_kRQuery.ToLine(rkP,iV0,iV1); +} +//---------------------------------------------------------------------------- +template +int Query2Filtered::ToCircumcircle (const Vector2& rkP, int iV0, + int iV1, int iV2) const +{ + const Vector2& rkV0 = m_akVertex[iV0]; + const Vector2& rkV1 = m_akVertex[iV1]; + const Vector2& rkV2 = m_akVertex[iV2]; + + Real fS0x = rkV0[0] + rkP[0]; + Real fD0x = rkV0[0] - rkP[0]; + Real fS0y = rkV0[1] + rkP[1]; + Real fD0y = rkV0[1] - rkP[1]; + Real fS1x = rkV1[0] + rkP[0]; + Real fD1x = rkV1[0] - rkP[0]; + Real fS1y = rkV1[1] + rkP[1]; + Real fD1y = rkV1[1] - rkP[1]; + Real fS2x = rkV2[0] + rkP[0]; + Real fD2x = rkV2[0] - rkP[0]; + Real fS2y = rkV2[1] + rkP[1]; + Real fD2y = rkV2[1] - rkP[1]; + Real fZ0 = fS0x*fD0x + fS0y*fD0y; + Real fZ1 = fS1x*fD1x + fS1y*fD1y; + Real fZ2 = fS2x*fD2x + fS2y*fD2y; + + Real fLen0 = Math::Sqrt(fD0x*fD0x + fD0y*fD0y + fZ0*fZ0); + Real fLen1 = Math::Sqrt(fD1x*fD1x + fD1y*fD1y + fZ1*fZ1); + Real fLen2 = Math::Sqrt(fD2x*fD2x + fD2y*fD2y + fZ2*fZ2); + Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1*fLen2; + + Real fDet3 = this->Det3(fD0x,fD0y,fZ0,fD1x,fD1y,fZ1,fD2x,fD2y,fZ2); + if (Math::FAbs(fDet3) >= fScaledUncertainty) + { + return (fDet3 < (Real)0.0 ? 1 : (fDet3 > (Real)0.0 ? -1 : 0)); + } + + return m_kRQuery.ToCircumcircle(rkP,iV0,iV1,iV2); +} +//---------------------------------------------------------------------------- +} //namespace Wm4 diff --git a/src/Mod/Mesh/App/WildMagic4/Wm4Query3Filtered.inl b/src/Mod/Mesh/App/WildMagic4/Wm4Query3Filtered.inl index 45a7239960..75224ee524 100644 --- a/src/Mod/Mesh/App/WildMagic4/Wm4Query3Filtered.inl +++ b/src/Mod/Mesh/App/WildMagic4/Wm4Query3Filtered.inl @@ -1,129 +1,129 @@ -// Wild Magic Source Code -// David Eberly -// http://www.geometrictools.com -// Copyright (c) 1998-2007 -// -// 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. The license is available for reading at -// either of the locations: -// http://www.gnu.org/copyleft/lgpl.html -// http://www.geometrictools.com/License/WildMagicLicense.pdf -// The license applies to versions 0 through 4 of Wild Magic. -// -// Version: 4.0.0 (2006/06/28) - -namespace Wm4 -{ -//---------------------------------------------------------------------------- -template -Query3Filtered::Query3Filtered (int iVQuantity, - const Vector3* akVertex, Real fUncertainty) - : - Query3(iVQuantity,akVertex), - m_kRQuery(iVQuantity,akVertex) -{ - assert((Real)0.0 <= fUncertainty && fUncertainty <= (Real)1.0); - m_fUncertainty = fUncertainty; -} -//---------------------------------------------------------------------------- -template -Query3Filtered::~Query3Filtered () -{ -} -//---------------------------------------------------------------------------- -template -Query::Type Query3Filtered::GetType () const -{ - return Query::QT_FILTERED; -} -//---------------------------------------------------------------------------- -template -int Query3Filtered::ToPlane (const Vector3& rkP, int iV0, int iV1, - int iV2) const -{ - const Vector3& rkV0 = m_akVertex[iV0]; - const Vector3& rkV1 = m_akVertex[iV1]; - const Vector3& rkV2 = m_akVertex[iV2]; - - Real fX0 = rkP[0] - rkV0[0]; - Real fY0 = rkP[1] - rkV0[1]; - Real fZ0 = rkP[2] - rkV0[2]; - Real fX1 = rkV1[0] - rkV0[0]; - Real fY1 = rkV1[1] - rkV0[1]; - Real fZ1 = rkV1[2] - rkV0[2]; - Real fX2 = rkV2[0] - rkV0[0]; - Real fY2 = rkV2[1] - rkV0[1]; - Real fZ2 = rkV2[2] - rkV0[2]; - - Real fLen0 = Math::Sqrt(fX0*fX0 + fY0*fY0 + fZ0*fZ0); - Real fLen1 = Math::Sqrt(fX1*fX1 + fY1*fY1 + fZ1*fZ1); - Real fLen2 = Math::Sqrt(fX2*fX2 + fY2*fY2 + fZ2*fZ2); - Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1*fLen2; - - Real fDet3 = Det3(fX0,fY0,fZ0,fX1,fY1,fZ1,fX2,fY2,fZ2); - if (Math::FAbs(fDet3) >= fScaledUncertainty) - { - return (fDet3 > (Real)0.0 ? +1 : (fDet3 < (Real)0.0 ? -1 : 0)); - } - - return m_kRQuery.ToPlane(rkP,iV0,iV1,iV2); -} -//---------------------------------------------------------------------------- -template -int Query3Filtered::ToCircumsphere (const Vector3& rkP, int iV0, - int iV1, int iV2, int iV3) const -{ - const Vector3& rkV0 = m_akVertex[iV0]; - const Vector3& rkV1 = m_akVertex[iV1]; - const Vector3& rkV2 = m_akVertex[iV2]; - const Vector3& rkV3 = m_akVertex[iV3]; - - Real fS0x = rkV0[0] + rkP[0]; - Real fD0x = rkV0[0] - rkP[0]; - Real fS0y = rkV0[1] + rkP[1]; - Real fD0y = rkV0[1] - rkP[1]; - Real fS0z = rkV0[2] + rkP[2]; - Real fD0z = rkV0[2] - rkP[2]; - Real fS1x = rkV1[0] + rkP[0]; - Real fD1x = rkV1[0] - rkP[0]; - Real fS1y = rkV1[1] + rkP[1]; - Real fD1y = rkV1[1] - rkP[1]; - Real fS1z = rkV1[2] + rkP[2]; - Real fD1z = rkV1[2] - rkP[2]; - Real fS2x = rkV2[0] + rkP[0]; - Real fD2x = rkV2[0] - rkP[0]; - Real fS2y = rkV2[1] + rkP[1]; - Real fD2y = rkV2[1] - rkP[1]; - Real fS2z = rkV2[2] + rkP[2]; - Real fD2z = rkV2[2] - rkP[2]; - Real fS3x = rkV3[0] + rkP[0]; - Real fD3x = rkV3[0] - rkP[0]; - Real fS3y = rkV3[1] + rkP[1]; - Real fD3y = rkV3[1] - rkP[1]; - Real fS3z = rkV3[2] + rkP[2]; - Real fD3z = rkV3[2] - rkP[2]; - Real fW0 = fS0x*fD0x + fS0y*fD0y + fS0z*fD0z; - Real fW1 = fS1x*fD1x + fS1y*fD1y + fS1z*fD1z; - Real fW2 = fS2x*fD2x + fS2y*fD2y + fS2z*fD2z; - Real fW3 = fS3x*fD3x + fS3y*fD3y + fS3z*fD3z; - - Real fLen0 = Math::Sqrt(fD0x*fD0x+fD0y*fD0y+fD0z*fD0z+fW0*fW0); - Real fLen1 = Math::Sqrt(fD1x*fD1x+fD1y*fD1y+fD1z*fD1z+fW1*fW1); - Real fLen2 = Math::Sqrt(fD2x*fD2x+fD2y*fD2y+fD2z*fD2z+fW2*fW2); - Real fLen3 = Math::Sqrt(fD3x*fD3x+fD3y*fD3y+fD3z*fD3z+fW3*fW3); - Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1*fLen2*fLen3; - - Real fDet4 = Det4(fD0x,fD0y,fD0z,fW0,fD1x,fD1y,fD1z,fW1,fD2x, - fD2y,fD2z,fW2,fD3x,fD3y,fD3z,fW3); - - if (Math::FAbs(fDet4) >= fScaledUncertainty) - { - return (fDet4 > (Real)0.0 ? 1 : (fDet4 < (Real)0.0 ? -1 : 0)); - } - - return m_kRQuery.ToCircumsphere(rkP,iV0,iV1,iV2,iV3); -} -//---------------------------------------------------------------------------- -} //namespace Wm4 +// Wild Magic Source Code +// David Eberly +// http://www.geometrictools.com +// Copyright (c) 1998-2007 +// +// 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. The license is available for reading at +// either of the locations: +// http://www.gnu.org/copyleft/lgpl.html +// http://www.geometrictools.com/License/WildMagicLicense.pdf +// The license applies to versions 0 through 4 of Wild Magic. +// +// Version: 4.0.0 (2006/06/28) + +namespace Wm4 +{ +//---------------------------------------------------------------------------- +template +Query3Filtered::Query3Filtered (int iVQuantity, + const Vector3* akVertex, Real fUncertainty) + : + Query3(iVQuantity,akVertex), + m_kRQuery(iVQuantity,akVertex) +{ + assert((Real)0.0 <= fUncertainty && fUncertainty <= (Real)1.0); + m_fUncertainty = fUncertainty; +} +//---------------------------------------------------------------------------- +template +Query3Filtered::~Query3Filtered () +{ +} +//---------------------------------------------------------------------------- +template +Query::Type Query3Filtered::GetType () const +{ + return Query::QT_FILTERED; +} +//---------------------------------------------------------------------------- +template +int Query3Filtered::ToPlane (const Vector3& rkP, int iV0, int iV1, + int iV2) const +{ + const Vector3& rkV0 = m_akVertex[iV0]; + const Vector3& rkV1 = m_akVertex[iV1]; + const Vector3& rkV2 = m_akVertex[iV2]; + + Real fX0 = rkP[0] - rkV0[0]; + Real fY0 = rkP[1] - rkV0[1]; + Real fZ0 = rkP[2] - rkV0[2]; + Real fX1 = rkV1[0] - rkV0[0]; + Real fY1 = rkV1[1] - rkV0[1]; + Real fZ1 = rkV1[2] - rkV0[2]; + Real fX2 = rkV2[0] - rkV0[0]; + Real fY2 = rkV2[1] - rkV0[1]; + Real fZ2 = rkV2[2] - rkV0[2]; + + Real fLen0 = Math::Sqrt(fX0*fX0 + fY0*fY0 + fZ0*fZ0); + Real fLen1 = Math::Sqrt(fX1*fX1 + fY1*fY1 + fZ1*fZ1); + Real fLen2 = Math::Sqrt(fX2*fX2 + fY2*fY2 + fZ2*fZ2); + Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1*fLen2; + + Real fDet3 = this->Det3(fX0,fY0,fZ0,fX1,fY1,fZ1,fX2,fY2,fZ2); + if (Math::FAbs(fDet3) >= fScaledUncertainty) + { + return (fDet3 > (Real)0.0 ? +1 : (fDet3 < (Real)0.0 ? -1 : 0)); + } + + return m_kRQuery.ToPlane(rkP,iV0,iV1,iV2); +} +//---------------------------------------------------------------------------- +template +int Query3Filtered::ToCircumsphere (const Vector3& rkP, int iV0, + int iV1, int iV2, int iV3) const +{ + const Vector3& rkV0 = m_akVertex[iV0]; + const Vector3& rkV1 = m_akVertex[iV1]; + const Vector3& rkV2 = m_akVertex[iV2]; + const Vector3& rkV3 = m_akVertex[iV3]; + + Real fS0x = rkV0[0] + rkP[0]; + Real fD0x = rkV0[0] - rkP[0]; + Real fS0y = rkV0[1] + rkP[1]; + Real fD0y = rkV0[1] - rkP[1]; + Real fS0z = rkV0[2] + rkP[2]; + Real fD0z = rkV0[2] - rkP[2]; + Real fS1x = rkV1[0] + rkP[0]; + Real fD1x = rkV1[0] - rkP[0]; + Real fS1y = rkV1[1] + rkP[1]; + Real fD1y = rkV1[1] - rkP[1]; + Real fS1z = rkV1[2] + rkP[2]; + Real fD1z = rkV1[2] - rkP[2]; + Real fS2x = rkV2[0] + rkP[0]; + Real fD2x = rkV2[0] - rkP[0]; + Real fS2y = rkV2[1] + rkP[1]; + Real fD2y = rkV2[1] - rkP[1]; + Real fS2z = rkV2[2] + rkP[2]; + Real fD2z = rkV2[2] - rkP[2]; + Real fS3x = rkV3[0] + rkP[0]; + Real fD3x = rkV3[0] - rkP[0]; + Real fS3y = rkV3[1] + rkP[1]; + Real fD3y = rkV3[1] - rkP[1]; + Real fS3z = rkV3[2] + rkP[2]; + Real fD3z = rkV3[2] - rkP[2]; + Real fW0 = fS0x*fD0x + fS0y*fD0y + fS0z*fD0z; + Real fW1 = fS1x*fD1x + fS1y*fD1y + fS1z*fD1z; + Real fW2 = fS2x*fD2x + fS2y*fD2y + fS2z*fD2z; + Real fW3 = fS3x*fD3x + fS3y*fD3y + fS3z*fD3z; + + Real fLen0 = Math::Sqrt(fD0x*fD0x+fD0y*fD0y+fD0z*fD0z+fW0*fW0); + Real fLen1 = Math::Sqrt(fD1x*fD1x+fD1y*fD1y+fD1z*fD1z+fW1*fW1); + Real fLen2 = Math::Sqrt(fD2x*fD2x+fD2y*fD2y+fD2z*fD2z+fW2*fW2); + Real fLen3 = Math::Sqrt(fD3x*fD3x+fD3y*fD3y+fD3z*fD3z+fW3*fW3); + Real fScaledUncertainty = m_fUncertainty*fLen0*fLen1*fLen2*fLen3; + + Real fDet4 = this->Det4(fD0x,fD0y,fD0z,fW0,fD1x,fD1y,fD1z,fW1,fD2x, + fD2y,fD2z,fW2,fD3x,fD3y,fD3z,fW3); + + if (Math::FAbs(fDet4) >= fScaledUncertainty) + { + return (fDet4 > (Real)0.0 ? 1 : (fDet4 < (Real)0.0 ? -1 : 0)); + } + + return m_kRQuery.ToCircumsphere(rkP,iV0,iV1,iV2,iV3); +} +//---------------------------------------------------------------------------- +} //namespace Wm4 diff --git a/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp b/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp index b99e5d08b8..ebc8a5fbd5 100644 --- a/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp +++ b/src/Mod/Mesh/App/WildMagic4/Wm4System.cpp @@ -568,7 +568,8 @@ int System::Write8be (FILE* pkFile, int iQuantity, const void* pvData) //---------------------------------------------------------------------------- const char* System::GetPath (const char* acDirectory, const char* acFilename) { -#ifdef __APPLE__ + // #0000656: WildMagic4 doesn't build on 64-bit Mac OS +#if defined(__APPLE__) && !defined(__x86_64__) // An application-relative path is needed for the applications to be able // to find the input data sets. Unfortunately, there is no exact way to // predict which directory the application is run from, since this depends diff --git a/src/Mod/Mesh/BuildRegularGeoms.py b/src/Mod/Mesh/BuildRegularGeoms.py index 8b4003935f..b67985eab4 100644 --- a/src/Mod/Mesh/BuildRegularGeoms.py +++ b/src/Mod/Mesh/BuildRegularGeoms.py @@ -39,12 +39,16 @@ def Cylinder (radius, len, closed, edgelen, count): def Cone (radius1, radius2, len, closed, edgelen, count): polyline = [] - if (closed): - step = radius2 / math.ceil(radius2 / edgelen) - i = 0.0 - while (i < radius2 - step / 2.0): - polyline.append([len, i]) - i = i + step + if (closed): + try: + step = radius2 / math.ceil(radius2 / edgelen) + except ZeroDivisionError: + pass + else: + i = 0.0 + while (i < radius2 - step / 2.0): + polyline.append([len, i]) + i = i + step ct = math.ceil(len / edgelen) step = len / ct @@ -58,12 +62,16 @@ def Cone (radius1, radius2, len, closed, edgelen, count): polyline.append([0.0, radius1]) if (closed): - step = radius1 / math.ceil(radius1 / edgelen) - i = radius1 - step - while (i > 0.0 + step / 2.0): - polyline.append([0.0, i]) - i = i - step - polyline.append([0.0, 0.0]) + try: + step = radius1 / math.ceil(radius1 / edgelen) + except ZeroDivisionError: + pass + else: + i = radius1 - step + while (i > 0.0 + step / 2.0): + polyline.append([0.0, i]) + i = i - step + polyline.append([0.0, 0.0]) return RotationBody(polyline, count) diff --git a/src/Mod/Mesh/Gui/CMakeLists.txt b/src/Mod/Mesh/Gui/CMakeLists.txt index 9941cac13b..ae4701a0f9 100644 --- a/src/Mod/Mesh/Gui/CMakeLists.txt +++ b/src/Mod/Mesh/Gui/CMakeLists.txt @@ -34,6 +34,7 @@ set(Dialogs_UIC_SRCS DlgSettingsMeshView.ui DlgSmoothing.ui RemoveComponents.ui + Segmentation.ui ) qt4_wrap_ui(Dialogs_UIC_HDRS ${Dialogs_UIC_SRCS}) SET(Dialogs_SRCS @@ -53,6 +54,9 @@ SET(Dialogs_SRCS RemoveComponents.ui RemoveComponents.cpp RemoveComponents.h + Segmentation.ui + Segmentation.cpp + Segmentation.h ) SOURCE_GROUP("Dialogs" FILES ${Dialogs_SRCS}) diff --git a/src/Mod/Mesh/Gui/Command.cpp b/src/Mod/Mesh/Gui/Command.cpp index 35228e7780..cc83bdaa0d 100644 --- a/src/Mod/Mesh/Gui/Command.cpp +++ b/src/Mod/Mesh/Gui/Command.cpp @@ -69,6 +69,7 @@ #include "ViewProviderMeshFaceSet.h" #include "ViewProviderCurvature.h" #include "MeshEditor.h" +#include "Segmentation.h" using namespace Mesh; @@ -289,11 +290,12 @@ void CmdMeshImport::activated(int iMsg) { // use current path as default QStringList filter; - filter << QObject::tr("All Mesh Files (*.stl *.ast *.bms *.obj *.ply)"); + filter << QObject::tr("All Mesh Files (*.stl *.ast *.bms *.obj *.off *.ply)"); filter << QObject::tr("Binary STL (*.stl)"); filter << QObject::tr("ASCII STL (*.ast)"); filter << QObject::tr("Binary Mesh (*.bms)"); filter << QObject::tr("Alias Mesh (*.obj)"); + filter << QObject::tr("Object File Format (*.off)"); filter << QObject::tr("Inventor V2.1 ascii (*.iv)"); filter << QObject::tr("Stanford Polygon (*.ply)"); //filter << "Nastran (*.nas *.bdf)"; @@ -1367,6 +1369,39 @@ bool CmdMeshFillInteractiveHole::isActive(void) return false; } +DEF_STD_CMD_A(CmdMeshSegmentation); + +CmdMeshSegmentation::CmdMeshSegmentation() + : Command("Mesh_Segmentation") +{ + sAppModule = "Mesh"; + sGroup = QT_TR_NOOP("Mesh"); + sMenuText = QT_TR_NOOP("Create mesh segments..."); + sToolTipText = QT_TR_NOOP("Create mesh segments"); + sWhatsThis = "Mesh_Segmentation"; + sStatusTip = QT_TR_NOOP("Create mesh segments"); +} + +void CmdMeshSegmentation::activated(int iMsg) +{ + std::vector objs = Gui::Selection().getObjectsOfType + (Mesh::Feature::getClassTypeId()); + Mesh::Feature* mesh = static_cast(objs.front()); + Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); + if (!dlg) { + dlg = new MeshGui::TaskSegmentation(mesh); + } + Gui::Control().showDialog(dlg); +} + +bool CmdMeshSegmentation::isActive(void) +{ + if (Gui::Control().activeDialog()) + return false; + return Gui::Selection().countObjectsOfType + (Mesh::Feature::getClassTypeId()) == 1; +} + void CreateMeshCommands(void) { Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager(); @@ -1399,4 +1434,5 @@ void CreateMeshCommands(void) rcCmdMgr.addCommand(new CmdMeshFillInteractiveHole()); rcCmdMgr.addCommand(new CmdMeshRemoveCompByHand()); rcCmdMgr.addCommand(new CmdMeshFromGeometry()); + rcCmdMgr.addCommand(new CmdMeshSegmentation()); } diff --git a/src/Mod/Mesh/Gui/Makefile.am b/src/Mod/Mesh/Gui/Makefile.am index 82cde54eec..dd4405cd7c 100644 --- a/src/Mod/Mesh/Gui/Makefile.am +++ b/src/Mod/Mesh/Gui/Makefile.am @@ -7,6 +7,7 @@ BUILT_SOURCES=\ ui_DlgSettingsMeshView.h \ ui_DlgSmoothing.h \ ui_RemoveComponents.h \ + ui_Segmentation.h \ moc_DlgEvaluateMeshImp.cpp \ moc_DlgRegularSolidImp.cpp \ moc_DlgSettingsMeshView.cpp \ @@ -34,6 +35,7 @@ libMeshGui_la_SOURCES=\ PropertyEditorMesh.cpp \ RemoveComponents.cpp \ RemoveComponents.h \ + Segmentation.cpp \ SoFCIndexedFaceSet.cpp \ SoFCMeshObject.cpp \ ViewProvider.cpp \ @@ -47,6 +49,7 @@ libMeshGui_la_SOURCES=\ include_HEADERS=\ PropertyEditorMesh.h \ + Segmentation.h \ SoFCIndexedFaceSet.h \ SoFCMeshObject.h \ ViewProvider.h \ @@ -66,7 +69,7 @@ libMeshGui_la_CPPFLAGS = -DMeshExport= -DMeshGuiExport= libMeshGui_la_LIBADD = \ @BOOST_SIGNALS_LIB@ @BOOST_SYSTEM_LIB@ \ - @GL_LIBS@ \ + @GL_LIBS@ @ZIPIOS_LIB@ \ -lFreeCADBase \ -lFreeCADApp \ -lFreeCADGui \ @@ -127,6 +130,7 @@ EXTRA_DIST = \ DlgSettingsMeshView.ui \ DlgSmoothing.ui \ RemoveComponents.ui \ + Segmentation.ui \ Resources/Mesh.qrc \ Resources/translations/Mesh_af.qm \ Resources/translations/Mesh_af.ts \ @@ -146,6 +150,8 @@ EXTRA_DIST = \ Resources/translations/Mesh_nl.ts \ Resources/translations/Mesh_no.qm \ Resources/translations/Mesh_no.ts \ + Resources/translations/Mesh_pl.qm \ + Resources/translations/Mesh_pl.ts \ Resources/translations/Mesh_pt.qm \ Resources/translations/Mesh_pt.ts \ Resources/translations/Mesh_ru.qm \ diff --git a/src/Mod/Mesh/Gui/Resources/Mesh.qrc b/src/Mod/Mesh/Gui/Resources/Mesh.qrc index 347f3b8aa2..940c6d4401 100644 --- a/src/Mod/Mesh/Gui/Resources/Mesh.qrc +++ b/src/Mod/Mesh/Gui/Resources/Mesh.qrc @@ -12,6 +12,7 @@ translations/Mesh_it.qm translations/Mesh_nl.qm translations/Mesh_no.qm + translations/Mesh_pl.qm translations/Mesh_pt.qm translations/Mesh_ru.qm translations/Mesh_se.qm diff --git a/src/Mod/Mesh/Gui/Segmentation.cpp b/src/Mod/Mesh/Gui/Segmentation.cpp new file mode 100644 index 0000000000..de2b81d48e --- /dev/null +++ b/src/Mod/Mesh/Gui/Segmentation.cpp @@ -0,0 +1,152 @@ +/*************************************************************************** + * Copyright (c) 2012 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 +#endif + +#include "Segmentation.h" +#include "ui_Segmentation.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace MeshGui; + +Segmentation::Segmentation(Mesh::Feature* mesh, QWidget* parent, Qt::WFlags fl) + : QWidget(parent, fl), myMesh(mesh) +{ + ui = new Ui_Segmentation; + ui->setupUi(this); + ui->numPln->setRange(1, INT_MAX); + ui->numPln->setValue(100); + ui->numCyl->setRange(1, INT_MAX); + ui->numCyl->setValue(100); + ui->numSph->setRange(1, INT_MAX); + ui->numSph->setValue(100); +} + +Segmentation::~Segmentation() +{ + // no need to delete child widgets, Qt does it all for us + delete ui; +} + +void Segmentation::accept() +{ + const Mesh::MeshObject* mesh = myMesh->Mesh.getValuePtr(); + // make a copy because we might smooth the mesh before + MeshCore::MeshKernel kernel = mesh->getKernel(); + + if (ui->checkBoxSmooth->isChecked()) { + MeshCore::LaplaceSmoothing smoother(kernel); + smoother.Smooth(ui->smoothSteps->value()); + } + + MeshCore::MeshSegmentAlgorithm finder(kernel); + MeshCore::MeshCurvature meshCurv(kernel); + meshCurv.ComputePerVertex(); + + std::vector segm; + if (ui->groupBoxCyl->isChecked()) { + segm.push_back(new MeshCore::MeshCurvatureCylindricalSegment + (meshCurv.GetCurvature(), ui->numCyl->value(), ui->tol1Cyl->value(), ui->tol2Cyl->value(), ui->radCyl->value())); + } + if (ui->groupBoxSph->isChecked()) { + segm.push_back(new MeshCore::MeshCurvatureSphericalSegment + (meshCurv.GetCurvature(), ui->numSph->value(), ui->tolSph->value(), ui->radSph->value())); + } + if (ui->groupBoxPln->isChecked()) { + segm.push_back(new MeshCore::MeshCurvaturePlanarSegment + (meshCurv.GetCurvature(), ui->numPln->value(), ui->tolPln->value())); + } + finder.FindSegments(segm); + + App::Document* document = App::GetApplication().getActiveDocument(); + document->openTransaction("Segmentation"); + + std::string internalname = "Segments_"; + internalname += myMesh->getNameInDocument(); + App::DocumentObjectGroup* group = static_cast(document->addObject + ("App::DocumentObjectGroup", internalname.c_str())); + std::string labelname = "Segments "; + labelname += myMesh->Label.getValue(); + group->Label.setValue(labelname); + for (std::vector::iterator it = segm.begin(); it != segm.end(); ++it) { + const std::vector& data = (*it)->GetSegments(); + for (std::vector::const_iterator jt = data.begin(); jt != data.end(); ++jt) { + Mesh::MeshObject* segment = mesh->meshFromSegment(*jt); + Mesh::Feature* feaSegm = static_cast(group->addObject("Mesh::Feature", "Segment")); + Mesh::MeshObject* feaMesh = feaSegm->Mesh.startEditing(); + feaMesh->swap(*segment); + feaSegm->Mesh.finishEditing(); + delete segment; + + std::stringstream label; + label << feaSegm->Label.getValue() << " (" << (*it)->GetType() << ")"; + feaSegm->Label.setValue(label.str()); + } + delete (*it); + } + document->commitTransaction(); +} + +void Segmentation::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + ui->retranslateUi(this); + } + QWidget::changeEvent(e); +} + +// --------------------------------------- + +/* TRANSLATOR MeshGui::TaskRemoveComponents */ + +TaskSegmentation::TaskSegmentation(Mesh::Feature* mesh) +{ + widget = new Segmentation(mesh); + taskbox = new Gui::TaskView::TaskBox( + QPixmap(), widget->windowTitle(), false, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskSegmentation::~TaskSegmentation() +{ + // automatically deleted in the sub-class +} + +bool TaskSegmentation::accept() +{ + widget->accept(); + return true; +} diff --git a/src/Mod/Mesh/Gui/Segmentation.h b/src/Mod/Mesh/Gui/Segmentation.h new file mode 100644 index 0000000000..95d1411635 --- /dev/null +++ b/src/Mod/Mesh/Gui/Segmentation.h @@ -0,0 +1,74 @@ +/*************************************************************************** + * Copyright (c) 2012 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 * + * * + ***************************************************************************/ + + +#ifndef MESHGUI_SEGMENTATION_H +#define MESHGUI_SEGMENTATION_H + +#include +#include +#include + +// forward declarations +namespace Mesh { class Feature; } + +namespace MeshGui { +class Ui_Segmentation; + +class MeshGuiExport Segmentation : public QWidget +{ +public: + Segmentation(Mesh::Feature* mesh, QWidget* parent = 0, Qt::WFlags fl = 0); + ~Segmentation(); + void accept(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui_Segmentation* ui; + Mesh::Feature* myMesh; +}; + +/** + * Embed the panel into a task dialog. + */ +class TaskSegmentation : public Gui::TaskView::TaskDialog +{ +public: + TaskSegmentation(Mesh::Feature* mesh); + ~TaskSegmentation(); + +public: + bool accept(); + + virtual QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; } + +private: + Segmentation* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} + +#endif // MESHGUI_SEGMENTATION_H diff --git a/src/Mod/Mesh/Gui/Segmentation.ui b/src/Mod/Mesh/Gui/Segmentation.ui new file mode 100644 index 0000000000..b6ce13bd86 --- /dev/null +++ b/src/Mod/Mesh/Gui/Segmentation.ui @@ -0,0 +1,244 @@ + + + MeshGui::Segmentation + + + + 0 + 0 + 289 + 379 + + + + Mesh segmentation + + + + + + Smooth mesh + + + true + + + + + + + 3 + + + + + + + Plane + + + true + + + + + + Tolerance + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Minumum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + Cylinder + + + true + + + + + + Radius + + + + + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + Tolerance (Flat) + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Tolerance (Curved) + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + Sphere + + + true + + + + + + Radius + + + + + + + 0.100000000000000 + + + 5.000000000000000 + + + + + + + Tolerance + + + + + + + 0.100000000000000 + + + 0.100000000000000 + + + + + + + Minimum number of faces + + + + + + + 100000 + + + 100 + + + + + + + + + + + + checkBoxSmooth + toggled(bool) + smoothSteps + setEnabled(bool) + + + 75 + 24 + + + 188 + 19 + + + + + diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index db7e99057c..d927661904 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -27,6 +27,8 @@ # include # include # include +# include +# include # include # include # include @@ -44,6 +46,7 @@ # include # include # include +# include #endif /// Here the FreeCAD includes sorted by Base,App,Gui...... @@ -63,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +86,7 @@ #include #include #include +#include #include "ViewProvider.h" #include "SoFCIndexedFaceSet.h" @@ -484,6 +489,69 @@ std::vector ViewProviderMesh::getDisplayModes(void) const return StrList; } +bool ViewProviderMesh::exportToVrml(const char* filename, const MeshCore::Material& mat, bool binary) const +{ + SoCoordinate3* coords = new SoCoordinate3(); + SoIndexedFaceSet* faces = new SoIndexedFaceSet(); + ViewProviderMeshBuilder builder; + builder.createMesh(&static_cast(pcObject)->Mesh, coords, faces); + + SoMaterialBinding* binding = new SoMaterialBinding; + SoMaterial* material = new SoMaterial; + + if (mat.diffuseColor.size() == coords->point.getNum()) { + binding->value = SoMaterialBinding::PER_VERTEX_INDEXED; + } + else if (mat.diffuseColor.size() == faces->coordIndex.getNum()/4) { + binding->value = SoMaterialBinding::PER_FACE_INDEXED; + } + + if (mat.diffuseColor.size() > 1) { + material->diffuseColor.setNum(mat.diffuseColor.size()); + SbColor* colors = material->diffuseColor.startEditing(); + for (unsigned int i=0; idiffuseColor.finishEditing(); + } + + SoGroup* group = new SoGroup(); + group->addChild(material); + group->addChild(binding); + group->addChild(new SoTransform()); + group->addChild(coords); + group->addChild(faces); + + SoToVRML2Action tovrml2; + group->ref(); + tovrml2.apply(group); + group->unref(); + SoVRMLGroup *vrmlRoot = tovrml2.getVRML2SceneGraph(); + vrmlRoot->ref(); + std::string buffer = Gui::SoFCDB::writeNodesToString(vrmlRoot); + vrmlRoot->unref(); // release the memory as soon as possible + + Base::FileInfo fi(filename); + if (binary) { + Base::ofstream str(fi, std::ios::out | std::ios::binary); + zipios::GZIPOutputStream gzip(str); + if (gzip) { + gzip << buffer; + gzip.close(); + return true; + } + } + else { + Base::ofstream str(fi, std::ios::out); + if (str) { + str << buffer; + str.close(); + return true; + } + } + + return false; +} + bool ViewProviderMesh::setEdit(int ModNum) { if (ModNum == ViewProvider::Transform) @@ -1045,13 +1113,7 @@ void ViewProviderMesh::cutMesh(const std::vector& picked, // Get the facet indices inside the tool mesh std::vector indices; getFacetsFromPolygon(picked, Viewer, inner, indices); - - // Get the attached mesh property - Mesh::PropertyMeshKernel& meshProp = static_cast(pcObject)->Mesh; - - //Remove the facets from the mesh and open a transaction object for the undo/redo stuff - meshProp.deleteFacetIndices(indices); - pcObject->purgeTouched(); + removeFacets(indices); } void ViewProviderMesh::trimMesh(const std::vector& polygon, @@ -1137,7 +1199,7 @@ void ViewProviderMesh::splitMesh(const MeshCore::MeshKernel& toolMesh, const Bas // Remove the facets from the mesh and create a new one Mesh::MeshObject* kernel = meshProp.getValue().meshFromSegment(indices); - meshProp.deleteFacetIndices(indices); + removeFacets(indices); Mesh::Feature* splitMesh = static_cast(App::GetApplication().getActiveDocument() ->addObject("Mesh::Feature",pcObject->getNameInDocument())); // Note: deletes also kernel @@ -1167,7 +1229,9 @@ void ViewProviderMesh::segmentMesh(const MeshCore::MeshKernel& toolMesh, const B indices = complementary; } - meshProp.createSegment(indices); + Mesh::MeshObject* kernel = meshProp.startEditing(); + kernel->addSegment(indices); + meshProp.finishEditing(); static_cast(pcObject)->purgeTouched(); } @@ -1401,10 +1465,23 @@ void ViewProviderMesh::fillHole(unsigned long uFacet) //add the facets to the mesh and open a transaction object for the undo/redo stuff Gui::Application::Instance->activeDocument()->openCommand("Fill hole"); - fea->Mesh.append(newFacets, newPoints); + Mesh::MeshObject* kernel = fea->Mesh.startEditing(); + kernel->addFacets(newFacets, newPoints); + fea->Mesh.finishEditing(); Gui::Application::Instance->activeDocument()->commitCommand(); } +void ViewProviderMesh::removeFacets(const std::vector& facets) +{ + // Get the attached mesh property + Mesh::PropertyMeshKernel& meshProp = static_cast(pcObject)->Mesh; + Mesh::MeshObject* kernel = meshProp.startEditing(); + //Remove the facets from the mesh and open a transaction object for the undo/redo stuff + kernel->deleteFacets(facets); + meshProp.finishEditing(); + pcObject->purgeTouched(); +} + void ViewProviderMesh::selectFacet(unsigned long facet) { std::vector selection; diff --git a/src/Mod/Mesh/Gui/ViewProvider.h b/src/Mod/Mesh/Gui/ViewProvider.h index ce0de6b8c9..3bf180bdd5 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.h +++ b/src/Mod/Mesh/Gui/ViewProvider.h @@ -60,6 +60,7 @@ namespace Gui { namespace MeshCore { class MeshKernel; + struct Material; } @@ -122,6 +123,7 @@ public: virtual void setDisplayMode(const char* ModeName); /// returns a list of all possible modes virtual std::vector getDisplayModes(void) const; + bool exportToVrml(const char* filename, const MeshCore::Material&, bool binary=false) const; /** @name Editing */ //@{ @@ -141,6 +143,7 @@ public: std::vector getFacetsOfRegion(const SbViewportRegion&, const SbViewportRegion&, SoCamera*) const; std::vector getVisibleFacetsAfterZoom(const SbBox2s&, const SbViewportRegion&, SoCamera*) const; std::vector getVisibleFacets(const SbViewportRegion&, SoCamera*) const; + virtual void removeFacets(const std::vector&); //@} protected: diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index e365f7152a..25b9bd6568 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -25,12 +25,15 @@ #ifndef _PreComp_ # include +# include +# include #endif #include "Workbench.h" #include #include #include +#include #include "../App/MeshFeature.h" @@ -53,6 +56,106 @@ Workbench::Workbench() Workbench::~Workbench() { } + +class MeshInfoWatcher : public Gui::TaskView::TaskWatcher, public Gui::SelectionObserver +{ +public: + MeshInfoWatcher() : TaskWatcher(0) + { + labelPoints = new QLabel(); + labelPoints->setText(QString::fromAscii("Number of points:")); + + labelFacets = new QLabel(); + labelFacets->setText(QString::fromAscii("Number of facets:")); + + numPoints = new QLabel(); + numFacets = new QLabel(); + + labelMin = new QLabel(); + labelMin->setText(QString::fromAscii("Minumum bound:")); + + labelMax = new QLabel(); + labelMax->setText(QString::fromAscii("Maximum bound:")); + + numMin = new QLabel(); + numMax = new QLabel(); + + QGroupBox* box = new QGroupBox(); + box->setTitle(QString::fromAscii("Mesh info box")); + //box->setAutoFillBackground(true); + QGridLayout* grid = new QGridLayout(box); + grid->addWidget(labelPoints, 0, 0); + grid->addWidget(numPoints, 0, 1); + grid->addWidget(labelFacets, 1, 0); + grid->addWidget(numFacets, 1, 1); + + grid->addWidget(labelMin, 2, 0); + grid->addWidget(numMin, 2, 1); + grid->addWidget(labelMax, 3, 0); + grid->addWidget(numMax, 3, 1); + + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + QPixmap(), QString::fromAscii("Mesh info"), false, 0); + taskbox->groupLayout()->addWidget(box); + Content.push_back(taskbox); + } + bool shouldShow(void) + { + return true; + } + void onSelectionChanged(const Gui::SelectionChanges& msg) + { + Base::BoundBox3d bbox; + unsigned long countPoints=0, countFacets=0; + std::vector mesh = Gui::Selection().getObjectsOfType(); + for (std::vector::iterator it = mesh.begin(); it != mesh.end(); ++it) { + countPoints += (*it)->Mesh.getValue().countPoints(); + countFacets += (*it)->Mesh.getValue().countFacets(); + bbox.Add((*it)->Mesh.getBoundingBox()); + } + + if (countPoints > 0) { + numPoints->setText(QString::number(countPoints)); + numFacets->setText(QString::number(countFacets)); + numMin->setText(QString::fromAscii("X: %1\tY: %2\tZ: %3") + .arg(bbox.MinX).arg(bbox.MinX).arg(bbox.MinX)); + numMax->setText(QString::fromAscii("X: %1\tY: %2\tZ: %3") + .arg(bbox.MaxX).arg(bbox.MaxX).arg(bbox.MaxX)); + } + else { + numPoints->setText(QString::fromAscii("")); + numFacets->setText(QString::fromAscii("")); + numMin->setText(QString::fromAscii("")); + numMax->setText(QString::fromAscii("")); + } + } + +private: + QLabel* labelPoints; + QLabel* numPoints; + QLabel* labelFacets; + QLabel* numFacets; + QLabel* labelMin; + QLabel* numMin; + QLabel* labelMax; + QLabel* numMax; +}; + +void Workbench::activated() +{ + Gui::Workbench::activated(); + + std::vector Watcher; + Watcher.push_back(new MeshInfoWatcher); + addTaskWatcher(Watcher); +} + +void Workbench::deactivated() +{ + Gui::Workbench::deactivated(); + removeTaskWatcher(); + +} void Workbench::setupContextMenu(const char* recipient,Gui::MenuItem* item) const { @@ -87,7 +190,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_FillupHoles" << "Mesh_FillInteractiveHole" << "Mesh_RemoveComponents" << "Mesh_RemoveCompByHand" << "Mesh_AddFacet" << "Mesh_Smoothing" << "Separator" << "Mesh_BuildRegularSolid" << boolean << "Separator" << "Mesh_PolySelect" << "Mesh_PolyCut" - << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_VertexCurvature"; + << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Mesh_Segmentation" + << "Mesh_VertexCurvature"; return root; } diff --git a/src/Mod/Mesh/Gui/Workbench.h b/src/Mod/Mesh/Gui/Workbench.h index 8f933fb23b..fba985f949 100644 --- a/src/Mod/Mesh/Gui/Workbench.h +++ b/src/Mod/Mesh/Gui/Workbench.h @@ -39,6 +39,8 @@ public: Workbench(); virtual ~Workbench(); + void activated(); + void deactivated(); void setupContextMenu(const char* recipient, Gui::MenuItem*) const; protected: diff --git a/src/Mod/Mesh/Init.py b/src/Mod/Mesh/Init.py index 427c366aff..bc76d6a79b 100644 --- a/src/Mod/Mesh/Init.py +++ b/src/Mod/Mesh/Init.py @@ -31,7 +31,7 @@ ParGrp = FreeCAD.ParamGet("System parameter:Modules").GetGroup("Mesh") # Append the open handler -FreeCAD.addImportType("Mesh formats (*.stl *.ast *.bms *.obj *.ply)","Mesh") +FreeCAD.addImportType("Mesh formats (*.stl *.ast *.bms *.obj *.off *.ply)","Mesh") FreeCAD.addExportType("Mesh formats (*.stl *.ast *.bms *.obj *.off *.ply)","Mesh") diff --git a/src/Mod/MeshPart/Gui/Resources/Makefile.am b/src/Mod/MeshPart/Gui/Resources/Makefile.am index cbc6560bb0..15086a83a7 100644 --- a/src/Mod/MeshPart/Gui/Resources/Makefile.am +++ b/src/Mod/MeshPart/Gui/Resources/Makefile.am @@ -26,6 +26,8 @@ EXTRA_DIST = \ translations/MeshPart_nl.ts \ translations/MeshPart_no.qm \ translations/MeshPart_no.ts \ + translations/MeshPart_pl.qm \ + translations/MeshPart_pl.ts \ translations/MeshPart_pt.qm \ translations/MeshPart_pt.ts \ translations/MeshPart_ru.qm \ diff --git a/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc b/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc index 486d2d5bed..2975b17301 100644 --- a/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc +++ b/src/Mod/MeshPart/Gui/Resources/MeshPart.qrc @@ -10,6 +10,7 @@ translations/MeshPart_it.qm translations/MeshPart_nl.qm translations/MeshPart_no.qm + translations/MeshPart_pl.qm translations/MeshPart_pt.qm translations/MeshPart_ru.qm translations/MeshPart_se.qm diff --git a/src/Mod/Part/App/AppPart.cpp b/src/Mod/Part/App/AppPart.cpp index 48eba53431..4980b0be11 100644 --- a/src/Mod/Part/App/AppPart.cpp +++ b/src/Mod/Part/App/AppPart.cpp @@ -74,6 +74,7 @@ #include "SurfaceOfExtrusionPy.h" #include "SurfaceOfRevolutionPy.h" #include "ToroidPy.h" +#include "BRepOffsetAPI_MakePipeShellPy.h" #include "PartFeaturePy.h" #include "PropertyGeometryList.h" @@ -125,9 +126,15 @@ void PartExport initPart() Base::Interpreter().addType(&Part::PartFeaturePy ::Type,partModule,"Feature"); + PyObject* brepModule = Py_InitModule3("BRepOffsetAPI", 0, "BrepOffsetAPI"); + Py_INCREF(brepModule); + PyModule_AddObject(partModule, "BRepOffsetAPI", brepModule); + Base::Interpreter().addType(&Part::BRepOffsetAPI_MakePipeShellPy::Type,brepModule,"MakePipeShell"); + Part::TopoShape ::init(); Part::PropertyPartShape ::init(); Part::PropertyGeometryList ::init(); + Part::PropertyShapeHistory ::init(); Part::PropertyFilletEdges ::init(); Part::Feature ::init(); @@ -172,6 +179,7 @@ void PartExport initPart() Part::Part2DObjectPython ::init(); Part::RuledSurface ::init(); Part::Loft ::init(); + Part::Sweep ::init(); // Geometry types Part::Geometry ::init(); diff --git a/src/Mod/Part/App/AppPartPy.cpp b/src/Mod/Part/App/AppPartPy.cpp index 2662593c58..2132042df4 100644 --- a/src/Mod/Part/App/AppPartPy.cpp +++ b/src/Mod/Part/App/AppPartPy.cpp @@ -1043,14 +1043,36 @@ static PyObject * makeTube(PyObject *self, PyObject *args) PyObject *pshape; double radius; double tolerance=0.001; + char* scont = "C0"; + int maxdegree = 3; + int maxsegment = 30; // Path + radius - if (!PyArg_ParseTuple(args, "O!d", &(TopoShapePy::Type), &pshape, &radius)) + if (!PyArg_ParseTuple(args, "O!d|sii", &(TopoShapePy::Type), &pshape, &radius, &scont, &maxdegree, &maxsegment)) return 0; + std::string str_cont = scont; + int cont; + if (str_cont == "C0") + cont = (int)GeomAbs_C0; + else if (str_cont == "C1") + cont = (int)GeomAbs_C1; + else if (str_cont == "C2") + cont = (int)GeomAbs_C2; + else if (str_cont == "C3") + cont = (int)GeomAbs_C3; + else if (str_cont == "CN") + cont = (int)GeomAbs_CN; + else if (str_cont == "G1") + cont = (int)GeomAbs_G1; + else if (str_cont == "G2") + cont = (int)GeomAbs_G2; + else + cont = (int)GeomAbs_C0; + try { const TopoDS_Shape& path_shape = static_cast(pshape)->getTopoShapePtr()->_Shape; TopoShape myShape(path_shape); - TopoDS_Shape face = myShape.makeTube(radius, tolerance); + TopoDS_Shape face = myShape.makeTube(radius, tolerance, cont, maxdegree, maxsegment); return new TopoShapeFacePy(new TopoShape(face)); } catch (Standard_Failure) { @@ -1465,7 +1487,8 @@ struct PyMethodDef Part_methods[] = { "these must have the same number of edges."}, {"makeTube" ,makeTube,METH_VARARGS, - "makeTube(edge,float) -- Create a tube."}, + "makeTube(edge,radius,[continuity,max degree,max segments]) -- Create a tube.\n" + "continuity is a string which must be 'C0','C1','C2','C3','CN','G1' or 'G1',"}, {"makeSweepSurface" ,makeSweepSurface,METH_VARARGS, "makeSweepSurface(edge(path),edge(profile),[float]) -- Create a profile along a path."}, diff --git a/src/Mod/Part/App/BRepOffsetAPI_MakePipeShellPy.xml b/src/Mod/Part/App/BRepOffsetAPI_MakePipeShellPy.xml new file mode 100644 index 0000000000..1f375a4371 --- /dev/null +++ b/src/Mod/Part/App/BRepOffsetAPI_MakePipeShellPy.xml @@ -0,0 +1,107 @@ + + + + + + Describes a portion of a circle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0: BRepBuilderAPI_Transformed + 1: BRepBuilderAPI_RightCorner + 2: BRepBuilderAPI_RoundCorner + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Part/App/BRepOffsetAPI_MakePipeShellPyImp.cpp b/src/Mod/Part/App/BRepOffsetAPI_MakePipeShellPyImp.cpp new file mode 100644 index 0000000000..2017e86d23 --- /dev/null +++ b/src/Mod/Part/App/BRepOffsetAPI_MakePipeShellPyImp.cpp @@ -0,0 +1,249 @@ +/*************************************************************************** + * Copyright (c) 2012 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 +# include +# include +# include +#endif + +#include "TopoShapePy.h" +#include "BRepOffsetAPI_MakePipeShellPy.h" +#include "BRepOffsetAPI_MakePipeShellPy.cpp" +#include "Tools.h" +#include +#include + +using namespace Part; + +PyObject *BRepOffsetAPI_MakePipeShellPy::PyMake(struct _typeobject *, PyObject *args, PyObject *) // Python wrapper +{ + // create a new instance of BRepOffsetAPI_MakePipeShellPy and the Twin object + PyObject* obj; + if (!PyArg_ParseTuple(args, "O!",&(TopoShapePy::Type),&obj)) + return 0; + const TopoDS_Shape& wire = static_cast(obj)->getTopoShapePtr()->_Shape; + if (!wire.IsNull() && wire.ShapeType() == TopAbs_WIRE) { + return new BRepOffsetAPI_MakePipeShellPy(new BRepOffsetAPI_MakePipeShell(TopoDS::Wire(wire))); + } + + PyErr_SetString(PyExc_Exception, "A valid wire is needed as argument"); + return 0; +} + +// constructor method +int BRepOffsetAPI_MakePipeShellPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) +{ + return 0; +} + +// returns a string which represents the object e.g. when printed in python +std::string BRepOffsetAPI_MakePipeShellPy::representation(void) const +{ + return std::string(""); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setFrenetMode(PyObject *args) +{ + PyObject *obj; + if (!PyArg_ParseTuple(args, "O!",&PyBool_Type,&obj)) + return 0; + this->getBRepOffsetAPI_MakePipeShellPtr()->SetMode(obj==Py_True); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setTrihedronMode(PyObject *args) +{ + PyObject *pnt, *dir; + if (!PyArg_ParseTuple(args, "O!O!",&Base::VectorPy::Type,&pnt + ,&Base::VectorPy::Type,&dir)) + return 0; + gp_Pnt p = Base::convertTo(Py::Vector(pnt,false).toVector()); + gp_Dir d = Base::convertTo(Py::Vector(dir,false).toVector()); + this->getBRepOffsetAPI_MakePipeShellPtr()->SetMode(gp_Ax2(p,d)); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setBiNormalMode(PyObject *args) +{ + PyObject *dir; + if (!PyArg_ParseTuple(args, "O!",&Base::VectorPy::Type,&dir)) + return 0; + gp_Dir d = Base::convertTo(Py::Vector(dir,false).toVector()); + this->getBRepOffsetAPI_MakePipeShellPtr()->SetMode(d); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setSpineSupport(PyObject *args) +{ + PyObject *shape; + if (!PyArg_ParseTuple(args, "O!",&Part::TopoShapePy::Type,&shape)) + return 0; + const TopoDS_Shape& s = static_cast(shape)->getTopoShapePtr()->_Shape; + Standard_Boolean ok = this->getBRepOffsetAPI_MakePipeShellPtr()->SetMode(s); + return Py::new_reference_to(Py::Boolean(ok ? true : false)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setAuxiliarySpine(PyObject *args) +{ + PyObject *spine, *curv, *keep; + if (!PyArg_ParseTuple(args, "O!O!O!",&Part::TopoShapePy::Type,&spine + ,&PyBool_Type,&curv + ,&PyBool_Type,&keep)) + return 0; + const TopoDS_Shape& s = static_cast(spine)->getTopoShapePtr()->_Shape; + if (s.IsNull() || s.ShapeType() != TopAbs_WIRE) { + PyErr_SetString(PyExc_TypeError, "spine is not a wire"); + return 0; + } + this->getBRepOffsetAPI_MakePipeShellPtr()->SetMode(TopoDS::Wire(s), curv==Py_True, keep==Py_True); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::add(PyObject *args) +{ + PyObject *prof, *curv=0, *keep=0; + if (!PyArg_ParseTuple(args, "O!|O!O!",&Part::TopoShapePy::Type,&prof + ,&PyBool_Type,&curv + ,&PyBool_Type,&keep)) + return 0; + const TopoDS_Shape& s = static_cast(prof)->getTopoShapePtr()->_Shape; + this->getBRepOffsetAPI_MakePipeShellPtr()->Add(s, curv==Py_True, keep==Py_True); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::remove(PyObject *args) +{ + PyObject *prof; + if (!PyArg_ParseTuple(args, "O!",&Part::TopoShapePy::Type,&prof)) + return 0; + const TopoDS_Shape& s = static_cast(prof)->getTopoShapePtr()->_Shape; + this->getBRepOffsetAPI_MakePipeShellPtr()->Delete(s); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::isReady(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + Standard_Boolean ok = this->getBRepOffsetAPI_MakePipeShellPtr()->IsReady(); + return Py::new_reference_to(Py::Boolean(ok ? true : false)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::getStatus(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + Standard_Integer val = this->getBRepOffsetAPI_MakePipeShellPtr()->GetStatus(); + return Py::new_reference_to(Py::Int(val)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::makeSolid(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + Standard_Boolean ok = this->getBRepOffsetAPI_MakePipeShellPtr()->MakeSolid(); + return Py::new_reference_to(Py::Boolean(ok ? true : false)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::build(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + this->getBRepOffsetAPI_MakePipeShellPtr()->Build(); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::shape(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + const TopoDS_Shape& shape = this->getBRepOffsetAPI_MakePipeShellPtr()->Shape(); + return new TopoShapePy(new TopoShape(shape)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::firstShape(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + TopoDS_Shape shape = this->getBRepOffsetAPI_MakePipeShellPtr()->FirstShape(); + return new TopoShapePy(new TopoShape(shape)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::lastShape(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return 0; + TopoDS_Shape shape = this->getBRepOffsetAPI_MakePipeShellPtr()->LastShape(); + return new TopoShapePy(new TopoShape(shape)); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::generated(PyObject *args) +{ + PyObject *shape; + if (!PyArg_ParseTuple(args, "O!",&Part::TopoShapePy::Type,&shape)) + return 0; + const TopoDS_Shape& s = static_cast(shape)->getTopoShapePtr()->_Shape; + const TopTools_ListOfShape& list = this->getBRepOffsetAPI_MakePipeShellPtr()->Generated(s); + + Py::List shapes; + TopTools_ListIteratorOfListOfShape it; + for (it.Initialize(list); it.More(); it.Next()) { + const TopoDS_Shape& s = it.Value(); + shapes.append(Py::asObject(new TopoShapePy(new TopoShape(s)))); + } + return Py::new_reference_to(shapes); +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setTolerance(PyObject *args) +{ + double tol3d, boundTol, tolAngular; + if (!PyArg_ParseTuple(args, "ddd",&tol3d,&boundTol,&tolAngular)) + return 0; + this->getBRepOffsetAPI_MakePipeShellPtr()->SetTolerance(tol3d, boundTol, tolAngular); + Py_Return; +} + +PyObject* BRepOffsetAPI_MakePipeShellPy::setTransitionMode(PyObject *args) +{ + int mode; + if (!PyArg_ParseTuple(args, "i",&mode)) + return 0; + this->getBRepOffsetAPI_MakePipeShellPtr()->SetTransitionMode(BRepBuilderAPI_TransitionMode(mode)); + Py_Return; +} + +PyObject *BRepOffsetAPI_MakePipeShellPy::getCustomAttributes(const char* attr) const +{ + return 0; +} + +int BRepOffsetAPI_MakePipeShellPy::setCustomAttributes(const char* attr, PyObject *obj) +{ + return 0; +} diff --git a/src/Mod/Part/App/BSplineCurvePyImp.cpp b/src/Mod/Part/App/BSplineCurvePyImp.cpp index 91f103fa9e..7f608c9029 100644 --- a/src/Mod/Part/App/BSplineCurvePyImp.cpp +++ b/src/Mod/Part/App/BSplineCurvePyImp.cpp @@ -393,6 +393,8 @@ PyObject* BSplineCurvePy::getPole(PyObject * args) try { Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (index < 1 || index > curve->NbPoles(), "Pole index out of range"); gp_Pnt pnt = curve->Pole(index); Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d( pnt.X(), pnt.Y(), pnt.Z())); @@ -457,6 +459,8 @@ PyObject* BSplineCurvePy::getWeight(PyObject * args) try { Handle_Geom_BSplineCurve curve = Handle_Geom_BSplineCurve::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (index < 1 || index > curve->NbPoles() , "Weight index out of range"); double weight = curve->Weight(index); return Py_BuildValue("d", weight); } diff --git a/src/Mod/Part/App/BSplineSurfacePyImp.cpp b/src/Mod/Part/App/BSplineSurfacePyImp.cpp index b16e78d9d7..c016f277a2 100644 --- a/src/Mod/Part/App/BSplineSurfacePyImp.cpp +++ b/src/Mod/Part/App/BSplineSurfacePyImp.cpp @@ -392,7 +392,7 @@ PyObject* BSplineSurfacePy::insertVKnots(PyObject *args) Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast (getGeometryPtr()->handle()); - surf->InsertUKnots(k,m,tol,(add==Py_True)); + surf->InsertVKnots(k,m,tol,(add==Py_True)); Py_Return; } catch (Standard_Failure) { @@ -751,6 +751,9 @@ PyObject* BSplineSurfacePy::getPole(PyObject *args) try { Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (uindex < 1 || uindex > surf->NbUPoles() || + vindex < 1 || vindex > surf->NbVPoles(), "Pole index out of range"); gp_Pnt pnt = surf->Pole(uindex,vindex); Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d( pnt.X(), pnt.Y(), pnt.Z())); @@ -870,6 +873,9 @@ PyObject* BSplineSurfacePy::getWeight(PyObject *args) try { Handle_Geom_BSplineSurface surf = Handle_Geom_BSplineSurface::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (uindex < 1 || uindex > surf->NbUPoles() || + vindex < 1 || vindex > surf->NbVPoles(), "Weight index out of range"); double w = surf->Weight(uindex,vindex); return Py_BuildValue("d", w); } diff --git a/src/Mod/Part/App/BezierCurvePyImp.cpp b/src/Mod/Part/App/BezierCurvePyImp.cpp index f7653b50dc..8acbb4bcc3 100644 --- a/src/Mod/Part/App/BezierCurvePyImp.cpp +++ b/src/Mod/Part/App/BezierCurvePyImp.cpp @@ -231,6 +231,8 @@ PyObject* BezierCurvePy::getPole(PyObject * args) try { Handle_Geom_BezierCurve curve = Handle_Geom_BezierCurve::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (index < 1 || index > curve->NbPoles(), "Pole index out of range"); gp_Pnt pnt = curve->Pole(index); Base::VectorPy* vec = new Base::VectorPy(Base::Vector3d( pnt.X(), pnt.Y(), pnt.Z())); @@ -321,6 +323,8 @@ PyObject* BezierCurvePy::getWeight(PyObject * args) try { Handle_Geom_BezierCurve curve = Handle_Geom_BezierCurve::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (index < 1 || index > curve->NbPoles() , "Weight index out of range"); double weight = curve->Weight(index); return Py_BuildValue("d", weight); } diff --git a/src/Mod/Part/App/BezierSurfacePyImp.cpp b/src/Mod/Part/App/BezierSurfacePyImp.cpp index 1554b27b0a..6e9dea1bee 100644 --- a/src/Mod/Part/App/BezierSurfacePyImp.cpp +++ b/src/Mod/Part/App/BezierSurfacePyImp.cpp @@ -190,10 +190,17 @@ PyObject* BezierSurfacePy::increase(PyObject *args) int udegree,vdegree; if (!PyArg_ParseTuple(args, "ii", &udegree, &vdegree)) return 0; - Handle_Geom_BezierSurface surf = Handle_Geom_BezierSurface::DownCast - (getGeometryPtr()->handle()); - surf->Increase(udegree, vdegree); - Py_Return; + try { + Handle_Geom_BezierSurface surf = Handle_Geom_BezierSurface::DownCast + (getGeometryPtr()->handle()); + surf->Increase(udegree, vdegree); + Py_Return; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } } PyObject* BezierSurfacePy::insertPoleColAfter(PyObject *args) @@ -528,6 +535,9 @@ PyObject* BezierSurfacePy::getPole(PyObject *args) try { Handle_Geom_BezierSurface surf = Handle_Geom_BezierSurface::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (uindex < 1 || uindex > surf->NbUPoles() || + vindex < 1 || vindex > surf->NbVPoles(), "Pole index out of range"); gp_Pnt p = surf->Pole(uindex,vindex); return new Base::VectorPy(Base::Vector3d(p.X(),p.Y(),p.Z())); } @@ -645,6 +655,9 @@ PyObject* BezierSurfacePy::getWeight(PyObject *args) try { Handle_Geom_BezierSurface surf = Handle_Geom_BezierSurface::DownCast (getGeometryPtr()->handle()); + Standard_OutOfRange_Raise_if + (uindex < 1 || uindex > surf->NbUPoles() || + vindex < 1 || vindex > surf->NbVPoles(), "Weight index out of range"); double w = surf->Weight(uindex,vindex); return Py_BuildValue("d", w); } diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index bd0cb791a6..20a33407b3 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -61,6 +61,7 @@ generate_from_xml(TopoShapeShellPy) generate_from_xml(TopoShapeSolidPy) generate_from_xml(TopoShapeVertexPy) generate_from_xml(TopoShapeWirePy) +generate_from_xml(BRepOffsetAPI_MakePipeShellPy) SET(Features_SRCS FeaturePartBoolean.cpp @@ -203,6 +204,8 @@ SET(Python_SRCS TopoShapeVertexPyImp.cpp TopoShapeWirePy.xml TopoShapeWirePyImp.cpp + BRepOffsetAPI_MakePipeShellPy.xml + BRepOffsetAPI_MakePipeShellPyImp.cpp ) SOURCE_GROUP("Python" FILES ${Python_SRCS}) diff --git a/src/Mod/Part/App/FeaturePartBoolean.cpp b/src/Mod/Part/App/FeaturePartBoolean.cpp index f21296a8b2..2a1781b6cf 100644 --- a/src/Mod/Part/App/FeaturePartBoolean.cpp +++ b/src/Mod/Part/App/FeaturePartBoolean.cpp @@ -23,9 +23,14 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include #endif #include "FeaturePartBoolean.h" +#include "modelRefine.h" +#include +#include using namespace Part; @@ -37,6 +42,9 @@ Boolean::Boolean(void) { ADD_PROPERTY(Base,(0)); ADD_PROPERTY(Tool,(0)); + ADD_PROPERTY_TYPE(History,(ShapeHistory()), "Boolean", (App::PropertyType) + (App::Prop_Output|App::Prop_Transient|App::Prop_Hidden), "Shape history"); + History.setSize(0); } short Boolean::mustExecute() const @@ -66,10 +74,32 @@ App::DocumentObjectExecReturn *Boolean::execute(void) TopoDS_Shape BaseShape = base->Shape.getValue(); TopoDS_Shape ToolShape = tool->Shape.getValue(); - TopoDS_Shape resShape = runOperation(BaseShape, ToolShape); - if (resShape.IsNull()) + std::auto_ptr mkBool(makeOperation(BaseShape, ToolShape)); + if (!mkBool->IsDone()) { + return new App::DocumentObjectExecReturn("Boolean operation failed"); + } + TopoDS_Shape resShape = mkBool->Shape(); + if (resShape.IsNull()) { return new App::DocumentObjectExecReturn("Resulting shape is invalid"); + } + + std::vector history; + history.push_back(buildHistory(*mkBool.get(), TopAbs_FACE, resShape, BaseShape)); + history.push_back(buildHistory(*mkBool.get(), TopAbs_FACE, resShape, ToolShape)); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean"); + if (hGrp->GetBool("RefineModel", false)) { + TopoDS_Shape oldShape = resShape; + BRepBuilderAPI_RefineModel mkRefine(oldShape); + resShape = mkRefine.Shape(); + ShapeHistory hist = buildHistory(mkRefine, TopAbs_FACE, resShape, oldShape); + history[0] = joinHistory(history[0], hist); + history[1] = joinHistory(history[1], hist); + } + this->Shape.setValue(resShape); + this->History.setValues(history); return App::DocumentObject::StdReturn; } catch (...) { diff --git a/src/Mod/Part/App/FeaturePartBoolean.h b/src/Mod/Part/App/FeaturePartBoolean.h index 742af5098e..2730af82f2 100644 --- a/src/Mod/Part/App/FeaturePartBoolean.h +++ b/src/Mod/Part/App/FeaturePartBoolean.h @@ -27,6 +27,8 @@ #include #include "PartFeature.h" +class BRepAlgoAPI_BooleanOperation; + namespace Part { @@ -39,6 +41,7 @@ public: App::PropertyLink Base; App::PropertyLink Tool; + PropertyShapeHistory History; /** @name methods overide Feature */ //@{ @@ -53,7 +56,7 @@ public: } protected: - virtual TopoDS_Shape runOperation(const TopoDS_Shape&, const TopoDS_Shape&) const = 0; + virtual BRepAlgoAPI_BooleanOperation* makeOperation(const TopoDS_Shape&, const TopoDS_Shape&) const = 0; }; } diff --git a/src/Mod/Part/App/FeaturePartBox.h b/src/Mod/Part/App/FeaturePartBox.h index 0349bb2111..086fa40cd4 100644 --- a/src/Mod/Part/App/FeaturePartBox.h +++ b/src/Mod/Part/App/FeaturePartBox.h @@ -32,7 +32,7 @@ namespace Part { -class Box :public Part::Primitive +class PartExport Box :public Part::Primitive { PROPERTY_HEADER(Part::Box); diff --git a/src/Mod/Part/App/FeaturePartCommon.cpp b/src/Mod/Part/App/FeaturePartCommon.cpp index 828512bc35..01ef09e417 100644 --- a/src/Mod/Part/App/FeaturePartCommon.cpp +++ b/src/Mod/Part/App/FeaturePartCommon.cpp @@ -25,11 +25,14 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include #endif #include "FeaturePartCommon.h" - +#include "modelRefine.h" +#include +#include #include using namespace Part; @@ -41,14 +44,10 @@ Common::Common(void) { } -TopoDS_Shape Common::runOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const +BRepAlgoAPI_BooleanOperation* Common::makeOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const { // Let's call algorithm computing a section operation: - BRepAlgoAPI_Common mkCommon(base, tool); - // Let's check if the section has been successful - if (!mkCommon.IsDone()) - throw Base::Exception("Intersection failed"); - return mkCommon.Shape(); + return new BRepAlgoAPI_Common(base, tool); } // ---------------------------------------------------- @@ -60,6 +59,9 @@ MultiCommon::MultiCommon(void) { ADD_PROPERTY(Shapes,(0)); Shapes.setSize(0); + ADD_PROPERTY_TYPE(History,(ShapeHistory()), "Boolean", (App::PropertyType) + (App::Prop_Output|App::Prop_Transient|App::Prop_Hidden), "Shape history"); + History.setSize(0); } short MultiCommon::mustExecute() const @@ -82,18 +84,50 @@ App::DocumentObjectExecReturn *MultiCommon::execute(void) } if (s.size() >= 2) { - TopoDS_Shape res = s.front(); - for (std::vector::iterator it = s.begin()+1; it != s.end(); ++it) { - // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Common mkCommon(res, *it); - // Let's check if the fusion has been successful - if (!mkCommon.IsDone()) - throw Base::Exception("Intersection failed"); - res = mkCommon.Shape(); + try { + std::vector history; + TopoDS_Shape resShape = s.front(); + for (std::vector::iterator it = s.begin()+1; it != s.end(); ++it) { + // Let's call algorithm computing a fuse operation: + BRepAlgoAPI_Common mkCommon(resShape, *it); + // Let's check if the fusion has been successful + if (!mkCommon.IsDone()) + throw Base::Exception("Intersection failed"); + resShape = mkCommon.Shape(); + + ShapeHistory hist1 = buildHistory(mkCommon, TopAbs_FACE, resShape, mkCommon.Shape1()); + ShapeHistory hist2 = buildHistory(mkCommon, TopAbs_FACE, resShape, mkCommon.Shape2()); + if (history.empty()) { + history.push_back(hist1); + history.push_back(hist2); + } + else { + for (std::vector::iterator jt = history.begin(); jt != history.end(); ++jt) + *jt = joinHistory(*jt, hist1); + history.push_back(hist2); + } + } + if (resShape.IsNull()) + throw Base::Exception("Resulting shape is invalid"); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean"); + if (hGrp->GetBool("RefineModel", false)) { + TopoDS_Shape oldShape = resShape; + BRepBuilderAPI_RefineModel mkRefine(oldShape); + resShape = mkRefine.Shape(); + ShapeHistory hist = buildHistory(mkRefine, TopAbs_FACE, resShape, oldShape); + for (std::vector::iterator jt = history.begin(); jt != history.end(); ++jt) + *jt = joinHistory(*jt, hist); + } + + this->Shape.setValue(resShape); + this->History.setValues(history); + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); } - if (res.IsNull()) - throw Base::Exception("Resulting shape is invalid"); - this->Shape.setValue(res); } else { throw Base::Exception("Not enough shape objects linked"); diff --git a/src/Mod/Part/App/FeaturePartCommon.h b/src/Mod/Part/App/FeaturePartCommon.h index 295ec2e4f2..ccb568aed9 100644 --- a/src/Mod/Part/App/FeaturePartCommon.h +++ b/src/Mod/Part/App/FeaturePartCommon.h @@ -41,7 +41,7 @@ public: //@{ /// recalculate the Feature protected: - TopoDS_Shape runOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; + BRepAlgoAPI_BooleanOperation* makeOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; //@} }; @@ -53,6 +53,7 @@ public: MultiCommon(); App::PropertyLinkList Shapes; + PropertyShapeHistory History; /** @name methods override feature */ //@{ diff --git a/src/Mod/Part/App/FeaturePartCut.cpp b/src/Mod/Part/App/FeaturePartCut.cpp index 1d48c1783f..6b6d792c5e 100644 --- a/src/Mod/Part/App/FeaturePartCut.cpp +++ b/src/Mod/Part/App/FeaturePartCut.cpp @@ -40,12 +40,8 @@ Cut::Cut(void) { } -TopoDS_Shape Cut::runOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const +BRepAlgoAPI_BooleanOperation* Cut::makeOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const { // Let's call algorithm computing a cut operation: - BRepAlgoAPI_Cut mkCut(base, tool); - // Let's check if the cut has been successful - if (!mkCut.IsDone()) - throw Base::Exception("Cut failed"); - return mkCut.Shape(); + return new BRepAlgoAPI_Cut(base, tool); } diff --git a/src/Mod/Part/App/FeaturePartCut.h b/src/Mod/Part/App/FeaturePartCut.h index 63b0de61a6..11187781c9 100644 --- a/src/Mod/Part/App/FeaturePartCut.h +++ b/src/Mod/Part/App/FeaturePartCut.h @@ -42,7 +42,7 @@ public: //@{ /// recalculate the Feature protected: - TopoDS_Shape runOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; + BRepAlgoAPI_BooleanOperation* makeOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; //@} }; diff --git a/src/Mod/Part/App/FeaturePartFuse.cpp b/src/Mod/Part/App/FeaturePartFuse.cpp index d0f4a0e972..ba73877ea5 100644 --- a/src/Mod/Part/App/FeaturePartFuse.cpp +++ b/src/Mod/Part/App/FeaturePartFuse.cpp @@ -29,7 +29,9 @@ #include "FeaturePartFuse.h" - +#include "modelRefine.h" +#include +#include #include using namespace Part; @@ -41,14 +43,10 @@ Fuse::Fuse(void) { } -TopoDS_Shape Fuse::runOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const +BRepAlgoAPI_BooleanOperation* Fuse::makeOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(base, tool); - // Let's check if the fusion has been successful - if (!mkFuse.IsDone()) - throw Base::Exception("Fusion failed"); - return mkFuse.Shape(); + return new BRepAlgoAPI_Fuse(base, tool); } // ---------------------------------------------------- @@ -60,6 +58,9 @@ MultiFuse::MultiFuse(void) { ADD_PROPERTY(Shapes,(0)); Shapes.setSize(0); + ADD_PROPERTY_TYPE(History,(ShapeHistory()), "Boolean", (App::PropertyType) + (App::Prop_Output|App::Prop_Transient|App::Prop_Hidden), "Shape history"); + History.setSize(0); } short MultiFuse::mustExecute() const @@ -83,18 +84,44 @@ App::DocumentObjectExecReturn *MultiFuse::execute(void) if (s.size() >= 2) { try { - TopoDS_Shape res = s.front(); + std::vector history; + TopoDS_Shape resShape = s.front(); for (std::vector::iterator it = s.begin()+1; it != s.end(); ++it) { // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(res, *it); + BRepAlgoAPI_Fuse mkFuse(resShape, *it); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) throw Base::Exception("Fusion failed"); - res = mkFuse.Shape(); + resShape = mkFuse.Shape(); + + ShapeHistory hist1 = buildHistory(mkFuse, TopAbs_FACE, resShape, mkFuse.Shape1()); + ShapeHistory hist2 = buildHistory(mkFuse, TopAbs_FACE, resShape, mkFuse.Shape2()); + if (history.empty()) { + history.push_back(hist1); + history.push_back(hist2); + } + else { + for (std::vector::iterator jt = history.begin(); jt != history.end(); ++jt) + *jt = joinHistory(*jt, hist1); + history.push_back(hist2); + } } - if (res.IsNull()) + if (resShape.IsNull()) throw Base::Exception("Resulting shape is invalid"); - this->Shape.setValue(res); + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part/Boolean"); + if (hGrp->GetBool("RefineModel", false)) { + TopoDS_Shape oldShape = resShape; + BRepBuilderAPI_RefineModel mkRefine(oldShape); + resShape = mkRefine.Shape(); + ShapeHistory hist = buildHistory(mkRefine, TopAbs_FACE, resShape, oldShape); + for (std::vector::iterator jt = history.begin(); jt != history.end(); ++jt) + *jt = joinHistory(*jt, hist); + } + + this->Shape.setValue(resShape); + this->History.setValues(history); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); diff --git a/src/Mod/Part/App/FeaturePartFuse.h b/src/Mod/Part/App/FeaturePartFuse.h index 251d7ec580..f1c83bb6f8 100644 --- a/src/Mod/Part/App/FeaturePartFuse.h +++ b/src/Mod/Part/App/FeaturePartFuse.h @@ -42,7 +42,7 @@ public: //@{ /// recalculate the Feature protected: - TopoDS_Shape runOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; + BRepAlgoAPI_BooleanOperation* makeOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; //@} }; @@ -54,6 +54,7 @@ public: MultiFuse(); App::PropertyLinkList Shapes; + PropertyShapeHistory History; /** @name methods override feature */ //@{ diff --git a/src/Mod/Part/App/FeaturePartSection.cpp b/src/Mod/Part/App/FeaturePartSection.cpp index 6beb1eeef3..55cd6da6ea 100644 --- a/src/Mod/Part/App/FeaturePartSection.cpp +++ b/src/Mod/Part/App/FeaturePartSection.cpp @@ -39,12 +39,8 @@ Section::Section(void) { } -TopoDS_Shape Section::runOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const +BRepAlgoAPI_BooleanOperation* Section::makeOperation(const TopoDS_Shape& base, const TopoDS_Shape& tool) const { // Let's call algorithm computing a section operation: - BRepAlgoAPI_Section mkSection(base, tool); - // Let's check if the section has been successful - if (!mkSection.IsDone()) - throw Base::Exception("Section failed"); - return mkSection.Shape(); + return new BRepAlgoAPI_Section(base, tool); } diff --git a/src/Mod/Part/App/FeaturePartSection.h b/src/Mod/Part/App/FeaturePartSection.h index 911c2a5b7d..69ec64c927 100644 --- a/src/Mod/Part/App/FeaturePartSection.h +++ b/src/Mod/Part/App/FeaturePartSection.h @@ -42,7 +42,7 @@ public: //@{ /// recalculate the Feature protected: - TopoDS_Shape runOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; + BRepAlgoAPI_BooleanOperation* makeOperation(const TopoDS_Shape&, const TopoDS_Shape&) const; //@} }; diff --git a/src/Mod/Part/App/Makefile.am b/src/Mod/Part/App/Makefile.am index 91c711564e..7784278143 100644 --- a/src/Mod/Part/App/Makefile.am +++ b/src/Mod/Part/App/Makefile.am @@ -4,6 +4,7 @@ lib_LTLIBRARIES=libPart.la Part.la BUILT_SOURCES=\ ArcPy.cpp \ ArcOfCirclePy.cpp \ + BRepOffsetAPI_MakePipeShellPy.cpp \ CirclePy.cpp \ EllipsePy.cpp \ HyperbolaPy.cpp \ @@ -42,6 +43,7 @@ BUILT_SOURCES=\ libPart_la_BUILT=\ ArcPy.h \ ArcOfCirclePy.h \ + BRepOffsetAPI_MakePipeShellPy.h \ CirclePy.h \ EllipsePy.h \ HyperbolaPy.h \ @@ -81,6 +83,7 @@ libPart_la_SOURCES=\ AppPartPy.cpp \ ArcPyImp.cpp \ ArcOfCirclePyImp.cpp \ + BRepOffsetAPI_MakePipeShellPyImp.cpp \ CirclePyImp.cpp \ CrossSection.cpp \ EllipsePyImp.cpp \ @@ -260,6 +263,7 @@ EXTRA_DIST = \ OpenCascadeAll.h \ ArcPy.xml \ ArcOfCirclePy.xml \ + BRepOffsetAPI_MakePipeShellPy.xml \ CirclePy.xml \ EllipsePy.xml \ HyperbolaPy.xml \ diff --git a/src/Mod/Part/App/Part2DObject.cpp b/src/Mod/Part/App/Part2DObject.cpp index eb44dc0a3c..d9280bc462 100644 --- a/src/Mod/Part/App/Part2DObject.cpp +++ b/src/Mod/Part/App/Part2DObject.cpp @@ -235,7 +235,8 @@ bool Part2DObject::seekTrimPoints(const std::vector &geomlist, gp_Pnt2d p1,p2; Handle_Geom2d_Curve secondaryCurve; for (int id=0; id < int(geomlist.size()); id++) { - if (id != GeoId && !geomlist[id]->Construction) { + // #0000624: Trim tool doesn't work with construction lines + if (id != GeoId/* && !geomlist[id]->Construction*/) { geom = (geomlist[id])->handle(); curve3d = Handle_Geom_Curve::DownCast(geom); if (!curve3d.IsNull()) { diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 508009317f..45e0076e95 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -26,6 +26,14 @@ #ifndef _PreComp_ # include # include +# include +# include +# include +# include +// includes for findAllFacesCutBy() +# include +# include +# include // for Precision::Confusion() #endif @@ -103,9 +111,12 @@ void Feature::onChanged(const App::Property* prop) } else { Base::Placement p; - p.fromMatrix(this->Shape.getShape().getTransform()); - if (p != this->Placement.getValue()) - this->Placement.setValue(p); + // shape must not be null to override the placement + if (!this->Shape.getValue().IsNull()) { + p.fromMatrix(this->Shape.getShape().getTransform()); + if (p != this->Placement.getValue()) + this->Placement.setValue(p); + } } } @@ -125,6 +136,92 @@ TopLoc_Location Feature::getLocation() const return TopLoc_Location(trf); } +ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_ShapeEnum type, + const TopoDS_Shape& newS, const TopoDS_Shape& oldS) +{ + ShapeHistory history; + history.type = type; + + TopTools_IndexedMapOfShape newM, oldM; + TopExp::MapShapes(newS, type, newM); // map containing all old objects of type "type" + TopExp::MapShapes(oldS, type, oldM); // map containing all new objects of type "type" + + // Look at all objects in the old shape and try to find the modified object in the new shape + for (int i=1; i<=oldM.Extent(); i++) { + bool found = false; + TopTools_ListIteratorOfListOfShape it; + // Find all new objects that are a modification of the old object (e.g. a face was resized) + for (it.Initialize(mkShape.Modified(oldM(i))); it.More(); it.Next()) { + found = true; + for (int j=1; j<=newM.Extent(); j++) { // one old object might create several new ones! + if (newM(j).IsPartner(it.Value())) { + history.shapeMap[i-1].push_back(j-1); // adjust indices to start at zero + break; + } + } + } + + // Find all new objects that were generated from an old object (e.g. a face generated from an edge) + for (it.Initialize(mkShape.Generated(oldM(i))); it.More(); it.Next()) { + found = true; + for (int j=1; j<=newM.Extent(); j++) { + if (newM(j).IsPartner(it.Value())) { + history.shapeMap[i-1].push_back(j-1); + break; + } + } + } + + if (!found) { + // Find all old objects that don't exist any more (e.g. a face was completely cut away) + if (mkShape.IsDeleted(oldM(i))) { + history.shapeMap[i-1] = std::vector(); + } + else { + // Mop up the rest (will this ever be reached?) + for (int j=1; j<=newM.Extent(); j++) { + if (newM(j).IsPartner(oldM(i))) { + history.shapeMap[i-1].push_back(j-1); + break; + } + } + } + } + } + + return history; +} + +ShapeHistory Feature::joinHistory(const ShapeHistory& oldH, const ShapeHistory& newH) +{ + ShapeHistory join; + join.type = oldH.type; + + for (ShapeHistory::MapList::const_iterator it = oldH.shapeMap.begin(); it != oldH.shapeMap.end(); ++it) { + int old_shape_index = it->first; + if (it->second.empty()) + join.shapeMap[old_shape_index] = ShapeHistory::List(); + for (ShapeHistory::List::const_iterator jt = it->second.begin(); jt != it->second.end(); ++jt) { + ShapeHistory::MapList::const_iterator kt = newH.shapeMap.find(*jt); + if (kt != newH.shapeMap.end()) { + ShapeHistory::List& ary = join.shapeMap[old_shape_index]; + ary.insert(ary.end(), kt->second.begin(), kt->second.end()); + } + } + } + + 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"; @@ -174,3 +271,51 @@ template<> PyObject* Part::FeaturePython::getPyObject(void) { template class PartExport FeaturePythonT; } +// ---------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include + +std::vector Part::findAllFacesCutBy( + const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir) +{ + // Find the centre of gravity of the face + GProp_GProps props; + BRepGProp::SurfaceProperties(face,props); + gp_Pnt cog = props.CentreOfMass(); + + // create a line through the centre of gravity + gp_Lin line = gce_MakeLin(cog, dir); + + // Find intersection of line with all faces of the shape + std::vector result; + BRepIntCurveSurface_Inter mkSection; + // TODO: Less precision than Confusion() should be OK? + + for (mkSection.Init(shape, line, Precision::Confusion()); mkSection.More(); mkSection.Next()) { + gp_Pnt iPnt = mkSection.Pnt(); + double dsq = cog.SquareDistance(iPnt); + + if (dsq < Precision::Confusion()) + continue; // intersection with original face + + // Find out which side of the original face the intersection is on + gce_MakeDir mkDir(cog, iPnt); + if (!mkDir.IsDone()) + continue; // some error (appears highly unlikely to happen, though...) + + if (mkDir.Value().IsOpposite(dir, Precision::Confusion())) + continue; // wrong side of face (opposite to extrusion direction) + + cutFaces newF; + newF.face = mkSection.Face(); + newF.distsq = dsq; + result.push_back(newF); + } + + return result; +} diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index efa0b7a836..9bb4bd49ae 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -29,6 +29,15 @@ #include #include #include +// includes for findAllFacesCutBy() +#include +class gp_Dir; + +class BRepBuilderAPI_MakeShape; + +// includes for findAllFacesCutBy() +#include +class gp_Dir; namespace Part { @@ -61,11 +70,25 @@ public: virtual PyObject* getPyObject(void); virtual std::vector getPySubObjects(const std::vector&) const; -protected: - void onChanged(const App::Property* prop); + /** + /* 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; + /** + /* Build a history of changes + /* MakeShape: The operation that created the changes, e.g. BRepAlgoAPI_Common + /* type: The type of object we are interested in, e.g. TopAbs_FACE + /* newS: The new shape that was created by the operation + /* oldS: The original shape prior to the operation + */ + ShapeHistory buildHistory(BRepBuilderAPI_MakeShape&, TopAbs_ShapeEnum type, + const TopoDS_Shape& newS, const TopoDS_Shape& oldS); + ShapeHistory joinHistory(const ShapeHistory&, const ShapeHistory&); }; class FilletBase : public Part::Feature @@ -96,6 +119,20 @@ public: } }; +// Utility methods +/** +/* Find all faces cut by a line through the centre of gravity of a given face +/* Useful for the "up to face" options to pocket or pad +*/ +struct cutFaces { + TopoDS_Face face; + double distsq; +}; + +PartExport +std::vector findAllFacesCutBy(const TopoDS_Shape& shape, + const TopoDS_Shape& face, const gp_Dir& dir); + } //namespace Part diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index abbd160830..431e157414 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -27,6 +27,9 @@ # include # include # include +# include +# include +# include #endif @@ -59,28 +62,48 @@ void RuledSurface::onChanged(const App::Property* prop) App::DocumentObjectExecReturn *RuledSurface::execute(void) { - App::DocumentObject* c1 = Curve1.getValue(); - if (!(c1 && c1->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) - return new App::DocumentObjectExecReturn("No shape linked."); - const std::vector& element1 = Curve1.getSubValues(); - if (element1.size() != 1) - return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); - App::DocumentObject* c2 = Curve2.getValue(); - if (!(c2 && c2->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) - return new App::DocumentObjectExecReturn("No shape linked."); - const std::vector& element2 = Curve2.getSubValues(); - if (element2.size() != 1) - return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); - - const Part::TopoShape& shape1 = static_cast(c1)->Shape.getValue(); - TopoDS_Shape curve1 = shape1.getSubShape(element1[0].c_str()); - if (curve1.IsNull()) curve1 = shape1._Shape; - - const Part::TopoShape& shape2 = static_cast(c2)->Shape.getValue(); - TopoDS_Shape curve2 = shape2.getSubShape(element2[0].c_str()); - if (curve2.IsNull()) curve2 = shape2._Shape; - try { + App::DocumentObject* c1 = Curve1.getValue(); + if (!(c1 && c1->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) + return new App::DocumentObjectExecReturn("No shape linked."); + const std::vector& element1 = Curve1.getSubValues(); + if (element1.size() != 1) + return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); + App::DocumentObject* c2 = Curve2.getValue(); + if (!(c2 && c2->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) + return new App::DocumentObjectExecReturn("No shape linked."); + const std::vector& element2 = Curve2.getSubValues(); + if (element2.size() != 1) + return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); + + TopoDS_Shape curve1; + const Part::TopoShape& shape1 = static_cast(c1)->Shape.getValue(); + if (!shape1._Shape.IsNull()) { + if (!element1[0].empty()) { + curve1 = shape1.getSubShape(element1[0].c_str()); + } + else { + if (shape1._Shape.ShapeType() == TopAbs_EDGE) + curve1 = shape1._Shape; + else if (shape1._Shape.ShapeType() == TopAbs_WIRE) + curve1 = shape1._Shape; + } + } + + TopoDS_Shape curve2; + const Part::TopoShape& shape2 = static_cast(c2)->Shape.getValue(); + if (!shape2._Shape.IsNull()) { + if (!element2[0].empty()) { + curve2 = shape2.getSubShape(element2[0].c_str()); + } + else { + if (shape2._Shape.ShapeType() == TopAbs_EDGE) + curve2 = shape2._Shape; + else if (shape2._Shape.ShapeType() == TopAbs_WIRE) + curve2 = shape2._Shape; + } + } + if (curve1.IsNull() || curve2.IsNull()) return new App::DocumentObjectExecReturn("Linked shapes are empty."); if (curve1.ShapeType() == TopAbs_EDGE && curve2.ShapeType() == TopAbs_EDGE) { @@ -100,6 +123,9 @@ App::DocumentObjectExecReturn *RuledSurface::execute(void) Handle_Standard_Failure e = Standard_Failure::Caught(); return new App::DocumentObjectExecReturn(e->GetMessageString()); } + catch (...) { + return new App::DocumentObjectExecReturn("General error in RuledSurface::execute()"); + } } // ---------------------------------------------------------------------------- @@ -145,12 +171,19 @@ App::DocumentObjectExecReturn *Loft::execute(void) const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape is invalid."); - if (shape.ShapeType() == TopAbs_WIRE) + if (shape.ShapeType() == TopAbs_WIRE) { profiles.Append(shape); - else if (shape.ShapeType() == TopAbs_VERTEX) + } + else if (shape.ShapeType() == TopAbs_EDGE) { + BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(shape)); + profiles.Append(mkWire.Wire()); + } + else if (shape.ShapeType() == TopAbs_VERTEX) { profiles.Append(shape); - else - return new App::DocumentObjectExecReturn("Linked shape is neither a vertex nor a wire."); + } + else { + return new App::DocumentObjectExecReturn("Linked shape is not a vertex, edge nor wire."); + } } Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; @@ -165,3 +198,132 @@ App::DocumentObjectExecReturn *Loft::execute(void) return new App::DocumentObjectExecReturn(e->GetMessageString()); } } + +// ---------------------------------------------------------------------------- + +const char* Part::Sweep::TransitionEnums[]= {"Transformed","Right corner", "Round corner",NULL}; + +PROPERTY_SOURCE(Part::Sweep, Part::Feature) + +Sweep::Sweep() +{ + ADD_PROPERTY_TYPE(Sections,(0),"Sweep",App::Prop_None,"List of sections"); + Sections.setSize(0); + ADD_PROPERTY_TYPE(Spine,(0),"Sweep",App::Prop_None,"Path to sweep along"); + ADD_PROPERTY_TYPE(Solid,(false),"Sweep",App::Prop_None,"Create solid"); + ADD_PROPERTY_TYPE(Frenet,(false),"Sweep",App::Prop_None,"Frenet"); + ADD_PROPERTY_TYPE(Transition,(long(1)),"Sweep",App::Prop_None,"Transition mode"); + Transition.setEnums(TransitionEnums); +} + +short Sweep::mustExecute() const +{ + if (Sections.isTouched()) + return 1; + if (Spine.isTouched()) + return 1; + if (Solid.isTouched()) + return 1; + if (Frenet.isTouched()) + return 1; + if (Transition.isTouched()) + return 1; + return 0; +} + +void Sweep::onChanged(const App::Property* prop) +{ + Part::Feature::onChanged(prop); +} + +App::DocumentObjectExecReturn *Sweep::execute(void) +{ + if (Sections.getSize() == 0) + return new App::DocumentObjectExecReturn("No sections linked."); + App::DocumentObject* spine = Spine.getValue(); + if (!(spine && spine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) + return new App::DocumentObjectExecReturn("No spine linked."); + const std::vector& subedge = Spine.getSubValues(); + if (subedge.size() != 1) + return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); + + TopoDS_Shape path; + const Part::TopoShape& shape = static_cast(spine)->Shape.getValue(); + if (!shape._Shape.IsNull()) { + if (!subedge[0].empty()) { + path = shape.getSubShape(subedge[0].c_str()); + } + else { + if (shape._Shape.ShapeType() == TopAbs_EDGE) + path = shape._Shape; + else if (shape._Shape.ShapeType() == TopAbs_WIRE) + path = shape._Shape; + else + return new App::DocumentObjectExecReturn("Spine is neither an edge nor a wire."); + } + } + + try { + TopTools_ListOfShape profiles; + const std::vector& shapes = Sections.getValues(); + std::vector::const_iterator it; + for (it = shapes.begin(); it != shapes.end(); ++it) { + if (!(*it)->isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Linked object is not a shape."); + const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Linked shape is invalid."); + if (shape.ShapeType() == TopAbs_WIRE) { + profiles.Append(shape); + } + else if (shape.ShapeType() == TopAbs_EDGE) { + BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(shape)); + profiles.Append(mkWire.Wire()); + } + else if (shape.ShapeType() == TopAbs_VERTEX) { + profiles.Append(shape); + } + else { + return new App::DocumentObjectExecReturn("Linked shape is not a vertex, edge nor wire."); + } + } + + Standard_Boolean isSolid = Solid.getValue() ? Standard_True : Standard_False; + Standard_Boolean isFrenet = Frenet.getValue() ? Standard_True : Standard_False; + BRepBuilderAPI_TransitionMode transMode; + switch (Transition.getValue()) { + case 1: transMode = BRepBuilderAPI_RightCorner; + break; + case 2: transMode = BRepBuilderAPI_RoundCorner; + break; + default: transMode = BRepBuilderAPI_Transformed; + break; + } + + if (path.ShapeType() == TopAbs_EDGE) { + BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(path)); + path = mkWire.Wire(); + } + + BRepOffsetAPI_MakePipeShell mkPipeShell(TopoDS::Wire(path)); + mkPipeShell.SetMode(isFrenet); + mkPipeShell.SetTransitionMode(transMode); + TopTools_ListIteratorOfListOfShape iter; + for (iter.Initialize(profiles); iter.More(); iter.Next()) { + mkPipeShell.Add(TopoDS_Shape(iter.Value())); + } + + if (!mkPipeShell.IsReady()) + Standard_Failure::Raise("shape is not ready to build"); + mkPipeShell.Build(); + if (isSolid) + mkPipeShell.MakeSolid(); + + this->Shape.setValue(mkPipeShell.Shape()); + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } +} diff --git a/src/Mod/Part/App/PartFeatures.h b/src/Mod/Part/App/PartFeatures.h index f01fde5752..ddaae9627d 100644 --- a/src/Mod/Part/App/PartFeatures.h +++ b/src/Mod/Part/App/PartFeatures.h @@ -73,6 +73,33 @@ protected: void onChanged (const App::Property* prop); }; +class Sweep : public Part::Feature +{ + PROPERTY_HEADER(Part::Sweep); + +public: + Sweep(); + + App::PropertyLinkList Sections; + App::PropertyLinkSub Spine; + App::PropertyBool Solid; + App::PropertyBool Frenet; + App::PropertyEnumeration Transition; + + /** @name methods override feature */ + //@{ + /// recalculate the feature + App::DocumentObjectExecReturn *execute(void); + short mustExecute() const; + //@} + +protected: + void onChanged (const App::Property* prop); + +private: + static const char* TransitionEnums[]; +}; + } //namespace Part diff --git a/src/Mod/Part/App/PrimitiveFeature.cpp b/src/Mod/Part/App/PrimitiveFeature.cpp index 2aef7aa077..5673ddd424 100644 --- a/src/Mod/Part/App/PrimitiveFeature.cpp +++ b/src/Mod/Part/App/PrimitiveFeature.cpp @@ -100,7 +100,7 @@ void Primitive::onChanged(const App::Property* prop) // Do not support sphere, ellipsoid and torus because the creation // takes too long and thus is not feasible std::string grp = (prop->getGroup() ? prop->getGroup() : ""); - if (grp == "Plane" || grp == "Cylinder" || grp == "Cone"){ + if (grp == "Plane" || grp == "Cylinder" || grp == "Cone") { try { App::DocumentObjectExecReturn *ret = recompute(); delete ret; @@ -585,6 +585,8 @@ App::DocumentObjectExecReturn *Torus::execute(void) PROPERTY_SOURCE(Part::Helix, Part::Primitive) +const char* Part::Helix::LocalCSEnums[]= {"Right-handed","Left-handed",NULL}; + Helix::Helix(void) { ADD_PROPERTY_TYPE(Pitch, (1.0),"Helix",App::Prop_None,"The pitch of the helix"); @@ -595,6 +597,24 @@ Helix::Helix(void) Radius.setConstraints(&floatRange); ADD_PROPERTY_TYPE(Angle,(0.0),"Helix",App::Prop_None,"If angle is > 0 a conical otherwise a cylindircal surface is used"); Angle.setConstraints(&apexRange); + ADD_PROPERTY_TYPE(LocalCoord,(long(0)),"Coordinate System",App::Prop_None,"Orientation of the local coordinate system of the helix"); + LocalCoord.setEnums(LocalCSEnums); +} + +void Helix::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + if (prop == &Pitch || prop == &Height || prop == &Radius || + prop == &Angle || prop == &LocalCoord) { + try { + App::DocumentObjectExecReturn *ret = recompute(); + delete ret; + } + catch (...) { + } + } + } + Part::Feature::onChanged(prop); } short Helix::mustExecute() const @@ -607,6 +627,8 @@ short Helix::mustExecute() const return 1; if (Angle.isTouched()) return 1; + if (LocalCoord.isTouched()) + return 1; return Primitive::mustExecute(); } @@ -617,8 +639,9 @@ App::DocumentObjectExecReturn *Helix::execute(void) Standard_Real myHeight = Height.getValue(); Standard_Real myRadius = Radius.getValue(); Standard_Real myAngle = Angle.getValue(); + Standard_Boolean myLocalCS = LocalCoord.getValue() ? Standard_True : Standard_False; TopoShape helix; - this->Shape.setValue(helix.makeHelix(myPitch, myHeight, myRadius, myAngle)); + this->Shape.setValue(helix.makeHelix(myPitch, myHeight, myRadius, myAngle, myLocalCS)); } catch (Standard_Failure) { Handle_Standard_Failure e = Standard_Failure::Caught(); diff --git a/src/Mod/Part/App/PrimitiveFeature.h b/src/Mod/Part/App/PrimitiveFeature.h index fe1eb06091..0c0b7b81d6 100644 --- a/src/Mod/Part/App/PrimitiveFeature.h +++ b/src/Mod/Part/App/PrimitiveFeature.h @@ -227,6 +227,7 @@ public: App::PropertyFloatConstraint Height; App::PropertyFloatConstraint Radius; App::PropertyFloatConstraint Angle; + App::PropertyEnumeration LocalCoord; /** @name methods override feature */ //@{ @@ -234,6 +235,12 @@ public: App::DocumentObjectExecReturn *execute(void); short mustExecute() const; //@} + +protected: + void onChanged (const App::Property* prop); + +private: + static const char* LocalCSEnums[]; }; class PartExport Wedge : public Primitive diff --git a/src/Mod/Part/App/PropertyTopoShape.cpp b/src/Mod/Part/App/PropertyTopoShape.cpp index d0cc3981c2..f3e83a809a 100644 --- a/src/Mod/Part/App/PropertyTopoShape.cpp +++ b/src/Mod/Part/App/PropertyTopoShape.cpp @@ -343,6 +343,72 @@ void PropertyPartShape::RestoreDocFile(Base::Reader &reader) // ------------------------------------------------------------------------- +TYPESYSTEM_SOURCE(Part::PropertyShapeHistory , App::PropertyLists); + +PropertyShapeHistory::PropertyShapeHistory() +{ +} + +PropertyShapeHistory::~PropertyShapeHistory() +{ +} + +void PropertyShapeHistory::setValue(const ShapeHistory& sh) +{ + aboutToSetValue(); + _lValueList.resize(1); + _lValueList[0] = sh; + hasSetValue(); +} + +void PropertyShapeHistory::setValues(const std::vector& values) +{ + aboutToSetValue(); + _lValueList = values; + hasSetValue(); +} + +PyObject *PropertyShapeHistory::getPyObject(void) +{ + return Py::new_reference_to(Py::None()); +} + +void PropertyShapeHistory::setPyObject(PyObject *value) +{ +} + +void PropertyShapeHistory::Save (Base::Writer &writer) const +{ +} + +void PropertyShapeHistory::Restore(Base::XMLReader &reader) +{ +} + +void PropertyShapeHistory::SaveDocFile (Base::Writer &writer) const +{ +} + +void PropertyShapeHistory::RestoreDocFile(Base::Reader &reader) +{ +} + +App::Property *PropertyShapeHistory::Copy(void) const +{ + PropertyShapeHistory *p= new PropertyShapeHistory(); + p->_lValueList = _lValueList; + return p; +} + +void PropertyShapeHistory::Paste(const Property &from) +{ + aboutToSetValue(); + _lValueList = dynamic_cast(from)._lValueList; + hasSetValue(); +} + +// ------------------------------------------------------------------------- + TYPESYSTEM_SOURCE(Part::PropertyFilletEdges , App::PropertyLists); PropertyFilletEdges::PropertyFilletEdges() diff --git a/src/Mod/Part/App/PropertyTopoShape.h b/src/Mod/Part/App/PropertyTopoShape.h index 3113ed4561..a75c85ccd0 100644 --- a/src/Mod/Part/App/PropertyTopoShape.h +++ b/src/Mod/Part/App/PropertyTopoShape.h @@ -21,12 +21,15 @@ ***************************************************************************/ -#ifndef PROPERTYTOPOSHAPE_H -#define PROPERTYTOPOSHAPE_H +#ifndef PART_PROPERTYTOPOSHAPE_H +#define PART_PROPERTYTOPOSHAPE_H #include "TopoShape.h" +#include #include #include +#include +#include namespace Part { @@ -95,6 +98,59 @@ private: TopoShape _Shape; }; +struct PartExport ShapeHistory { + typedef std::map > MapList; + typedef std::vector List; + + TopAbs_ShapeEnum type; + MapList shapeMap; +}; + +class PartExport PropertyShapeHistory : public App::PropertyLists +{ + TYPESYSTEM_HEADER(); + +public: + PropertyShapeHistory(); + ~PropertyShapeHistory(); + + virtual void setSize(int newSize) { + _lValueList.resize(newSize); + } + virtual int getSize(void) const { + return _lValueList.size(); + } + + /** Sets the property + */ + void setValue(const ShapeHistory&); + + void setValues (const std::vector& values); + + const std::vector &getValues(void) const { + return _lValueList; + } + + virtual PyObject *getPyObject(void); + virtual void setPyObject(PyObject *); + + virtual void Save (Base::Writer &writer) const; + virtual void Restore(Base::XMLReader &reader); + + virtual void SaveDocFile (Base::Writer &writer) const; + virtual void RestoreDocFile(Base::Reader &reader); + + virtual Property *Copy(void) const; + virtual void Paste(const Property &from); + + virtual unsigned int getMemSize (void) const { + return _lValueList.size() * sizeof(ShapeHistory); + } + +private: + std::vector _lValueList; +}; + /** A property class to store hash codes and two radii for the fillet algorithm. * @author Werner Mayer */ @@ -151,4 +207,4 @@ private: } //namespace Part -#endif // PROPERTYTOPOSHAPE_H +#endif // PART_PROPERTYTOPOSHAPE_H diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 490ba3c78c..9bf4870744 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -32,7 +32,9 @@ # include # include # include +# include # include +# include # include # include # include @@ -431,25 +433,19 @@ void TopoShape::operator = (const TopoShape& sh) } } -void TopoShape::setTransform(const Base::Matrix4D& rclTrf) +void TopoShape::convertTogpTrsf(const Base::Matrix4D& mtrx, gp_Trsf& trsf) { - gp_Trsf mov; - mov.SetValues(rclTrf[0][0],rclTrf[0][1],rclTrf[0][2],rclTrf[0][3], - rclTrf[1][0],rclTrf[1][1],rclTrf[1][2],rclTrf[1][3], - rclTrf[2][0],rclTrf[2][1],rclTrf[2][2],rclTrf[2][3], - 0.00001,0.00001); - TopLoc_Location loc(mov); - _Shape.Location(loc); + trsf.SetValues(mtrx[0][0],mtrx[0][1],mtrx[0][2],mtrx[0][3], + mtrx[1][0],mtrx[1][1],mtrx[1][2],mtrx[1][3], + mtrx[2][0],mtrx[2][1],mtrx[2][2],mtrx[2][3], + 0.00001,0.00001); } -Base::Matrix4D TopoShape::getTransform(void) const +void TopoShape::convertToMatrix(const gp_Trsf& trsf, Base::Matrix4D& mtrx) { - Base::Matrix4D mtrx; - gp_Trsf Trf = _Shape.Location().Transformation(); - - gp_Mat m = Trf._CSFDB_Getgp_Trsfmatrix(); - gp_XYZ p = Trf._CSFDB_Getgp_Trsfloc(); - Standard_Real scale = Trf._CSFDB_Getgp_Trsfscale(); + gp_Mat m = trsf._CSFDB_Getgp_Trsfmatrix(); + gp_XYZ p = trsf._CSFDB_Getgp_Trsfloc(); + Standard_Real scale = trsf._CSFDB_Getgp_Trsfscale(); // set Rotation matrix mtrx[0][0] = scale * m._CSFDB_Getgp_Matmatrix(0,0); @@ -468,7 +464,21 @@ Base::Matrix4D TopoShape::getTransform(void) const mtrx[0][3] = p._CSFDB_Getgp_XYZx(); mtrx[1][3] = p._CSFDB_Getgp_XYZy(); mtrx[2][3] = p._CSFDB_Getgp_XYZz(); +} +void TopoShape::setTransform(const Base::Matrix4D& rclTrf) +{ + gp_Trsf mov; + convertTogpTrsf(rclTrf, mov); + TopLoc_Location loc(mov); + _Shape.Location(loc); +} + +Base::Matrix4D TopoShape::getTransform(void) const +{ + Base::Matrix4D mtrx; + gp_Trsf Trf = _Shape.Location().Transformation(); + convertToMatrix(Trf, mtrx); return mtrx; } @@ -1343,7 +1353,8 @@ TopoDS_Shape TopoShape::makePipeShell(const TopTools_ListOfShape& profiles, return mkPipeShell.Shape(); } -TopoDS_Shape TopoShape::makeTube(double radius, double tol) const +#if 0 +TopoDS_Shape TopoShape::makeTube() const { // http://opencascade.blogspot.com/2009/11/surface-modeling-part3.html if (this->_Shape.IsNull()) @@ -1378,43 +1389,53 @@ TopoDS_Shape TopoShape::makeTube(double radius, double tol) const ); return mkBuilder.Face(); } - -// for testing -static Handle(Law_Function) CreateBsFunction (const Standard_Real theFirst, const Standard_Real theLast) +#else +static Handle(Law_Function) CreateBsFunction (const Standard_Real theFirst, const Standard_Real theLast, const Standard_Real theRadius) { //Handle_Law_BSpline aBs; //Handle_Law_BSpFunc aFunc = new Law_BSpFunc (aBs, theFirst, theLast); Handle_Law_Linear aFunc = new Law_Linear(); - aFunc->Set(theFirst, 2.0, theLast, 3.0); + aFunc->Set(theFirst, theRadius, theLast, theRadius); return aFunc; } -// for testing -TopoDS_Shape TopoShape::makeTube() const +TopoDS_Shape TopoShape::makeTube(double radius, double tol, int cont, int maxdegree, int maxsegm) const { // http://opencascade.blogspot.com/2009/11/surface-modeling-part3.html - Standard_Real theTol = 0.001; + Standard_Real theTol = tol; Standard_Boolean theIsPolynomial = Standard_True; Standard_Boolean myIsElem = Standard_True; - GeomAbs_Shape theContinuity = GeomAbs_G1; - Standard_Integer theMaxDegree = 3; - Standard_Integer theMaxSegment = 1000; + GeomAbs_Shape theContinuity = GeomAbs_Shape(cont); + Standard_Integer theMaxDegree = maxdegree; + Standard_Integer theMaxSegment = maxsegm; if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); - if (this->_Shape.ShapeType() != TopAbs_EDGE) - Standard_Failure::Raise("Spine shape is not an edge"); - const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); - BRepAdaptor_Curve path_adapt(path_edge); + Handle(Adaptor3d_HCurve) myPath; + if (this->_Shape.ShapeType() == TopAbs_EDGE) { + const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); + BRepAdaptor_Curve path_adapt(path_edge); + myPath = new BRepAdaptor_HCurve(path_adapt); + } + //else if (this->_Shape.ShapeType() == TopAbs_WIRE) { + // const TopoDS_Wire& path_wire = TopoDS::Wire(this->_Shape); + // BRepAdaptor_CompCurve path_adapt(path_wire); + // myPath = new BRepAdaptor_HCompCurve(path_adapt); + //} + //else { + // Standard_Failure::Raise("Spine shape is neither an edge nor a wire"); + //} + else { + Standard_Failure::Raise("Spine shape is not an edge"); + } //circular profile - Handle(Geom_Circle) aCirc = new Geom_Circle (gp::XOY(), 1.0); + Handle(Geom_Circle) aCirc = new Geom_Circle (gp::XOY(), radius); aCirc->Rotate (gp::OZ(), Standard_PI/2.); //perpendicular section - Handle(BRepAdaptor_HCurve) myPath = new BRepAdaptor_HCurve(path_adapt); - Handle(Law_Function) myEvol = ::CreateBsFunction (myPath->FirstParameter(), myPath->LastParameter()); + Handle(Law_Function) myEvol = ::CreateBsFunction (myPath->FirstParameter(), myPath->LastParameter(), radius); Handle(GeomFill_SectionLaw) aSec = new GeomFill_EvolvedSection(aCirc, myEvol); Handle(GeomFill_LocationLaw) aLoc = new GeomFill_CurveAndTrihedron(new GeomFill_CorrectedFrenet); aLoc->SetCurve (myPath); @@ -1438,6 +1459,7 @@ TopoDS_Shape TopoShape::makeTube() const return TopoDS_Shape(); } +#endif TopoDS_Shape TopoShape::makeSweep(const TopoDS_Shape& profile, double tol, int fillMode) const { @@ -1493,42 +1515,49 @@ TopoDS_Shape TopoShape::makeSweep(const TopoDS_Shape& profile, double tol, int f } TopoDS_Shape TopoShape::makeHelix(Standard_Real pitch, Standard_Real height, - Standard_Real radius, Standard_Real angle) const + Standard_Real radius, Standard_Real angle, + Standard_Boolean leftHanded) const { - if (pitch < Precision::Confusion()) - Standard_Failure::Raise("Pitch of helix too small"); + if (pitch < Precision::Confusion()) + Standard_Failure::Raise("Pitch of helix too small"); - if (height < Precision::Confusion()) - Standard_Failure::Raise("Height of helix too small"); + if (height < Precision::Confusion()) + Standard_Failure::Raise("Height of helix too small"); - if (radius < Precision::Confusion()) - Standard_Failure::Raise("Radius of helix too small"); + if (radius < Precision::Confusion()) + Standard_Failure::Raise("Radius of helix too small"); - gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); - Handle_Geom_Surface surf; - if (angle < Precision::Confusion()) { - surf = new Geom_CylindricalSurface(cylAx2, radius); - } - else { - angle = Base::toRadians(angle); - if (angle < Precision::Confusion()) - Standard_Failure::Raise("Angle of helix too small"); - surf = new Geom_ConicalSurface(gp_Ax3(cylAx2), angle, radius); - } + gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); + Handle_Geom_Surface surf; + if (angle < Precision::Confusion()) { + surf = new Geom_CylindricalSurface(cylAx2, radius); + } + else { + angle = Base::toRadians(angle); + if (angle < Precision::Confusion()) + Standard_Failure::Raise("Angle of helix too small"); + surf = new Geom_ConicalSurface(gp_Ax3(cylAx2), angle, radius); + } - gp_Pnt2d aPnt(0, 0); - gp_Dir2d aDir(2. * PI, pitch); - gp_Ax2d aAx2d(aPnt, aDir); + gp_Pnt2d aPnt(0, 0); + gp_Dir2d aDir(2. * PI, pitch); + if (leftHanded) { + //aPnt.SetCoord(0.0, height); + //aDir.SetCoord(2.0 * PI, -pitch); + aPnt.SetCoord(2. * PI, 0.0); + aDir.SetCoord(-2. * PI, pitch); + } + gp_Ax2d aAx2d(aPnt, aDir); - Handle(Geom2d_Line) line = new Geom2d_Line(aAx2d); - gp_Pnt2d beg = line->Value(0); - gp_Pnt2d end = line->Value(sqrt(4.0*PI*PI+pitch*pitch)*(height/pitch)); - Handle(Geom2d_TrimmedCurve) segm = GCE2d_MakeSegment(beg , end); + Handle(Geom2d_Line) line = new Geom2d_Line(aAx2d); + gp_Pnt2d beg = line->Value(0); + gp_Pnt2d end = line->Value(sqrt(4.0*PI*PI+pitch*pitch)*(height/pitch)); + Handle(Geom2d_TrimmedCurve) segm = GCE2d_MakeSegment(beg , end); - TopoDS_Edge edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); - TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edgeOnSurf); - BRepLib::BuildCurves3d(wire); - return wire; + TopoDS_Edge edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); + TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edgeOnSurf); + BRepLib::BuildCurves3d(wire); + return wire; } TopoDS_Shape TopoShape::makeLoft(const TopTools_ListOfShape& profiles, @@ -1546,6 +1575,11 @@ TopoDS_Shape TopoShape::makeLoft(const TopTools_ListOfShape& profiles, aGenerator.AddVertex(TopoDS::Vertex (item)); countShapes++; } + else if (!item.IsNull() && item.ShapeType() == TopAbs_EDGE) { + BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(item)); + aGenerator.AddWire(mkWire.Wire()); + countShapes++; + } else if (!item.IsNull() && item.ShapeType() == TopAbs_WIRE) { aGenerator.AddWire(TopoDS::Wire (item)); countShapes++; @@ -1553,7 +1587,7 @@ TopoDS_Shape TopoShape::makeLoft(const TopTools_ListOfShape& profiles, } if (countShapes < 2) - Standard_Failure::Raise("Need at least two vertexes or wires to create loft face"); + Standard_Failure::Raise("Need at least two vertices, edges or wires to create loft face"); Standard_Boolean anIsCheck = Standard_True; aGenerator.CheckCompatibility (anIsCheck); diff --git a/src/Mod/Part/App/TopoShape.h b/src/Mod/Part/App/TopoShape.h index 9f3b17562b..1d16b9e073 100644 --- a/src/Mod/Part/App/TopoShape.h +++ b/src/Mod/Part/App/TopoShape.h @@ -73,6 +73,8 @@ public: Base::Matrix4D getTransform(void) const; /// Bound box from the CasCade shape Base::BoundBox3d getBoundBox(void)const; + static void convertTogpTrsf(const Base::Matrix4D& mtrx, gp_Trsf& trsf); + static void convertToMatrix(const gp_Trsf& trsf, Base::Matrix4D& mtrx); //@} /** @name Subelement management */ @@ -158,10 +160,9 @@ public: TopoDS_Shape makeThickSolid(const TopTools_ListOfShape& remFace, Standard_Real offset, Standard_Real tolerance) const; TopoDS_Shape makeSweep(const TopoDS_Shape& profile, double, int) const; - TopoDS_Shape makeTube(double radius, double tol) const; - TopoDS_Shape makeTube() const; + TopoDS_Shape makeTube(double radius, double tol, int cont, int maxdeg, int maxsegm) const; TopoDS_Shape makeHelix(Standard_Real pitch, Standard_Real height, - Standard_Real radius, Standard_Real angle=0) const; + Standard_Real radius, Standard_Real angle=0, Standard_Boolean left=Standard_False) const; TopoDS_Shape makeLoft(const TopTools_ListOfShape& profiles, Standard_Boolean isSolid, Standard_Boolean isRuled) const; TopoDS_Shape makeOffset(double offset, double tol, diff --git a/src/Mod/Part/App/TopoShapeEdgePy.xml b/src/Mod/Part/App/TopoShapeEdgePy.xml index 873b3fb726..40def10305 100644 --- a/src/Mod/Part/App/TopoShapeEdgePy.xml +++ b/src/Mod/Part/App/TopoShapeEdgePy.xml @@ -24,7 +24,12 @@ Vector = valueAt(pos) - Get the point at the given parameter [0|Length] if defined - + + + Float = parameterAt(Vertex) - Get the parameter at the given vertex if lying on the edge + + + Vector = normalAt(pos) - Get the normal vector at the given parameter [0|Length] if defined @@ -64,6 +69,11 @@ Discretizes the edge using a given deflection or number of points and returns a list of points + + + Splits the edge at the given parameter values and builds a wire out of it + + Set or get the tolerance of the vertex diff --git a/src/Mod/Part/App/TopoShapeEdgePyImp.cpp b/src/Mod/Part/App/TopoShapeEdgePyImp.cpp index ec5bc09054..329c6bd6c6 100644 --- a/src/Mod/Part/App/TopoShapeEdgePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeEdgePyImp.cpp @@ -23,10 +23,13 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include # include # include # include # include +# include +# include # include # include # include @@ -47,6 +50,7 @@ # include # include # include +# include # include #endif @@ -55,12 +59,14 @@ #include #include +#include #include #include #include "TopoShape.h" #include "TopoShapeFacePy.h" #include "TopoShapeVertexPy.h" +#include "TopoShapeWirePy.h" #include "TopoShapeEdgePy.h" #include "TopoShapeEdgePy.cpp" @@ -185,6 +191,35 @@ PyObject* TopoShapeEdgePy::valueAt(PyObject *args) return new Base::VectorPy(new Base::Vector3d(V.X(),V.Y(),V.Z())); } +PyObject* TopoShapeEdgePy::parameterAt(PyObject *args) +{ + PyObject* pnt; + PyObject* face=0; + if (!PyArg_ParseTuple(args, "O!|O!",&TopoShapeVertexPy::Type,&pnt, + &TopoShapeFacePy::Type,&face)) + return 0; + + try { + const TopoDS_Shape& v = static_cast(pnt)->getTopoShapePtr()->_Shape; + const TopoDS_Edge& e = TopoDS::Edge(getTopoShapePtr()->_Shape); + + if (face) { + const TopoDS_Shape& f = static_cast(face)->getTopoShapePtr()->_Shape; + Standard_Real par = BRep_Tool::Parameter(TopoDS::Vertex(v), e, TopoDS::Face(f)); + return PyFloat_FromDouble(par); + } + else { + Standard_Real par = BRep_Tool::Parameter(TopoDS::Vertex(v), e); + return PyFloat_FromDouble(par); + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; + } +} + PyObject* TopoShapeEdgePy::tangentAt(PyObject *args) { double u; @@ -443,6 +478,74 @@ PyObject* TopoShapeEdgePy::discretize(PyObject *args) return 0; } +PyObject* TopoShapeEdgePy::split(PyObject *args) +{ + PyObject* float_or_list; + if (!PyArg_ParseTuple(args, "O", &float_or_list)) + return 0; + + try { + BRepAdaptor_Curve adapt(TopoDS::Edge(getTopoShapePtr()->_Shape)); + Standard_Real f = adapt.FirstParameter(); + Standard_Real l = adapt.LastParameter(); + + std::vector par; + par.push_back(f); + if (PyFloat_Check(float_or_list)) { + double val = PyFloat_AsDouble(float_or_list); + if (val == f || val == l) { + PyErr_SetString(PyExc_ValueError, "Cannot split edge at start or end point"); + return 0; + } + else if (val < f || val > l) { + PyErr_SetString(PyExc_ValueError, "Value out of parameter range"); + return 0; + } + par.push_back(val); + } + else if (PyList_Check(float_or_list)) { + Py::List list(float_or_list); + for (Py::List::iterator it = list.begin(); it != list.end(); ++it) { + double val = (double)Py::Float(*it); + if (val == f || val == l) { + PyErr_SetString(PyExc_ValueError, "Cannot split edge at start or end point"); + return 0; + } + else if (val < f || val > l) { + PyErr_SetString(PyExc_ValueError, "Value out of parameter range"); + return 0; + } + par.push_back(val); + } + } + else { + PyErr_SetString(PyExc_TypeError, "Either float or list of floats expected"); + return 0; + } + + par.push_back(l); + std::sort(par.begin(), par.end()); + + BRepBuilderAPI_MakeWire mkWire; + Handle_Geom_Curve c = adapt.Curve().Curve(); + std::vector::iterator end = par.end() - 1; + for (std::vector::iterator it = par.begin(); it != end; ++it) { + BRepBuilderAPI_MakeEdge mkBuilder(c, it[0], it[1]); + mkWire.Add(mkBuilder.Edge()); + } + + return new TopoShapeWirePy(new TopoShape(mkWire.Shape())); + } + 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* TopoShapeEdgePy::setTolerance(PyObject *args) { double tol; diff --git a/src/Mod/Part/App/TopoShapeFacePyImp.cpp b/src/Mod/Part/App/TopoShapeFacePyImp.cpp index 9c65d51f28..ab03bb14c8 100644 --- a/src/Mod/Part/App/TopoShapeFacePyImp.cpp +++ b/src/Mod/Part/App/TopoShapeFacePyImp.cpp @@ -550,14 +550,16 @@ Py::Tuple TopoShapeFacePy::getParameterRange(void) const Py::Object TopoShapeFacePy::getWire(void) const { - TopoDS_Shape clSh = getTopoShapePtr()->_Shape; + const TopoDS_Shape& clSh = getTopoShapePtr()->_Shape; + if (clSh.IsNull()) + throw Py::Exception("Null shape"); if (clSh.ShapeType() == TopAbs_FACE) { TopoDS_Face clFace = (TopoDS_Face&)clSh; TopoDS_Wire clWire = ShapeAnalysis::OuterWire(clFace); return Py::Object(new TopoShapeWirePy(new TopoShape(clWire)),true); } else - throw "Internal error, TopoDS_Shape is not a face!"; + throw Py::Exception("Internal error, TopoDS_Shape is not a face!"); return Py::Object(); } diff --git a/src/Mod/Part/App/TopoShapePy.xml b/src/Mod/Part/App/TopoShapePy.xml index eb612ab736..34522f5f95 100644 --- a/src/Mod/Part/App/TopoShapePy.xml +++ b/src/Mod/Part/App/TopoShapePy.xml @@ -179,7 +179,8 @@ the underlying geometry. - A hollowed solid is built from an initial solid and a set of faces on this solid, + makeThickness(List of shapes, Ofset (Float), Tolerance (Float)) -> Shape +A hollowed solid is built from an initial solid and a set of faces on this solid, which are to be removed. The remaining faces of the solid become the walls of the hollowed solid, their thickness defined at the time of construction. diff --git a/src/Mod/Part/App/TopoShapePyImp.cpp b/src/Mod/Part/App/TopoShapePyImp.cpp index 3aef9eab90..8f641a2f7e 100644 --- a/src/Mod/Part/App/TopoShapePyImp.cpp +++ b/src/Mod/Part/App/TopoShapePyImp.cpp @@ -347,7 +347,12 @@ PyObject* TopoShapePy::exportStl(PyObject *args) } catch (const Base::Exception& e) { PyErr_SetString(PyExc_Exception,e.what()); - return NULL; + return 0; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + PyErr_SetString(PyExc_Exception, e->GetMessageString()); + return 0; } Py_Return; diff --git a/src/Mod/Part/App/TopoShapeShellPyImp.cpp b/src/Mod/Part/App/TopoShapeShellPyImp.cpp index e50d82adaf..fc186b0ce2 100644 --- a/src/Mod/Part/App/TopoShapeShellPyImp.cpp +++ b/src/Mod/Part/App/TopoShapeShellPyImp.cpp @@ -100,6 +100,9 @@ int TopoShapeShellPy::PyInit(PyObject* args, PyObject* /*kwd*/) shape = sewShell.ApplySewing(shell); } + if (shape.IsNull()) + Standard_Failure::Raise("Shape is null"); + if (shape.ShapeType() != TopAbs_SHELL) Standard_Failure::Raise("Shape is not a shell"); } diff --git a/src/Mod/Part/App/modelRefine.cpp b/src/Mod/Part/App/modelRefine.cpp index 3fd6082a0c..25bb9378ac 100644 --- a/src/Mod/Part/App/modelRefine.cpp +++ b/src/Mod/Part/App/modelRefine.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -364,7 +365,7 @@ TopoDS_Face FaceTypedPlane::buildFace(const FaceVectorType &faces) const std::sort(wires.begin(), wires.end(), ModelRefine::WireSort()); - TopoDS_Face current = BRepLib_MakeFace(wires.at(0)); + TopoDS_Face current = BRepLib_MakeFace(wires.at(0), Standard_True); if (wires.size() > 1) { ShapeFix_Face faceFix(current); @@ -547,6 +548,8 @@ bool FaceUniter::process() { if (workShell.IsNull()) return false; + modifiedShapes.clear(); + deletedShapes.clear(); typeObjects.push_back(&getPlaneObject()); typeObjects.push_back(&getCylinderObject()); //add more face types. @@ -583,6 +586,12 @@ bool FaceUniter::process() facesToRemove.reserve(facesToRemove.size() + adjacencySplitter.getGroup(adjacentIndex).size()); FaceVectorType temp = adjacencySplitter.getGroup(adjacentIndex); facesToRemove.insert(facesToRemove.end(), temp.begin(), temp.end()); + // the first shape will be marked as modified, i.e. replaced by newFace, all others are marked as deleted + if (!temp.empty()) + { + modifiedShapes.push_back(std::make_pair(temp.front(), newFace)); + deletedShapes.insert(deletedShapes.end(), temp.begin()+1, temp.end()); + } } } } @@ -608,6 +617,15 @@ bool FaceUniter::process() sew.Add(*sewIt); sew.Perform(); workShell = TopoDS::Shell(sew.SewedShape()); + // update the list of modifications + for (std::vector::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) + { + if (sew.IsModified(it->second)) + { + it->second = sew.Modified(it->second); + break; + } + } } else { @@ -629,6 +647,156 @@ bool FaceUniter::process() faceFixer.Perform(); } workShell = TopoDS::Shell(edgeFuse.Shape()); + // update the list of modifications + TopTools_DataMapOfShapeShape faceMap; + edgeFuse.Faces(faceMap); + for (std::vector::iterator it = modifiedShapes.begin(); it != modifiedShapes.end(); ++it) + { + if (faceMap.IsBound(it->second)) + { + const TopoDS_Shape& value = faceMap.Find(it->second); + if (!value.IsSame(it->second)) + it->second = value; + } + } } return true; } + +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +//BRepBuilderAPI_RefineModel implement a way to log all modifications on the faces + +Part::BRepBuilderAPI_RefineModel::BRepBuilderAPI_RefineModel(const TopoDS_Shape& shape) +{ + myShape = shape; + Build(); +} + +void Part::BRepBuilderAPI_RefineModel::Build() +{ + if (myShape.IsNull()) + Standard_Failure::Raise("Cannot remove splitter from empty shape"); + + if (myShape.ShapeType() == TopAbs_SOLID) { + const TopoDS_Solid &solid = TopoDS::Solid(myShape); + BRepTools_ReShape reshape; + TopExp_Explorer it; + for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { + const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); + ModelRefine::FaceUniter uniter(currentShell); + if (uniter.process()) { + if (uniter.isModified()) { + const TopoDS_Shell &newShell = uniter.getShell(); + reshape.Replace(currentShell, newShell); + LogModifications(uniter); + } + } + else { + Standard_Failure::Raise("Removing splitter failed"); + } + } + myShape = reshape.Apply(solid); + } + else if (myShape.ShapeType() == TopAbs_SHELL) { + const TopoDS_Shell& shell = TopoDS::Shell(myShape); + ModelRefine::FaceUniter uniter(shell); + if (uniter.process()) { + myShape = uniter.getShell(); + LogModifications(uniter); + } + else { + Standard_Failure::Raise("Removing splitter failed"); + } + } + else if (myShape.ShapeType() == TopAbs_COMPOUND) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + + TopExp_Explorer xp; + // solids + for (xp.Init(myShape, TopAbs_SOLID); xp.More(); xp.Next()) { + const TopoDS_Solid &solid = TopoDS::Solid(xp.Current()); + BRepTools_ReShape reshape; + TopExp_Explorer it; + for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { + const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); + ModelRefine::FaceUniter uniter(currentShell); + if (uniter.process()) { + if (uniter.isModified()) { + const TopoDS_Shell &newShell = uniter.getShell(); + reshape.Replace(currentShell, newShell); + LogModifications(uniter); + } + } + } + builder.Add(comp, reshape.Apply(solid)); + } + // free shells + for (xp.Init(myShape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next()) { + const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); + ModelRefine::FaceUniter uniter(shell); + if (uniter.process()) { + builder.Add(comp, uniter.getShell()); + LogModifications(uniter); + } + } + // the rest + for (xp.Init(myShape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + for (xp.Init(myShape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + for (xp.Init(myShape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + for (xp.Init(myShape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { + if (!xp.Current().IsNull()) + builder.Add(comp, xp.Current()); + } + + myShape = comp; + } + + Done(); +} + +void Part::BRepBuilderAPI_RefineModel::LogModifications(const ModelRefine::FaceUniter& uniter) +{ + const std::vector& modShapes = uniter.getModifiedShapes(); + for (std::vector::const_iterator it = modShapes.begin(); it != modShapes.end(); ++it) { + TopTools_ListOfShape list; + list.Append(it->second); + myModified.Bind(it->first, list); + } + const ShapeVectorType& delShapes = uniter.getDeletedShapes(); + for (ShapeVectorType::const_iterator it = delShapes.begin(); it != delShapes.end(); ++it) { + myDeleted.Append(*it); + } +} + +const TopTools_ListOfShape& Part::BRepBuilderAPI_RefineModel::Modified(const TopoDS_Shape& S) +{ + if (myModified.IsBound(S)) + return myModified.Find(S); + else + return myEmptyList; +} + +Standard_Boolean Part::BRepBuilderAPI_RefineModel::IsDeleted(const TopoDS_Shape& S) +{ + TopTools_ListIteratorOfListOfShape it; + for (it.Initialize(myDeleted); it.More(); it.Next()) + { + if (it.Value().IsSame(S)) + return Standard_True; + } + + return Standard_False; +} + diff --git a/src/Mod/Part/App/modelRefine.h b/src/Mod/Part/App/modelRefine.h index ed1267f984..32c897ff70 100644 --- a/src/Mod/Part/App/modelRefine.h +++ b/src/Mod/Part/App/modelRefine.h @@ -36,12 +36,15 @@ #include #include #include +#include namespace ModelRefine { - typedef std::vector FaceVectorType; - typedef std::vector EdgeVectorType; + typedef std::vector FaceVectorType; + typedef std::vector EdgeVectorType; + typedef std::vector ShapeVectorType; + typedef std::pair ShapePairType; void getFaceEdges(const TopoDS_Face &face, EdgeVectorType &edges); void boundaryEdges(const FaceVectorType &faces, EdgeVectorType &edgesOut); @@ -147,10 +150,16 @@ namespace ModelRefine bool process(); const TopoDS_Shell& getShell() const {return workShell;} bool isModified(){return modifiedSignal;} + const std::vector& getModifiedShapes() const + {return modifiedShapes;} + const ShapeVectorType& getDeletedShapes() const + {return deletedShapes;} private: TopoDS_Shell workShell; std::vector typeObjects; + std::vector modifiedShapes; + ShapeVectorType deletedShapes; bool modifiedSignal; }; } @@ -170,5 +179,23 @@ GeomAbs_OffsetSurface, GeomAbs_OtherSurface }; */ +namespace Part { +class BRepBuilderAPI_RefineModel : public BRepBuilderAPI_MakeShape +{ +public: + BRepBuilderAPI_RefineModel(const TopoDS_Shape&); + void Build(); + const TopTools_ListOfShape& Modified(const TopoDS_Shape& S); + Standard_Boolean IsDeleted(const TopoDS_Shape& S); + +private: + void LogModifications(const ModelRefine::FaceUniter& uniter); + +private: + TopTools_DataMapOfShapeListOfShape myModified; + TopTools_ListOfShape myEmptyList; + TopTools_ListOfShape myDeleted; +}; +} #endif // MODELREFINE_H diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index d9ff99f955..ec068eb957 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -41,6 +41,7 @@ set(PartGui_MOC_HDRS TaskFaceColors.h TaskShapeBuilder.h TaskLoft.h + TaskSweep.h ) fc_wrap_cpp(PartGui_MOC_SRCS ${PartGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartGui_MOC_SRCS}) @@ -65,6 +66,7 @@ set(PartGui_UIC_SRCS TaskFaceColors.ui TaskShapeBuilder.ui TaskLoft.ui + TaskSweep.ui ) qt4_wrap_ui(PartGui_UIC_HDRS ${PartGui_UIC_SRCS}) @@ -155,6 +157,9 @@ SET(PartGui_SRCS TaskLoft.cpp TaskLoft.h TaskLoft.ui + TaskSweep.cpp + TaskSweep.h + TaskSweep.ui ) SET(PartGui_Scripts diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index 1b616525a7..e713331d9f 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -61,6 +61,7 @@ #include "ViewProvider.h" #include "TaskShapeBuilder.h" #include "TaskLoft.h" +#include "TaskSweep.h" //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -511,7 +512,6 @@ void CmdPartExport::activated(int iMsg) if (!fn.isEmpty()) { App::Document* pDoc = getDocument(); if (!pDoc) return; // no document - openCommand("Import Part"); QString ext = QFileInfo(fn).suffix().toLower(); if (ext == QLatin1String("step") || ext == QLatin1String("stp") || @@ -522,7 +522,6 @@ void CmdPartExport::activated(int iMsg) else { Gui::Application::Instance->exportTo((const char*)fn.toUtf8(),pDoc->getName(),"Part"); } - commitCommand(); } } @@ -948,6 +947,7 @@ CmdPartLoft::CmdPartLoft() sToolTipText = QT_TR_NOOP("Advanced utility to lofts"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; + sPixmap = "Part_Loft"; } void CmdPartLoft::activated(int iMsg) @@ -962,6 +962,32 @@ bool CmdPartLoft::isActive(void) //-------------------------------------------------------------------------------------- +DEF_STD_CMD_A(CmdPartSweep); + +CmdPartSweep::CmdPartSweep() + : Command("Part_Sweep") +{ + sAppModule = "Part"; + sGroup = QT_TR_NOOP("Part"); + sMenuText = QT_TR_NOOP("Sweep..."); + sToolTipText = QT_TR_NOOP("Advanced utility to sweep"); + sWhatsThis = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "Part_Sweep"; +} + +void CmdPartSweep::activated(int iMsg) +{ + Gui::Control().showDialog(new PartGui::TaskSweep()); +} + +bool CmdPartSweep::isActive(void) +{ + return (hasActiveDocument() && !Gui::Control().activeDialog()); +} + +//-------------------------------------------------------------------------------------- + DEF_STD_CMD_A(CmdShapeInfo); CmdShapeInfo::CmdShapeInfo() @@ -1196,5 +1222,6 @@ void CreatePartCommands(void) rcCmdMgr.addCommand(new CmdPartRuledSurface()); rcCmdMgr.addCommand(new CmdPartBuilder()); rcCmdMgr.addCommand(new CmdPartLoft()); + rcCmdMgr.addCommand(new CmdPartSweep()); } diff --git a/src/Mod/Part/Gui/DlgFilletEdges.cpp b/src/Mod/Part/Gui/DlgFilletEdges.cpp index 6fa8ab5e92..f6c701ab8b 100644 --- a/src/Mod/Part/Gui/DlgFilletEdges.cpp +++ b/src/Mod/Part/Gui/DlgFilletEdges.cpp @@ -157,6 +157,7 @@ namespace PartGui { App::DocumentObject* object; EdgeSelection* selection; Part::FilletBase* fillet; + std::vector edge_ids; typedef boost::signals::connection Connection; Connection connectApplicationDeletedObject; Connection connectApplicationDeletedDocument; @@ -374,10 +375,13 @@ void DlgFilletEdges::setupFillet(const std::vector& objs) ui->shapeObject->setEnabled(false); QStandardItemModel *model = qobject_cast(ui->treeView->model()); for (std::vector::const_iterator et = e.begin(); et != e.end(); ++et) { - int index = et->edgeid-1; - model->setData(model->index(index, 0), Qt::Checked, Qt::CheckStateRole); - model->setData(model->index(index, 1), QVariant(QLocale::system().toString(et->radius1,'f',2))); - model->setData(model->index(index, 2), QVariant(QLocale::system().toString(et->radius2,'f',2))); + std::vector::iterator it = std::find(d->edge_ids.begin(), d->edge_ids.end(), et->edgeid); + if (it != d->edge_ids.end()) { + int index = it - d->edge_ids.begin(); + model->setData(model->index(index, 0), Qt::Checked, Qt::CheckStateRole); + model->setData(model->index(index, 1), QVariant(QLocale::system().toString(et->radius1,'f',2))); + model->setData(model->index(index, 2), QVariant(QLocale::system().toString(et->radius2,'f',2))); + } } } } @@ -438,33 +442,30 @@ void DlgFilletEdges::on_shapeObject_activated(int index) TopExp::MapShapes(myShape, TopAbs_EDGE, mapOfShape); // populate the model - std::vector edge_ids; + d->edge_ids.clear(); for (int i=1; i<= edge2Face.Extent(); ++i) { // set the index value as user data to use it in accept() const TopTools_ListOfShape& los = edge2Face.FindFromIndex(i); if (los.Extent() == 2) { // set the index value as user data to use it in accept() const TopoDS_Shape& edge = edge2Face.FindKey(i); - const TopTools_ListOfShape& los = edge2Face.FindFromIndex(i); - if (los.Extent() == 2) { - // Now check also the continuity to only allow C0-continious - // faces - 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) { - int id = mapOfShape.FindIndex(edge); - edge_ids.push_back(id); - } + // Now check also the continuity to only allow C0-continious + // faces + 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) { + int id = mapOfShape.FindIndex(edge); + d->edge_ids.push_back(id); } } } - model->insertRows(0, edge_ids.size()); + model->insertRows(0, d->edge_ids.size()); int index = 0; - for (std::vector::iterator it = edge_ids.begin(); it != edge_ids.end(); ++it) { + for (std::vector::iterator it = d->edge_ids.begin(); it != d->edge_ids.end(); ++it) { model->setData(model->index(index, 0), QVariant(tr("Edge%1").arg(*it))); model->setData(model->index(index, 0), QVariant(*it), Qt::UserRole); model->setData(model->index(index, 1), QVariant(QLocale::system().toString(1.0,'f',2))); diff --git a/src/Mod/Part/Gui/DlgPrimitives.cpp b/src/Mod/Part/Gui/DlgPrimitives.cpp index 83b6b53cc5..3665dd196e 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.cpp +++ b/src/Mod/Part/Gui/DlgPrimitives.cpp @@ -481,12 +481,14 @@ void DlgPrimitives::createPrimitive(const QString& placement) "App.ActiveDocument.%1.Height=%3\n" "App.ActiveDocument.%1.Radius=%4\n" "App.ActiveDocument.%1.Angle=%5\n" - "App.ActiveDocument.%1.Placement=%6\n") + "App.ActiveDocument.%1.LocalCoord=%6\n" + "App.ActiveDocument.%1.Placement=%7\n") .arg(name) .arg(ui.helixPitch->value(),0,'f',2) .arg(ui.helixHeight->value(),0,'f',2) .arg(ui.helixRadius->value(),0,'f',2) .arg(ui.helixAngle->value(),0,'f',2) + .arg(ui.helixLocalCS->currentIndex()) .arg(placement); } else if (ui.comboBox1->currentIndex() == 9) { // circle diff --git a/src/Mod/Part/Gui/DlgPrimitives.ui b/src/Mod/Part/Gui/DlgPrimitives.ui index 6138066ea9..4bc21969f7 100644 --- a/src/Mod/Part/Gui/DlgPrimitives.ui +++ b/src/Mod/Part/Gui/DlgPrimitives.ui @@ -1231,6 +1231,27 @@ + + + + Coordinate system: + + + + + + + + Right-handed + + + + + Left-handed + + + + diff --git a/src/Mod/Part/Gui/DlgRevolution.cpp b/src/Mod/Part/Gui/DlgRevolution.cpp index 32af63d27b..d0a04668d9 100644 --- a/src/Mod/Part/Gui/DlgRevolution.cpp +++ b/src/Mod/Part/Gui/DlgRevolution.cpp @@ -24,7 +24,13 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +# include +# include +# include # include +# include +# include #endif #include "ui_DlgRevolution.h" @@ -40,16 +46,60 @@ #include #include #include +#include using namespace PartGui; +class DlgRevolution::EdgeSelection : public Gui::SelectionFilterGate +{ +public: + gp_Pnt loc; + gp_Dir dir; + bool canSelect; + + EdgeSelection() + : Gui::SelectionFilterGate((Gui::SelectionFilter*)0) + { + } + bool allow(App::Document*pDoc, App::DocumentObject*pObj, const char*sSubName) + { + this->canSelect = false; + if (!pObj->isDerivedFrom(Part::Feature::getClassTypeId())) + return false; + if (!sSubName || sSubName[0] == '\0') + return false; + std::string element(sSubName); + if (element.substr(0,4) != "Edge") + return false; + Part::Feature* fea = static_cast(pObj); + try { + TopoDS_Shape sub = fea->Shape.getShape().getSubShape(sSubName); + if (!sub.IsNull() && sub.ShapeType() == TopAbs_EDGE) { + const TopoDS_Edge& edge = TopoDS::Edge(sub); + BRepAdaptor_Curve adapt(edge); + if (adapt.GetType() == GeomAbs_Line) { + gp_Lin line = adapt.Line(); + this->loc = line.Location(); + this->dir = line.Direction(); + this->canSelect = true; + return true; + } + } + } + catch (...) { + } + + return false; + } +}; + DlgRevolution::DlgRevolution(QWidget* parent, Qt::WFlags fl) - : Gui::LocationDialog(parent, fl) + : Gui::LocationDialog(parent, fl), filter(0) { ui = new Ui_RevolutionComp(this); - ui->baseX->setRange(-DBL_MAX,DBL_MAX); - ui->baseY->setRange(-DBL_MAX,DBL_MAX); - ui->baseZ->setRange(-DBL_MAX,DBL_MAX); + ui->xPos->setRange(-DBL_MAX,DBL_MAX); + ui->yPos->setRange(-DBL_MAX,DBL_MAX); + ui->zPos->setRange(-DBL_MAX,DBL_MAX); findShapes(); Gui::ItemViewSelection sel(ui->treeWidget); @@ -62,6 +112,7 @@ DlgRevolution::DlgRevolution(QWidget* parent, Qt::WFlags fl) DlgRevolution::~DlgRevolution() { // no need to delete child widgets, Qt does it all for us + Gui::Selection().rmvSelectionGate(); delete ui; } @@ -142,9 +193,9 @@ void DlgRevolution::accept() .arg(axis.x,0,'f',2) .arg(axis.y,0,'f',2) .arg(axis.z,0,'f',2) - .arg(ui->baseX->value(),0,'f',2) - .arg(ui->baseY->value(),0,'f',2) - .arg(ui->baseZ->value(),0,'f',2) + .arg(ui->xPos->value(),0,'f',2) + .arg(ui->yPos->value(),0,'f',2) + .arg(ui->zPos->value(),0,'f',2) .arg(ui->angle->value(),0,'f',2); Gui::Application::Instance->runPythonCode((const char*)code.toAscii()); QByteArray to = name.toAscii(); @@ -159,6 +210,24 @@ void DlgRevolution::accept() QDialog::accept(); } +void DlgRevolution::on_selectLine_clicked() +{ + if (!filter) { + filter = new EdgeSelection(); + Gui::Selection().addSelectionGate(filter); + } +} + +void DlgRevolution::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + if (msg.Type == Gui::SelectionChanges::AddSelection) { + if (filter && filter->canSelect) { + ui->setPosition (Base::convertTo(filter->loc)); + ui->setDirection(Base::convertTo(filter->dir)); + } + } +} + // --------------------------------------- TaskRevolution::TaskRevolution() diff --git a/src/Mod/Part/Gui/DlgRevolution.h b/src/Mod/Part/Gui/DlgRevolution.h index 50359a474a..8e4ebba507 100644 --- a/src/Mod/Part/Gui/DlgRevolution.h +++ b/src/Mod/Part/Gui/DlgRevolution.h @@ -23,6 +23,7 @@ #ifndef PARTGUI_DLGREVOLUTION_H #define PARTGUI_DLGREVOLUTION_H +#include #include #include #include @@ -30,7 +31,7 @@ namespace PartGui { class Ui_DlgRevolution; -class DlgRevolution : public Gui::LocationDialog +class DlgRevolution : public Gui::LocationDialog, public Gui::SelectionObserver { Q_OBJECT @@ -44,13 +45,19 @@ public: protected: void changeEvent(QEvent *e); +private Q_SLOTS: + void on_selectLine_clicked(); + private: void findShapes(); void directionActivated(int); + void onSelectionChanged(const Gui::SelectionChanges& msg); private: typedef Gui::LocationInterfaceComp Ui_RevolutionComp; Ui_RevolutionComp* ui; + class EdgeSelection; + EdgeSelection* filter; }; class TaskRevolution : public Gui::TaskView::TaskDialog diff --git a/src/Mod/Part/Gui/DlgRevolution.ui b/src/Mod/Part/Gui/DlgRevolution.ui index 2f5f694c97..6c5635118b 100644 --- a/src/Mod/Part/Gui/DlgRevolution.ui +++ b/src/Mod/Part/Gui/DlgRevolution.ui @@ -49,7 +49,7 @@ - + @@ -62,7 +62,7 @@ - + @@ -88,7 +88,7 @@ - + @@ -105,7 +105,7 @@ - + Qt::Vertical @@ -118,7 +118,7 @@ - + QAbstractItemView::ExtendedSelection @@ -136,14 +136,21 @@ + + + + Select line in 3D view + + + treeWidget angle - baseX - baseY - baseZ + xPos + yPos + zPos direction diff --git a/src/Mod/Part/Gui/DlgSettingsGeneral.cpp b/src/Mod/Part/Gui/DlgSettingsGeneral.cpp index 61bce31f2f..a9c917a86e 100644 --- a/src/Mod/Part/Gui/DlgSettingsGeneral.cpp +++ b/src/Mod/Part/Gui/DlgSettingsGeneral.cpp @@ -69,6 +69,7 @@ void DlgSettingsGeneral::saveSettings() Interface_Static::SetCVal("write.step.unit","MM"); break; } + ui->checkBooleanRefine->onSave(); } void DlgSettingsGeneral::loadSettings() @@ -77,6 +78,7 @@ void DlgSettingsGeneral::loadSettings() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/Part"); int unit = hGrp->GetInt("Unit", 0); ui->comboBoxUnits->setCurrentIndex(unit); + ui->checkBooleanRefine->onRestore(); } /** diff --git a/src/Mod/Part/Gui/DlgSettingsGeneral.ui b/src/Mod/Part/Gui/DlgSettingsGeneral.ui index 4bca9519f0..4ea3f5222d 100644 --- a/src/Mod/Part/Gui/DlgSettingsGeneral.ui +++ b/src/Mod/Part/Gui/DlgSettingsGeneral.ui @@ -1,10 +1,8 @@ - - - - + + PartGui::DlgSettingsGeneral - - + + 0 0 @@ -12,73 +10,54 @@ 333 - + General - - - 9 - - - 6 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - + + + + Export - - + + 9 - + 6 - - + + - + Millimeter - + Meter - + Inch - - - + + + Units for export of STEP/IGES - + - + Qt::Horizontal - + 40 20 @@ -89,9 +68,50 @@ + + + + Boolean operation + + + + + + Automatically refine model after boolean operation + + + RefineModel + + + Mod/Part/Boolean + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + - + + + Gui::PrefCheckBox + QCheckBox +

Gui/PrefWidgets.h
+ + diff --git a/src/Mod/Part/Gui/Makefile.am b/src/Mod/Part/Gui/Makefile.am index fe7d7a8ddb..15a2a094ab 100644 --- a/src/Mod/Part/Gui/Makefile.am +++ b/src/Mod/Part/Gui/Makefile.am @@ -200,12 +200,14 @@ EXTRA_DIST = \ Resources/icons/Part_Fillet.svg \ Resources/icons/Part_Revolve.svg \ Resources/icons/Part_Import.svg \ + Resources/icons/Part_Loft.svg \ Resources/icons/Part_Mirror.svg \ Resources/icons/Part_MirrorPNG.png \ Resources/icons/Part_RuledSurface.svg \ Resources/icons/Part_Shapebuilder.png \ Resources/icons/Part_Shapebuilder.svg \ Resources/icons/Part_ShapeInfo.svg \ + Resources/icons/Part_Sweep.svg \ Resources/icons/Tree_Part.svg \ Resources/icons/preferences-part_design.svg \ Resources/icons/PartFeature.svg \ @@ -247,6 +249,8 @@ EXTRA_DIST = \ Resources/translations/Part_nl.ts \ Resources/translations/Part_no.qm \ Resources/translations/Part_no.ts \ + Resources/translations/Part_pl.qm \ + Resources/translations/Part_pl.ts \ Resources/translations/Part_pt.qm \ Resources/translations/Part_pt.ts \ Resources/translations/Part_ru.qm \ diff --git a/src/Mod/Part/Gui/Resources/Part.qrc b/src/Mod/Part/Gui/Resources/Part.qrc index 213e2c47a9..f6fbdf0c33 100644 --- a/src/Mod/Part/Gui/Resources/Part.qrc +++ b/src/Mod/Part/Gui/Resources/Part.qrc @@ -16,6 +16,7 @@ icons/Part_Fillet.svg icons/Part_Fuse.svg icons/Part_Import.svg + icons/Part_Loft.svg icons/Part_Mirror.svg icons/Part_MirrorPNG.png icons/Part_Revolve.svg @@ -24,6 +25,7 @@ icons/Part_Shapebuilder.png icons/Part_ShapeInfo.svg icons/Part_Sphere.svg + icons/Part_Sweep.svg icons/Part_Torus.svg icons/preferences-part_design.svg icons/Tree_Part.svg @@ -36,6 +38,7 @@ translations/Part_it.qm translations/Part_nl.qm translations/Part_no.qm + translations/Part_pl.qm translations/Part_pt.qm translations/Part_ru.qm translations/Part_se.qm diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Loft.svg b/src/Mod/Part/Gui/Resources/icons/Part_Loft.svg new file mode 100644 index 0000000000..72df9ab92a --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Loft.svg @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/Resources/icons/Part_Sweep.svg b/src/Mod/Part/Gui/Resources/icons/Part_Sweep.svg new file mode 100644 index 0000000000..33a9f428ab --- /dev/null +++ b/src/Mod/Part/Gui/Resources/icons/Part_Sweep.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/src/Mod/Part/Gui/TaskLoft.cpp b/src/Mod/Part/Gui/TaskLoft.cpp index aed8dd911f..7192c27c42 100644 --- a/src/Mod/Part/Gui/TaskLoft.cpp +++ b/src/Mod/Part/Gui/TaskLoft.cpp @@ -32,6 +32,7 @@ #include "TaskLoft.h" #include +#include #include #include #include @@ -68,10 +69,14 @@ LoftWidget::LoftWidget(QWidget* parent) Gui::Application::Instance->runPythonCode("import Part"); d->ui.setupUi(this); - connect(d->ui.treeWidgetWire, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + d->ui.selector->setAvailableLabel(tr("Vertex/Wire")); + d->ui.selector->setSelectedLabel(tr("Loft")); + + connect(d->ui.selector->availableTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); - connect(d->ui.treeWidgetLoft, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + connect(d->ui.selector->selectedTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); + findShapes(); } @@ -93,7 +98,9 @@ void LoftWidget::findShapes() const TopoDS_Shape& shape = (*it)->Shape.getValue(); if (shape.IsNull()) continue; - if (shape.ShapeType() == TopAbs_WIRE || shape.ShapeType() == TopAbs_VERTEX) { + if (shape.ShapeType() == TopAbs_WIRE || + shape.ShapeType() == TopAbs_EDGE || + shape.ShapeType() == TopAbs_VERTEX) { QString label = QString::fromUtf8((*it)->Label.getValue()); QString name = QString::fromAscii((*it)->getNameInDocument()); @@ -103,7 +110,7 @@ void LoftWidget::findShapes() child->setData(0, Qt::UserRole, name); Gui::ViewProvider* vp = activeGui->getViewProvider(*it); if (vp) child->setIcon(0, vp->getIcon()); - d->ui.treeWidgetWire->addTopLevelItem(child); + d->ui.selector->availableTreeWidget()->addTopLevelItem(child); } } } @@ -123,13 +130,13 @@ bool LoftWidget::accept() QTextStream str(&list); - int count = d->ui.treeWidgetLoft->topLevelItemCount(); + int count = d->ui.selector->selectedTreeWidget()->topLevelItemCount(); if (count < 2) { - QMessageBox::critical(this, tr("Too few elements"), tr("At least two vertices or wires are required.")); + QMessageBox::critical(this, tr("Too few elements"), tr("At least two vertices, edges or wires are required.")); return false; } for (int i=0; iui.treeWidgetLoft->topLevelItem(i); + QTreeWidgetItem* child = d->ui.selector->selectedTreeWidget()->topLevelItem(i); QString name = child->data(0, Qt::UserRole).toString(); str << "App.getDocument('" << d->document.c_str() << "')." << name << ", "; } @@ -175,61 +182,13 @@ void LoftWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* } } -void LoftWidget::on_addButton_clicked() -{ - QTreeWidgetItem* item = d->ui.treeWidgetWire->currentItem(); - if (item) { - int index = d->ui.treeWidgetWire->indexOfTopLevelItem(item); - item = d->ui.treeWidgetWire->takeTopLevelItem(index); - d->ui.treeWidgetWire->setCurrentItem(0); - d->ui.treeWidgetLoft->addTopLevelItem(item); - d->ui.treeWidgetLoft->setCurrentItem(item); - } -} - -void LoftWidget::on_removeButton_clicked() -{ - QTreeWidgetItem* item = d->ui.treeWidgetLoft->currentItem(); - if (item) { - int index = d->ui.treeWidgetLoft->indexOfTopLevelItem(item); - item = d->ui.treeWidgetLoft->takeTopLevelItem(index); - d->ui.treeWidgetLoft->setCurrentItem(0); - d->ui.treeWidgetWire->addTopLevelItem(item); - d->ui.treeWidgetWire->setCurrentItem(item); - } -} - -void LoftWidget::on_upButton_clicked() -{ - QTreeWidgetItem* item = d->ui.treeWidgetLoft->currentItem(); - if (item && d->ui.treeWidgetLoft->isItemSelected(item)) { - int index = d->ui.treeWidgetLoft->indexOfTopLevelItem(item); - if (index > 0) { - d->ui.treeWidgetLoft->takeTopLevelItem(index); - d->ui.treeWidgetLoft->insertTopLevelItem(index-1, item); - d->ui.treeWidgetLoft->setCurrentItem(item); - } - } -} - -void LoftWidget::on_downButton_clicked() -{ - QTreeWidgetItem* item = d->ui.treeWidgetLoft->currentItem(); - if (item && d->ui.treeWidgetLoft->isItemSelected(item)) { - int index = d->ui.treeWidgetLoft->indexOfTopLevelItem(item); - if (index < d->ui.treeWidgetLoft->topLevelItemCount()-1) { - d->ui.treeWidgetLoft->takeTopLevelItem(index); - d->ui.treeWidgetLoft->insertTopLevelItem(index+1, item); - d->ui.treeWidgetLoft->setCurrentItem(item); - } - } -} - void LoftWidget::changeEvent(QEvent *e) { QWidget::changeEvent(e); if (e->type() == QEvent::LanguageChange) { d->ui.retranslateUi(this); + d->ui.selector->setAvailableLabel(tr("Vertex/Wire")); + d->ui.selector->setSelectedLabel(tr("Loft")); } } @@ -240,7 +199,8 @@ TaskLoft::TaskLoft() { widget = new LoftWidget(); taskbox = new Gui::TaskView::TaskBox( - QPixmap(), widget->windowTitle(), true, 0); + Gui::BitmapFactory().pixmap("Part_Loft"), + widget->windowTitle(), true, 0); taskbox->groupLayout()->addWidget(widget); Content.push_back(taskbox); } diff --git a/src/Mod/Part/Gui/TaskLoft.h b/src/Mod/Part/Gui/TaskLoft.h index 82ac877a51..50d30771d1 100644 --- a/src/Mod/Part/Gui/TaskLoft.h +++ b/src/Mod/Part/Gui/TaskLoft.h @@ -43,10 +43,6 @@ public: bool reject(); private Q_SLOTS: - void on_addButton_clicked(); - void on_removeButton_clicked(); - void on_upButton_clicked(); - void on_downButton_clicked(); void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*); private: diff --git a/src/Mod/Part/Gui/TaskLoft.ui b/src/Mod/Part/Gui/TaskLoft.ui index 1dd0c6159f..dd461047d9 100644 --- a/src/Mod/Part/Gui/TaskLoft.ui +++ b/src/Mod/Part/Gui/TaskLoft.ui @@ -6,7 +6,7 @@ 0 0 - 324 + 336 326
@@ -14,172 +14,8 @@ Loft
- - - - - Vertex/Wire - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 33 - 58 - - - - - - - - true - - - - 30 - 30 - - - - Move right - - - <b>Move the selected item one level down.</b><p>This will also change the level of the parent item.</p> - - - - - - - :/icons/button_right.xpm:/icons/button_right.xpm - - - - - - - true - - - - 30 - 30 - - - - Move left - - - <b>Move the selected item one level up.</b><p>This will also change the level of the parent item.</p> - - - - - - - :/icons/button_left.xpm:/icons/button_left.xpm - - - true - - - false - - - - - - - true - - - - 30 - 30 - - - - Move up - - - <b>Move the selected item up.</b><p>The item will be moved within the hierarchy level.</p> - - - - - - - :/icons/button_up.xpm:/icons/button_up.xpm - - - - - - - true - - - - 30 - 30 - - - - Move down - - - <b>Move the selected item down.</b><p>The item will be moved within the hierarchy level.</p> - - - - - - - :/icons/button_down.xpm:/icons/button_down.xpm - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 33 - 57 - - - - - - - - - - - Loft - - - + + @@ -188,15 +24,35 @@ - + Ruled surface + + + + Qt::Horizontal + + + + 130 + 20 + + + +
+ + + Gui::ActionSelector + QWidget +
Gui/Widgets.h
+
+
diff --git a/src/Mod/Part/Gui/TaskShapeBuilder.cpp b/src/Mod/Part/Gui/TaskShapeBuilder.cpp index d7d2dbacf8..1d37534be7 100644 --- a/src/Mod/Part/Gui/TaskShapeBuilder.cpp +++ b/src/Mod/Part/Gui/TaskShapeBuilder.cpp @@ -201,10 +201,10 @@ void ShapeBuilderWidget::createEdge() void ShapeBuilderWidget::createFace() { - Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 3.."); + Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1.."); bool matchEdge = edgeFilter.match(); if (!matchEdge) { - QMessageBox::critical(this, tr("Wrong selection"), tr("Select three or more edges")); + QMessageBox::critical(this, tr("Wrong selection"), tr("Select one or more edges")); return; } diff --git a/src/Mod/Part/Gui/TaskSweep.cpp b/src/Mod/Part/Gui/TaskSweep.cpp new file mode 100644 index 0000000000..64e9995e46 --- /dev/null +++ b/src/Mod/Part/Gui/TaskSweep.cpp @@ -0,0 +1,257 @@ +/*************************************************************************** + * Copyright (c) 2011 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 +#endif + +#include "ui_TaskSweep.h" +#include "TaskSweep.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace PartGui; + +class SweepWidget::Private +{ +public: + Ui_TaskSweep ui; + std::string document; + Private() + { + } + ~Private() + { + } +}; + +/* TRANSLATOR PartGui::SweepWidget */ + +SweepWidget::SweepWidget(QWidget* parent) + : d(new Private()) +{ + Gui::Application::Instance->runPythonCode("from FreeCAD import Base"); + Gui::Application::Instance->runPythonCode("import Part"); + + d->ui.setupUi(this); + d->ui.selector->setAvailableLabel(tr("Vertex/Wire")); + d->ui.selector->setSelectedLabel(tr("Sweep")); + + connect(d->ui.selector->availableTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); + connect(d->ui.selector->selectedTreeWidget(), SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), + this, SLOT(onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*))); + + findShapes(); +} + +SweepWidget::~SweepWidget() +{ + delete d; +} + +void SweepWidget::findShapes() +{ + App::Document* activeDoc = App::GetApplication().getActiveDocument(); + Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc); + if (!activeGui) return; + d->document = activeDoc->getName(); + + std::vector objs = activeDoc->getObjectsOfType(); + + for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { + const TopoDS_Shape& shape = (*it)->Shape.getValue(); + if (shape.IsNull()) continue; + + if (shape.ShapeType() == TopAbs_WIRE || + shape.ShapeType() == TopAbs_EDGE || + shape.ShapeType() == TopAbs_VERTEX) { + QString label = QString::fromUtf8((*it)->Label.getValue()); + QString name = QString::fromAscii((*it)->getNameInDocument()); + + QTreeWidgetItem* child = new QTreeWidgetItem(); + child->setText(0, label); + child->setToolTip(0, label); + child->setData(0, Qt::UserRole, name); + Gui::ViewProvider* vp = activeGui->getViewProvider(*it); + if (vp) child->setIcon(0, vp->getIcon()); + d->ui.selector->availableTreeWidget()->addTopLevelItem(child); + } + } +} + +bool SweepWidget::accept() +{ + Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1"); + Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 1"); + bool matchEdge = edgeFilter.match(); + bool matchPart = partFilter.match(); + if (!matchEdge && !matchPart) { + QMessageBox::critical(this, tr("Sweep path"), tr("Select an edge or wire you want to sweep along.")); + return false; + } + + // get the selected object + std::string objectName, subShape; + if (matchEdge) { + const std::vector& result = edgeFilter.Result[0]; + const std::vector& edges = result[0].getSubNames(); + objectName = result.front().getFeatName(); + subShape = edges.front(); + } + else { + const std::vector& result = partFilter.Result[0]; + objectName = result.front().getFeatName(); + } + + QString list, solid, frenet; + if (d->ui.checkSolid->isChecked()) + solid = QString::fromAscii("True"); + else + solid = QString::fromAscii("False"); + + if (d->ui.checkFrenet->isChecked()) + frenet = QString::fromAscii("True"); + else + frenet = QString::fromAscii("False"); + + QTextStream str(&list); + + int count = d->ui.selector->selectedTreeWidget()->topLevelItemCount(); + if (count < 1) { + QMessageBox::critical(this, tr("Too few elements"), tr("At least one edge or wire is required.")); + return false; + } + for (int i=0; iui.selector->selectedTreeWidget()->topLevelItem(i); + QString name = child->data(0, Qt::UserRole).toString(); + str << "App.getDocument('" << d->document.c_str() << "')." << name << ", "; + } + + try { + QString cmd; + cmd = QString::fromAscii( + "App.getDocument('%6').addObject('Part::Sweep','Sweep')\n" + "App.getDocument('%6').ActiveObject.Sections=[%1]\n" + "App.getDocument('%6').ActiveObject.Spine=(FreeCAD.ActiveDocument.%2,['%3'])\n" + "App.getDocument('%6').ActiveObject.Solid=%4\n" + "App.getDocument('%6').ActiveObject.Frenet=%5\n" + ) + .arg(list).arg(QLatin1String(objectName.c_str())) + .arg(QLatin1String(subShape.c_str())) + .arg(solid).arg(frenet).arg(QString::fromAscii(d->document.c_str())); + + Gui::Document* doc = Gui::Application::Instance->getDocument(d->document.c_str()); + if (!doc) throw Base::Exception("Document doesn't exist anymore"); + doc->openCommand("Sweep"); + Gui::Application::Instance->runPythonCode((const char*)cmd.toAscii(), false, false); + doc->commitCommand(); + doc->getDocument()->recompute(); + } + catch (const Base::Exception& e) { + Base::Console().Error("%s\n", e.what()); + return false; + } + + return true; +} + +bool SweepWidget::reject() +{ + return true; +} + +void SweepWidget::onCurrentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* previous) +{ + if (previous) { + Gui::Selection().rmvSelection(d->document.c_str(), + (const char*)previous->data(0,Qt::UserRole).toByteArray()); + } + if (current) { + Gui::Selection().addSelection(d->document.c_str(), + (const char*)current->data(0,Qt::UserRole).toByteArray()); + } +} + +void SweepWidget::changeEvent(QEvent *e) +{ + QWidget::changeEvent(e); + if (e->type() == QEvent::LanguageChange) { + d->ui.retranslateUi(this); + d->ui.selector->setAvailableLabel(tr("Vertex/Wire")); + d->ui.selector->setSelectedLabel(tr("Sweep")); + } +} + + +/* TRANSLATOR PartGui::TaskSweep */ + +TaskSweep::TaskSweep() +{ + widget = new SweepWidget(); + taskbox = new Gui::TaskView::TaskBox( + Gui::BitmapFactory().pixmap("Part_Sweep"), + widget->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskSweep::~TaskSweep() +{ +} + +void TaskSweep::open() +{ +} + +void TaskSweep::clicked(int) +{ +} + +bool TaskSweep::accept() +{ + return widget->accept(); +} + +bool TaskSweep::reject() +{ + return widget->reject(); +} + +#include "moc_TaskSweep.cpp" diff --git a/src/Mod/Part/Gui/TaskSweep.h b/src/Mod/Part/Gui/TaskSweep.h new file mode 100644 index 0000000000..f0c6fc5921 --- /dev/null +++ b/src/Mod/Part/Gui/TaskSweep.h @@ -0,0 +1,81 @@ +/*************************************************************************** + * Copyright (c) 2011 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 * + * * + ***************************************************************************/ + + +#ifndef PARTGUI_TASKSWEEP_H +#define PARTGUI_TASKSWEEP_H + +#include +#include + +class QTreeWidgetItem; + +namespace PartGui { + +class SweepWidget : public QWidget +{ + Q_OBJECT + +public: + SweepWidget(QWidget* parent = 0); + ~SweepWidget(); + + bool accept(); + bool reject(); + +private Q_SLOTS: + void onCurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*); + +private: + void changeEvent(QEvent *e); + void findShapes(); + +private: + class Private; + Private* d; +}; + +class TaskSweep : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskSweep(); + ~TaskSweep(); + +public: + void open(); + bool accept(); + bool reject(); + void clicked(int); + + QDialogButtonBox::StandardButtons getStandardButtons() const + { return QDialogButtonBox::Ok|QDialogButtonBox::Cancel; } + +private: + SweepWidget* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} //namespace PartGui + +#endif // PARTGUI_TASKSWEEP_H diff --git a/src/Mod/Part/Gui/TaskSweep.ui b/src/Mod/Part/Gui/TaskSweep.ui new file mode 100644 index 0000000000..6cfab459d1 --- /dev/null +++ b/src/Mod/Part/Gui/TaskSweep.ui @@ -0,0 +1,68 @@ + + + PartGui::TaskSweep + + + + 0 + 0 + 336 + 326 + + + + Sweep + + + + + + + + + Create solid + + + + + + + Qt::Horizontal + + + + 130 + 20 + + + + + + + + Frenet + + + + + + + Select one or more profiles and select an edge or wire +in the 3D view for the sweep path. + + + + + + + + Gui::ActionSelector + QWidget +
Gui/Widgets.h
+
+
+ + + + +
diff --git a/src/Mod/Part/Gui/ViewProviderBoolean.cpp b/src/Mod/Part/Gui/ViewProviderBoolean.cpp index 5857b2ef71..d73afe2966 100644 --- a/src/Mod/Part/Gui/ViewProviderBoolean.cpp +++ b/src/Mod/Part/Gui/ViewProviderBoolean.cpp @@ -24,9 +24,15 @@ #include "PreCompiled.h" #ifndef _PreComp_ +# include +# include +# include +# include +# include #endif #include "ViewProviderBoolean.h" +#include #include #include #include @@ -71,6 +77,72 @@ QIcon ViewProviderBoolean::getIcon(void) const return ViewProviderPart::getIcon(); } +void applyColor(const Part::ShapeHistory& hist, + const std::vector& colBase, + std::vector& colBool) +{ + std::map >::const_iterator jt; + // apply color from modified faces + for (jt = hist.shapeMap.begin(); jt != hist.shapeMap.end(); ++jt) { + std::vector::const_iterator kt; + for (kt = jt->second.begin(); kt != jt->second.end(); ++kt) { + colBool[*kt] = colBase[jt->first]; + } + } +} + +void ViewProviderBoolean::updateData(const App::Property* prop) +{ + PartGui::ViewProviderPart::updateData(prop); + if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) { + const std::vector& hist = static_cast + (prop)->getValues(); + if (hist.size() != 2) + return; + Part::Boolean* objBool = dynamic_cast(getObject()); + Part::Feature* objBase = dynamic_cast(objBool->Base.getValue()); + Part::Feature* objTool = dynamic_cast(objBool->Tool.getValue()); + if (objBase && objTool) { + const TopoDS_Shape& baseShape = objBase->Shape.getValue(); + const TopoDS_Shape& toolShape = objTool->Shape.getValue(); + const TopoDS_Shape& boolShape = objBool->Shape.getValue(); + + TopTools_IndexedMapOfShape baseMap, toolMap, boolMap; + TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap); + TopExp::MapShapes(toolShape, TopAbs_FACE, toolMap); + TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); + + Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase); + Gui::ViewProvider* vpTool = Gui::Application::Instance->getViewProvider(objTool); + std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); + std::vector colTool = static_cast(vpTool)->DiffuseColor.getValues(); + std::vector colBool; + colBool.resize(boolMap.Extent(), this->ShapeColor.getValue()); + + bool setColor=false; + if (colBase.size() == baseMap.Extent()) { + applyColor(hist[0], colBase, colBool); + setColor = true; + } + else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + colBase.resize(baseMap.Extent(), colBase[0]); + applyColor(hist[0], colBase, colBool); + setColor = true; + } + if (colTool.size() == toolMap.Extent()) { + applyColor(hist[1], colTool, colBool); + setColor = true; + } + else if (!colTool.empty() && colTool[0] != this->ShapeColor.getValue()) { + colTool.resize(toolMap.Extent(), colTool[0]); + applyColor(hist[1], colTool, colBool); + setColor = true; + } + if (setColor) + this->DiffuseColor.setValues(colBool); + } + } +} PROPERTY_SOURCE(PartGui::ViewProviderMultiFuse,PartGui::ViewProviderPart) @@ -92,6 +164,51 @@ QIcon ViewProviderMultiFuse::getIcon(void) const return Gui::BitmapFactory().pixmap("Part_Fuse"); } +void ViewProviderMultiFuse::updateData(const App::Property* prop) +{ + PartGui::ViewProviderPart::updateData(prop); + if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) { + const std::vector& hist = static_cast + (prop)->getValues(); + Part::MultiFuse* objBool = dynamic_cast(getObject()); + std::vector sources = objBool->Shapes.getValues(); + if (hist.size() != sources.size()) + return; + + const TopoDS_Shape& boolShape = objBool->Shape.getValue(); + TopTools_IndexedMapOfShape boolMap; + TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); + + std::vector colBool; + colBool.resize(boolMap.Extent(), this->ShapeColor.getValue()); + + bool setColor=false; + int index=0; + for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { + Part::Feature* objBase = dynamic_cast(*it); + const TopoDS_Shape& baseShape = objBase->Shape.getValue(); + + TopTools_IndexedMapOfShape baseMap; + TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap); + + Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase); + std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); + if (colBase.size() == baseMap.Extent()) { + applyColor(hist[index], colBase, colBool); + setColor = true; + } + else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + colBase.resize(baseMap.Extent(), colBase[0]); + applyColor(hist[index], colBase, colBool); + setColor = true; + } + } + + if (setColor) + this->DiffuseColor.setValues(colBool); + } +} + PROPERTY_SOURCE(PartGui::ViewProviderMultiCommon,PartGui::ViewProviderPart) @@ -112,3 +229,48 @@ QIcon ViewProviderMultiCommon::getIcon(void) const { return Gui::BitmapFactory().pixmap("Part_Common"); } + +void ViewProviderMultiCommon::updateData(const App::Property* prop) +{ + PartGui::ViewProviderPart::updateData(prop); + if (prop->getTypeId() == Part::PropertyShapeHistory::getClassTypeId()) { + const std::vector& hist = static_cast + (prop)->getValues(); + Part::MultiCommon* objBool = dynamic_cast(getObject()); + std::vector sources = objBool->Shapes.getValues(); + if (hist.size() != sources.size()) + return; + + const TopoDS_Shape& boolShape = objBool->Shape.getValue(); + TopTools_IndexedMapOfShape boolMap; + TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); + + std::vector colBool; + colBool.resize(boolMap.Extent(), this->ShapeColor.getValue()); + + bool setColor=false; + int index=0; + for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { + Part::Feature* objBase = dynamic_cast(*it); + const TopoDS_Shape& baseShape = objBase->Shape.getValue(); + + TopTools_IndexedMapOfShape baseMap; + TopExp::MapShapes(baseShape, TopAbs_FACE, baseMap); + + Gui::ViewProvider* vpBase = Gui::Application::Instance->getViewProvider(objBase); + std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); + if (colBase.size() == baseMap.Extent()) { + applyColor(hist[index], colBase, colBool); + setColor = true; + } + else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + colBase.resize(baseMap.Extent(), colBase[0]); + applyColor(hist[index], colBase, colBool); + setColor = true; + } + } + + if (setColor) + this->DiffuseColor.setValues(colBool); + } +} diff --git a/src/Mod/Part/Gui/ViewProviderBoolean.h b/src/Mod/Part/Gui/ViewProviderBoolean.h index 0fb245bb4e..29c5311092 100644 --- a/src/Mod/Part/Gui/ViewProviderBoolean.h +++ b/src/Mod/Part/Gui/ViewProviderBoolean.h @@ -42,6 +42,7 @@ public: /// grouping handling std::vector claimChildren(void) const; QIcon getIcon(void) const; + void updateData(const App::Property*); }; /// ViewProvider for the MultiFuse feature @@ -58,6 +59,7 @@ public: /// grouping handling std::vector claimChildren(void) const; QIcon getIcon(void) const; + void updateData(const App::Property*); }; /// ViewProvider for the MultiFuse feature @@ -74,6 +76,7 @@ public: /// grouping handling std::vector claimChildren(void) const; QIcon getIcon(void) const; + void updateData(const App::Property*); }; diff --git a/src/Mod/Part/Gui/Workbench.cpp b/src/Mod/Part/Gui/Workbench.cpp index bceedc0936..9997750b2f 100644 --- a/src/Mod/Part/Gui/Workbench.cpp +++ b/src/Mod/Part/Gui/Workbench.cpp @@ -58,28 +58,27 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* root = StdWorkbench::setupMenuBar(); Gui::MenuItem* item = root->findItem("&Windows"); + Gui::MenuItem* prim = new Gui::MenuItem; + prim->setCommand("Primitives"); + *prim << "Part_Box" << "Part_Cylinder" << "Part_Sphere" + << "Part_Cone" << "Part_Torus"; + Gui::MenuItem* part = new Gui::MenuItem; root->insertItem(item, part); part->setCommand("&Part"); *part << "Part_Import" << "Part_Export" << "Separator"; - *part << "Part_Primitives" << "Part_ShapeFromMesh" + *part << prim << "Part_Primitives" << "Separator" << "Part_ShapeFromMesh" << "Part_MakeSolid" << "Part_ReverseShape" << "Part_SimpleCopy" << "Part_RefineShape" << "Separator" << "Part_Boolean" << "Part_CrossSections" << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer" - << "Part_RuledSurface" << "Part_Loft" + << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep" << "Part_Builder"; - Gui::MenuItem* partSimple = new Gui::MenuItem; - root->insertItem(item, partSimple); - partSimple->setCommand("&Simple"); - *partSimple << "Part_SimpleCylinder"; - - Gui::MenuItem* solids = new Gui::MenuItem; - root->insertItem(item, solids); - solids->setCommand("&Parametric"); - *solids << "Part_Box" << "Part_Cylinder" << "Part_Sphere" << "Part_Cone" - << "Part_Torus" << "Separator" << "Part_Primitives"; + //Gui::MenuItem* partSimple = new Gui::MenuItem; + //root->insertItem(item, partSimple); + //partSimple->setCommand("&Simple"); + //*partSimple << "Part_SimpleCylinder"; return root; } diff --git a/src/Mod/PartDesign/App/AppPartDesign.cpp b/src/Mod/PartDesign/App/AppPartDesign.cpp index debb60f26b..16620762f6 100644 --- a/src/Mod/PartDesign/App/AppPartDesign.cpp +++ b/src/Mod/PartDesign/App/AppPartDesign.cpp @@ -34,6 +34,7 @@ #include "FeatureFillet.h" #include "FeatureSketchBased.h" #include "FeatureRevolution.h" +#include "FeatureGroove.h" #include "Body.h" #include "FeatureDressUp.h" #include "FeatureChamfer.h" @@ -82,6 +83,7 @@ void PartDesignExport initPartDesign() PartDesign::Pocket ::init(); PartDesign::Fillet ::init(); PartDesign::Revolution ::init(); + PartDesign::Groove ::init(); PartDesign::Chamfer ::init(); PartDesign::Face ::init(); } diff --git a/src/Mod/PartDesign/App/CMakeLists.txt b/src/Mod/PartDesign/App/CMakeLists.txt index 49af698364..837189bb1e 100644 --- a/src/Mod/PartDesign/App/CMakeLists.txt +++ b/src/Mod/PartDesign/App/CMakeLists.txt @@ -50,6 +50,8 @@ SET(FeaturesSketchBased_SRCS FeaturePocket.h FeatureRevolution.cpp FeatureRevolution.h + FeatureGroove.cpp + FeatureGroove.h FeatureAdditive.cpp FeatureAdditive.h FeatureSubtractive.h diff --git a/src/Mod/PartDesign/App/FeatureDressUp.cpp b/src/Mod/PartDesign/App/FeatureDressUp.cpp index 0fb3bb606c..da69c80ed4 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.cpp +++ b/src/Mod/PartDesign/App/FeatureDressUp.cpp @@ -48,4 +48,14 @@ void DressUp::positionByBase(void) this->Placement.setValue(base->Placement.getValue()); } +void DressUp::onChanged(const App::Property* prop) +{ + if (prop == &Base) { + // if attached to a sketch then mark it as read-only + this->Placement.StatusBits.set(2, Base.getValue() != 0); + } + + Feature::onChanged(prop); +} + } diff --git a/src/Mod/PartDesign/App/FeatureDressUp.h b/src/Mod/PartDesign/App/FeatureDressUp.h index f72fc4624e..e439172f25 100644 --- a/src/Mod/PartDesign/App/FeatureDressUp.h +++ b/src/Mod/PartDesign/App/FeatureDressUp.h @@ -41,7 +41,10 @@ public: /// updates the Placement property from the Placement of Base void positionByBase(void); - }; + +protected: + void onChanged(const App::Property* prop); +}; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp new file mode 100644 index 0000000000..1cf17541d2 --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -0,0 +1,208 @@ +/*************************************************************************** + * 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 +# include +# include +# include +#endif + +#include +#include +#include +#include + +#include "FeatureGroove.h" + + +using namespace PartDesign; + +namespace PartDesign { + + +PROPERTY_SOURCE(PartDesign::Groove, PartDesign::SketchBased) + +Groove::Groove() +{ + ADD_PROPERTY_TYPE(Base,(Base::Vector3f(0.0f,0.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Base"); + ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)),"Groove", App::Prop_ReadOnly, "Axis"); + ADD_PROPERTY_TYPE(Angle,(360.0),"Groove", App::Prop_None, "Angle"); + ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Groove",(App::PropertyType)(App::Prop_None),"Reference axis of Groove"); + ADD_PROPERTY_TYPE(Midplane,(0),"Groove", App::Prop_None, "Mid plane"); + ADD_PROPERTY_TYPE(Reversed, (0),"Groove", App::Prop_None, "Reversed"); +} + +short Groove::mustExecute() const +{ + if (Placement.isTouched() || + Sketch.isTouched() || + ReferenceAxis.isTouched() || + Axis.isTouched() || + Base.isTouched() || + Angle.isTouched() || + Midplane.isTouched() || + Reversed.isTouched()) + return 1; + return 0; +} + +App::DocumentObjectExecReturn *Groove::execute(void) +{ + App::DocumentObject* link = Sketch.getValue(); + if (!link) + return new App::DocumentObjectExecReturn("No sketch linked"); + if (!link->getTypeId().isDerivedFrom(Part::Part2DObject::getClassTypeId())) + return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject"); + + Part::Part2DObject* pcSketch=static_cast(link); + + TopoDS_Shape shape = pcSketch->Shape.getShape()._Shape; + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Linked shape object is empty"); + + // this is a workaround for an obscure OCC bug which leads to empty tessellations + // for some faces. Making an explicit copy of the linked shape seems to fix it. + // The error only happens when re-computing the shape. + if (!this->Shape.getValue().IsNull()) { + BRepBuilderAPI_Copy copy(shape); + shape = copy.Shape(); + if (shape.IsNull()) + return new App::DocumentObjectExecReturn("Linked shape object is empty"); + } + + TopExp_Explorer ex; + std::vector wires; + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { + wires.push_back(TopoDS::Wire(ex.Current())); + } + if (wires.empty()) // there can be several wires + return new App::DocumentObjectExecReturn("Linked shape object is not a wire"); + + // get the Sketch plane + Base::Placement SketchPlm = pcSketch->Placement.getValue(); + + // get reference axis + App::DocumentObject *pcReferenceAxis = ReferenceAxis.getValue(); + const std::vector &subReferenceAxis = ReferenceAxis.getSubValues(); + if (pcReferenceAxis && pcReferenceAxis == pcSketch) { + bool hasValidAxis=false; + Base::Axis axis; + if (subReferenceAxis[0] == "V_Axis") { + hasValidAxis = true; + axis = pcSketch->getAxis(Part::Part2DObject::V_Axis); + } + else if (subReferenceAxis[0] == "H_Axis") { + hasValidAxis = true; + axis = pcSketch->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 < pcSketch->getAxisCount()) { + hasValidAxis = true; + axis = pcSketch->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); + } + } + + // get revolve axis + Base::Vector3f b = Base.getValue(); + gp_Pnt pnt(b.x,b.y,b.z); + Base::Vector3f v = Axis.getValue(); + gp_Dir dir(v.x,v.y,v.z); + + // get the support of the Sketch if any + App::DocumentObject* pcSupport = pcSketch->Support.getValue(); + Part::Feature *SupportObject = 0; + if (pcSupport && pcSupport->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + SupportObject = static_cast(pcSupport); + + TopoDS_Shape aFace = makeFace(wires); + if (aFace.IsNull()) + return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); + + // Rotate the face by half the angle to get Groove symmetric to sketch plane + if (Midplane.getValue()) { + gp_Trsf mov; + mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()) * (-1.0) / 2.0); + TopLoc_Location loc(mov); + aFace.Move(loc); + } + + this->positionBySketch(); + TopLoc_Location invObjLoc = this->getLocation().Inverted(); + pnt.Transform(invObjLoc.Transformation()); + dir.Transform(invObjLoc.Transformation()); + + // Reverse angle if selected + double angle = Base::toRadians(Angle.getValue()); + if (Reversed.getValue() && !Midplane.getValue()) + angle *= (-1.0); + + try { + // revolve the face to a solid + BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle); + + if (RevolMaker.IsDone()) { + TopoDS_Shape result = RevolMaker.Shape(); + // if the sketch has a support fuse them to get one result object (PAD!) + if (SupportObject) { + const TopoDS_Shape& support = SupportObject->Shape.getValue(); + if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) { + // Let's call algorithm computing a fuse operation: + BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), result); + // Let's check if the fusion has been successful + if (!mkCut.IsDone()) + throw Base::Exception("Cut out of support failed"); + result = mkCut.Shape(); + } + } + + this->Shape.setValue(result); + } + else + return new App::DocumentObjectExecReturn("Could not revolve the sketch!"); + + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } +} + +} diff --git a/src/Mod/PartDesign/App/FeatureGroove.h b/src/Mod/PartDesign/App/FeatureGroove.h new file mode 100644 index 0000000000..782e728cbc --- /dev/null +++ b/src/Mod/PartDesign/App/FeatureGroove.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * 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 PARTDESIGN_Groove_H +#define PARTDESIGN_Groove_H + +#include +#include "FeatureSketchBased.h" + +namespace PartDesign +{ + +class Groove : public SketchBased +{ + PROPERTY_HEADER(PartDesign::Groove); + +public: + Groove(); + + App::PropertyVector Base; + App::PropertyVector Axis; + App::PropertyAngle Angle; + App::PropertyBool Midplane; + App::PropertyBool Reversed; + + /** if this property is set to a valid link, both Axis and Base properties + * are calculated according to the linked line + */ + App::PropertyLinkSub ReferenceAxis; + + /** @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::ViewProviderGroove"; + } + //@} +}; + +} //namespace PartDesign + + +#endif // PART_Groove_H diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 1a12c45565..8335668aeb 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -23,14 +23,12 @@ #include "PreCompiled.h" #ifndef _PreComp_ -//# include -//# include # include +# include # include # include # include # include -//# include # include # include # include @@ -39,23 +37,32 @@ # include # include # include +# include +# include #endif #include #include +#include #include "FeaturePad.h" using namespace PartDesign; +const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL}; + PROPERTY_SOURCE(PartDesign::Pad, PartDesign::Additive) Pad::Pad() { + ADD_PROPERTY(Type,((long)0)); + Type.setEnums(TypeEnums); ADD_PROPERTY(Length,(100.0)); ADD_PROPERTY(Reversed,(0)); - ADD_PROPERTY(MirroredExtent,(0)); + ADD_PROPERTY(Midplane,(0)); + ADD_PROPERTY(Length2,(100.0)); + ADD_PROPERTY(FaceName,("")); } short Pad::mustExecute() const @@ -63,8 +70,10 @@ short Pad::mustExecute() const if (Placement.isTouched() || Sketch.isTouched() || Length.isTouched() || - MirroredExtent.isTouched() || - Reversed.isTouched()) + Midplane.isTouched() || + Reversed.isTouched() || + Length2.isTouched() || + FaceName.isTouched()) return 1; return 0; } @@ -74,6 +83,10 @@ App::DocumentObjectExecReturn *Pad::execute(void) double L = Length.getValue(); if (L < Precision::Confusion()) return new App::DocumentObjectExecReturn("Length of pad too small"); + double L2 = Length2.getValue(); + if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion())) + return new App::DocumentObjectExecReturn("Second length of pad too small"); + App::DocumentObject* link = Sketch.getValue(); if (!link) return new App::DocumentObjectExecReturn("No sketch linked"); @@ -103,10 +116,8 @@ App::DocumentObjectExecReturn *Pad::execute(void) // get the Sketch plane Base::Placement SketchPos = static_cast(link)->Placement.getValue(); Base::Rotation SketchOrientation = SketchPos.getRotation(); - Base::Vector3d SketchOrientationVector(0,0,1); - if (Reversed.getValue()) // negative direction - SketchOrientationVector *= -1; - SketchOrientation.multVec(SketchOrientationVector,SketchOrientationVector); + Base::Vector3d SketchVector(0,0,1); + SketchOrientation.multVec(SketchVector,SketchVector); // get the support of the Sketch if any App::DocumentObject* SupportLink = static_cast(link)->Support.getValue(); @@ -118,27 +129,159 @@ App::DocumentObjectExecReturn *Pad::execute(void) if (aFace.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); - // lengthen the vector - SketchOrientationVector *= L; - this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { // extrude the face to a solid - gp_Vec vec(SketchOrientationVector.x,SketchOrientationVector.y,SketchOrientationVector.z); - vec.Transform(invObjLoc.Transformation()); - BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); - if (PrismMaker.IsDone()) { - // if the sketch has a support fuse them to get one result object (PAD!) - if (SupportObject) { - // At this point the prism can be a compound - TopoDS_Shape result = PrismMaker.Shape(); - // set the additive shape property for later usage in e.g. pattern - this->AddShape.setValue(result); + TopoDS_Shape prism; + bool isSolid = false; // support is a solid? + bool isSolidChecked = false; // not checked yet + + if ((std::string(Type.getValueAsString()) == "UpToLast") || + (std::string(Type.getValueAsString()) == "UpToFirst") || + (std::string(Type.getValueAsString()) == "UpToFace")) + { + TopoDS_Face upToFace; + gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); + + if ((std::string(Type.getValueAsString()) == "UpToLast") || + (std::string(Type.getValueAsString()) == "UpToFirst")) + { + // Check for valid support object + if (!SupportObject) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No support in Sketch!"); const TopoDS_Shape& support = SupportObject->Shape.getValue(); - bool isSolid = false; + if (support.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is invalid"); + TopExp_Explorer xp (support, TopAbs_SOLID); + if (!xp.More()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is not a solid"); + isSolid = true; + isSolidChecked = true; + + TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit + std::vector cfaces = Part::findAllFacesCutBy(support, origFace, dir); + if (cfaces.empty()) + return new App::DocumentObjectExecReturn("No faces found in this direction"); + + // Find nearest/furthest face + std::vector::const_iterator it, it_near, it_far; + it_near = it_far = cfaces.begin(); + for (it = cfaces.begin(); it != cfaces.end(); it++) + if (it->distsq > it_far->distsq) + it_far = it; + else if (it->distsq < it_near->distsq) + it_near = it; + upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face); + } else { + if (FaceName.isEmpty()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected"); + + // Get active object, this is the object that the user referenced when he clicked on the face! + App::DocumentObject* baseLink = this->getDocument()->getActiveObject(); + + if (!baseLink) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked"); + if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object"); + Part::Feature *base = static_cast(baseLink); + const Part::TopoShape& baseShape = base->Shape.getShape(); + if (baseShape._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape"); + + TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue()); + if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE) + upToFace = TopoDS::Face(sub); + else + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face"); + + // Validate face + // TODO: This would also exclude faces that are valid but not cut by the line + // So for now we trust to the intelligence of the user when picking the face + /*std::vector cfaces = findAllFacesCutBy(upToFace, origFace, dir); + if (cfaces.empty()) + return new App::DocumentObjectExecReturn("No faces found in this direction");*/ + } + + // Create semi-infinite prism from sketch in direction dir + // Hack, because the two lines commented out below do NOT work!!! + SketchVector *= 1E6; + gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); + vec.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // very long, but finite prism + //dir.Transform(invObjLoc.Transformation()); + //BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1); + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!"); + + // Cut off the prism at the face we found + // Grab any point from the sketch + TopExp_Explorer exp; + exp.Init(aFace, TopAbs_VERTEX); + if (!exp.More()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?"); + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current())); + + // Create a halfspace from the face, extending in direction of sketch plane + BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt); + if (!mkHalfSpace.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed"); + + // Find common material between halfspace and prism + BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc)); + if (!mkCommon.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed"); + + prism = this->getSolid(mkCommon.Shape()); + if (prism.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid"); + } else if ((std::string(Type.getValueAsString()) == "Length") || + (std::string(Type.getValueAsString()) == "TwoLengths")) { + if (std::string(Type.getValueAsString()) == "Length") { + if (Midplane.getValue()) { + // Move face by half the extrusion distance to get pad symmetric to sketch plane + gp_Trsf mov; + mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L/2.0); + TopLoc_Location loc(mov); + aFace.Move(loc); + } else if (Reversed.getValue()) { // negative direction + SketchVector *= -1.0; + } + + // lengthen the vector + SketchVector *= L; + } else { + // Move face by the second length to get pad extending to both sides of sketch plane + gp_Trsf mov; + mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L2); + TopLoc_Location loc(mov); + aFace.Move(loc); + + // lengthen the vector + SketchVector *= (L + L2); + } + + // create the extrusion + gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); + vec.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); + prism = PrismMaker.Shape(); + } else { + return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pad feature"); + } + + // if the sketch has a support fuse them to get one result object (PAD!) + if (SupportObject) { + // set the additive shape property for later usage in e.g. pattern + this->AddShape.setValue(prism); + + const TopoDS_Shape& support = SupportObject->Shape.getValue(); + + if (!isSolidChecked) { // we haven't checked for solid, yet if (!support.IsNull()) { TopExp_Explorer xp; xp.Init(support,TopAbs_SOLID); @@ -147,32 +290,30 @@ App::DocumentObjectExecReturn *Pad::execute(void) break; } } - if (isSolid) { - // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result); - // Let's check if the fusion has been successful - if (!mkFuse.IsDone()) - return new App::DocumentObjectExecReturn("Fusion with support failed"); - result = mkFuse.Shape(); - // we have to get the solids (fuse create seldomly compounds) - TopoDS_Shape solRes = this->getSolid(result); - // lets check if the result is a solid - if (solRes.IsNull()) - return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); - this->Shape.setValue(solRes); - } - else + + if (!isSolid) return new App::DocumentObjectExecReturn("Support is not a solid"); } - else { - TopoDS_Shape result = this->getSolid(PrismMaker.Shape()); - // set the additive shape property for later usage in e.g. pattern - this->AddShape.setValue(result); - this->Shape.setValue(result); - } + + // Let's call algorithm computing a fuse operation: + BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), prism); + // Let's check if the fusion has been successful + if (!mkFuse.IsDone()) + return new App::DocumentObjectExecReturn("Fusion with support failed"); + TopoDS_Shape result = mkFuse.Shape(); + // we have to get the solids (fuse create seldomly compounds) + TopoDS_Shape solRes = this->getSolid(result); + // lets check if the result is a solid + if (solRes.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); + this->Shape.setValue(solRes); + } + else { + TopoDS_Shape result = this->getSolid(prism); + // set the additive shape property for later usage in e.g. pattern + this->AddShape.setValue(result); + this->Shape.setValue(result); } - else - return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); return App::DocumentObject::StdReturn; } diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h index c758c94f7e..91bdeff59f 100644 --- a/src/Mod/PartDesign/App/FeaturePad.h +++ b/src/Mod/PartDesign/App/FeaturePad.h @@ -38,10 +38,13 @@ class Pad : public Additive public: Pad(); - App::PropertyLength Length; + App::PropertyEnumeration Type; + App::PropertyLength Length; //App::PropertyEnumeration Side; - App::PropertyBool Reversed; - App::PropertyBool MirroredExtent; + App::PropertyBool Reversed; + App::PropertyBool Midplane; + App::PropertyLength Length2; + App::PropertyString FaceName; /** @name methods override feature */ //@{ @@ -54,7 +57,8 @@ public: } //@} private: - static const char* SideEnums[]; + static const char* TypeEnums[]; + //static const char* SideEnums[]; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index c7f4fa8ace..a0ef1cdd4b 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -27,6 +27,7 @@ # include # include # include +# include # include # include # include @@ -40,17 +41,20 @@ # include # include # include +# include +# include #endif #include #include +#include #include "FeaturePocket.h" using namespace PartDesign; -const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst",NULL}; +const char* Pocket::TypeEnums[]= {"Length","UpToLast","UpToFirst","ThroughAll","UpToFace",NULL}; PROPERTY_SOURCE(PartDesign::Pocket, PartDesign::SketchBased) @@ -59,13 +63,15 @@ Pocket::Pocket() ADD_PROPERTY(Type,((long)0)); Type.setEnums(TypeEnums); ADD_PROPERTY(Length,(100.0)); + ADD_PROPERTY(FaceName,("")); } short Pocket::mustExecute() const { if (Placement.isTouched() || Sketch.isTouched() || - Length.isTouched()) + Length.isTouched() || + FaceName.isTouched()) return 1; return 0; } @@ -113,13 +119,22 @@ App::DocumentObjectExecReturn *Pocket::execute(void) if (!SupportObject) return new App::DocumentObjectExecReturn("No support in Sketch!"); + const TopoDS_Shape& support = SupportObject->Shape.getValue(); + if (support.IsNull()) + return new App::DocumentObjectExecReturn("Support shape is invalid"); + TopExp_Explorer xp (support, TopAbs_SOLID); + if (!xp.More()) + return new App::DocumentObjectExecReturn("Support shape is not a solid"); + TopoDS_Shape aFace = makeFace(wires); if (aFace.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); // This is a trick to avoid problems with the cut operation. Sometimes a cut doesn't - // work as expected if faces or coincident. Thus, we move the face in normal direction + // work as expected if faces are coincident. Thus, we move the face in normal direction // but make it longer by one unit in the opposite direction. + // TODO: Isn't one unit (one millimeter) a lot, assuming someone models a really tiny solid? + // What about using 2 * Precision::Confusion() ? gp_Trsf mov; mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z)); TopLoc_Location loc(mov); @@ -134,39 +149,133 @@ App::DocumentObjectExecReturn *Pocket::execute(void) this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); - // extrude the face to a solid - gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); - vec.Transform(invObjLoc.Transformation()); - BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); - if (PrismMaker.IsDone()) { - // if the sketch has a support fuse them to get one result object (PAD!) - if (SupportObject) { - const TopoDS_Shape& support = SupportObject->Shape.getValue(); - if (support.IsNull()) - return new App::DocumentObjectExecReturn("Support shape is invalid"); - TopExp_Explorer xp (support, TopAbs_SOLID); - if (!xp.More()) - return new App::DocumentObjectExecReturn("Support shape is not a solid"); - // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), PrismMaker.Shape()); - // Let's check if the fusion has been successful - if (!mkCut.IsDone()) - return new App::DocumentObjectExecReturn("Cut with support failed"); + try { + // extrude the face to a solid + TopoDS_Shape prism; - // we have to get the solids (fuse create seldomly compounds) - TopoDS_Shape solRes = this->getSolid(mkCut.Shape()); - if (solRes.IsNull()) - return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); + if ((std::string(Type.getValueAsString()) == "UpToLast") || + (std::string(Type.getValueAsString()) == "UpToFirst") || + (std::string(Type.getValueAsString()) == "UpToFace")) + { + TopoDS_Face upToFace; + gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); - this->Shape.setValue(solRes); - } - else { - return new App::DocumentObjectExecReturn("Cannot create a tool out of sketch with no support"); + if ((std::string(Type.getValueAsString()) == "UpToLast") || + (std::string(Type.getValueAsString()) == "UpToFirst")) + { + TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit + std::vector cfaces = Part::findAllFacesCutBy(support, origFace, dir); + if (cfaces.empty()) + return new App::DocumentObjectExecReturn("No faces found in this direction"); + + // Find nearest/furthest face + std::vector::const_iterator it, it_near, it_far; + it_near = it_far = cfaces.begin(); + for (it = cfaces.begin(); it != cfaces.end(); it++) + if (it->distsq > it_far->distsq) + it_far = it; + else if (it->distsq < it_near->distsq) + it_near = it; + upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face); + } else { + if (FaceName.getValue() == "") + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected"); + + // Get active object, this is the object that the user referenced when he clicked on the face! + App::DocumentObject* baseLink = this->getDocument()->getActiveObject(); + + if (!baseLink) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked"); + if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object"); + Part::Feature *base = static_cast(baseLink); + const Part::TopoShape& baseShape = base->Shape.getShape(); + if (baseShape._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape"); + + TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue()); + if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE) + upToFace = TopoDS::Face(sub); + else + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face"); + + // Find the origin of this face (i.e. a vertex or a edge in a sketch) + TopoDS_Shape origin = base->findOriginOf(sub); + + // Validate face + // TODO: This would also exclude faces that are valid but not cut by the line + // So for now we trust to the intelligence of the user when picking the face + /*std::vector cfaces = findAllFacesCutBy(upToFace, origFace, dir); + if (cfaces.empty()) + return new App::DocumentObjectExecReturn("No faces found in this direction");*/ + } + + // Create semi-infinite prism from sketch in direction dir + dir.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1); + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!"); + + // Cut off the prism at the face we found + // Grab any point from the sketch + TopExp_Explorer exp; + exp.Init(aFace, TopAbs_VERTEX); + if (!exp.More()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?"); + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current())); + + // Create a halfspace from the face, extending in direction of sketch plane + BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt); + if (!mkHalfSpace.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed"); + + // Find common material between halfspace and prism + BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc)); + if (!mkCommon.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed"); + + prism = this->getSolid(mkCommon.Shape()); + if (prism.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid"); + } else if (std::string(Type.getValueAsString()) == "ThroughAll") { + gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); + dir.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,1,0,1); // infinite prism (in both directions!) + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); + prism = PrismMaker.Shape(); + } else if (std::string(Type.getValueAsString()) == "Length") { + gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); + vec.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); + prism = PrismMaker.Shape(); + } else { + return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pocket feature"); } + + // TODO: Set the subtractive shape property for later usage in e.g. pattern + //this->SubShape.setValue(prism); // This crashes with "Illegal storage access". Why? + + // Cut out the pocket + BRepAlgoAPI_Cut mkCut(support.Moved(invObjLoc), prism); + + // Let's check if the fusion has been successful + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Cut with support failed"); + + // we have to get the solids (fuse sometimes creates compounds) + TopoDS_Shape solRes = this->getSolid(mkCut.Shape()); + if (solRes.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); + + this->Shape.setValue(solRes); + + return App::DocumentObject::StdReturn; + } catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); } - else - return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); - - return App::DocumentObject::StdReturn; } diff --git a/src/Mod/PartDesign/App/FeaturePocket.h b/src/Mod/PartDesign/App/FeaturePocket.h index 7a7d579628..b9b47aa72d 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.h +++ b/src/Mod/PartDesign/App/FeaturePocket.h @@ -39,6 +39,7 @@ public: App::PropertyEnumeration Type; App::PropertyLength Length; + App::PropertyString FaceName; /** @name methods override feature */ //@{ diff --git a/src/Mod/PartDesign/App/FeatureRevolution.cpp b/src/Mod/PartDesign/App/FeatureRevolution.cpp index 317aa52d19..a31bebf439 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.cpp +++ b/src/Mod/PartDesign/App/FeatureRevolution.cpp @@ -52,10 +52,12 @@ PROPERTY_SOURCE(PartDesign::Revolution, PartDesign::SketchBased) Revolution::Revolution() { - ADD_PROPERTY(Base,(Base::Vector3f(0.0f,0.0f,0.0f))); - ADD_PROPERTY(Axis,(Base::Vector3f(0.0f,1.0f,0.0f))); - ADD_PROPERTY(Angle,(360.0)); - ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Revolution",(App::PropertyType)(App::Prop_None),"Reference axis of revolution"); + ADD_PROPERTY_TYPE(Base,(Base::Vector3f(0.0f,0.0f,0.0f)),"Revolution", App::Prop_ReadOnly, "Base"); + ADD_PROPERTY_TYPE(Axis,(Base::Vector3f(0.0f,1.0f,0.0f)),"Revolution", App::Prop_ReadOnly, "Axis"); + ADD_PROPERTY_TYPE(Angle,(360.0),"Revolution", App::Prop_None, "Angle"); + ADD_PROPERTY_TYPE(ReferenceAxis,(0),"Revolution",(App::Prop_None),"Reference axis of revolution"); + ADD_PROPERTY_TYPE(Midplane,(0),"Revolution", App::Prop_None, "Mid plane"); + ADD_PROPERTY_TYPE(Reversed, (0),"Revolution", App::Prop_None, "Reversed"); } short Revolution::mustExecute() const @@ -65,7 +67,9 @@ short Revolution::mustExecute() const ReferenceAxis.isTouched() || Axis.isTouched() || Base.isTouched() || - Angle.isTouched()) + Angle.isTouched() || + Midplane.isTouched() || + Reversed.isTouched()) return 1; return 0; } @@ -151,35 +155,54 @@ App::DocumentObjectExecReturn *Revolution::execute(void) if (aFace.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); + // Rotate the face by half the angle to get revolution symmetric to sketch plane + if (Midplane.getValue()) { + gp_Trsf mov; + mov.SetRotation(gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue()) * (-1.0) / 2.0); + TopLoc_Location loc(mov); + aFace.Move(loc); + } + this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); pnt.Transform(invObjLoc.Transformation()); dir.Transform(invObjLoc.Transformation()); - // revolve the face to a solid - BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), Base::toRadians(Angle.getValue())); + // Reverse angle if selected + double angle = Base::toRadians(Angle.getValue()); + if (Reversed.getValue() && !Midplane.getValue()) + angle *= (-1.0); - if (RevolMaker.IsDone()) { - TopoDS_Shape result = RevolMaker.Shape(); - // if the sketch has a support fuse them to get one result object (PAD!) - if (SupportObject) { - const TopoDS_Shape& support = SupportObject->Shape.getValue(); - if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) { - // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result); - // Let's check if the fusion has been successful - if (!mkFuse.IsDone()) - throw Base::Exception("Fusion with support failed"); - result = mkFuse.Shape(); + try { + // revolve the face to a solid + BRepPrimAPI_MakeRevol RevolMaker(aFace.Moved(invObjLoc), gp_Ax1(pnt, dir), angle); + + if (RevolMaker.IsDone()) { + TopoDS_Shape result = RevolMaker.Shape(); + // if the sketch has a support fuse them to get one result object (PAD!) + if (SupportObject) { + const TopoDS_Shape& support = SupportObject->Shape.getValue(); + if (!support.IsNull() && support.ShapeType() == TopAbs_SOLID) { + // Let's call algorithm computing a fuse operation: + BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result); + // Let's check if the fusion has been successful + if (!mkFuse.IsDone()) + throw Base::Exception("Fusion with support failed"); + result = mkFuse.Shape(); + } } + + this->Shape.setValue(result); } + else + return new App::DocumentObjectExecReturn("Could not revolve the sketch!"); - this->Shape.setValue(result); + return App::DocumentObject::StdReturn; + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); } - else - return new App::DocumentObjectExecReturn("Could not revolve the sketch!"); - - return App::DocumentObject::StdReturn; } } diff --git a/src/Mod/PartDesign/App/FeatureRevolution.h b/src/Mod/PartDesign/App/FeatureRevolution.h index 4d6677d545..ed11adc068 100644 --- a/src/Mod/PartDesign/App/FeatureRevolution.h +++ b/src/Mod/PartDesign/App/FeatureRevolution.h @@ -39,7 +39,9 @@ public: App::PropertyVector Base; App::PropertyVector Axis; - App::PropertyAngle Angle; + App::PropertyAngle Angle; + App::PropertyBool Midplane; + App::PropertyBool Reversed; /** if this property is set to a valid link, both Axis and Base properties * are calculated according to the linked line diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index 286e518156..ce6323632d 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -89,6 +89,16 @@ void SketchBased::positionBySketch(void) } } +void SketchBased::onChanged(const App::Property* prop) +{ + if (prop == &Sketch) { + // if attached to a sketch then mark it as read-only + this->Placement.StatusBits.set(2, Sketch.getValue() != 0); + } + + Feature::onChanged(prop); +} + bool SketchBased::isInside(const TopoDS_Wire& wire1, const TopoDS_Wire& wire2) const { Bnd_Box box1; diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 1255f6f7bf..8fab209394 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -51,6 +51,7 @@ public: 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 diff --git a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp index d86285fbee..32e7187786 100644 --- a/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp +++ b/src/Mod/PartDesign/Gui/AppPartDesignGui.cpp @@ -37,6 +37,7 @@ #include "ViewProviderChamfer.h" #include "ViewProviderFillet.h" #include "ViewProviderRevolution.h" +#include "ViewProviderGroove.h" //#include "resources/qrc_PartDesign.cpp" @@ -83,6 +84,7 @@ void PartDesignGuiExport initPartDesignGui() PartDesignGui::ViewProviderPocket ::init(); PartDesignGui::ViewProviderPad ::init(); PartDesignGui::ViewProviderRevolution::init(); + PartDesignGui::ViewProviderGroove ::init(); PartDesignGui::ViewProviderChamfer ::init(); PartDesignGui::ViewProviderFillet ::init(); diff --git a/src/Mod/PartDesign/Gui/CMakeLists.txt b/src/Mod/PartDesign/Gui/CMakeLists.txt index 8f6e265565..0aa1cb9189 100644 --- a/src/Mod/PartDesign/Gui/CMakeLists.txt +++ b/src/Mod/PartDesign/Gui/CMakeLists.txt @@ -32,6 +32,7 @@ set(PartDesignGui_MOC_HDRS TaskFilletParameters.h TaskHoleParameters.h TaskRevolutionParameters.h + TaskGrooveParameters.h ) fc_wrap_cpp(PartDesignGui_MOC_SRCS ${PartDesignGui_MOC_HDRS}) SOURCE_GROUP("Moc" FILES ${PartDesignGui_MOC_SRCS}) @@ -46,6 +47,7 @@ set(PartDesignGui_UIC_SRCS TaskFilletParameters.ui TaskHoleParameters.ui TaskRevolutionParameters.ui + TaskGrooveParameters.ui ) qt4_wrap_ui(PartDesignGui_UIC_HDRS ${PartDesignGui_UIC_SRCS}) @@ -64,6 +66,8 @@ SET(PartDesignGuiViewProvider_SRCS ViewProviderFillet.h ViewProviderRevolution.cpp ViewProviderRevolution.h + ViewProviderGroove.cpp + ViewProviderGroove.h ViewProviderPatternRectangular.cpp ViewProviderPatternRectangular.h ) @@ -88,6 +92,9 @@ SET(PartDesignGuiTaskDlgs_SRCS TaskRevolutionParameters.ui TaskRevolutionParameters.cpp TaskRevolutionParameters.h + TaskGrooveParameters.ui + TaskGrooveParameters.cpp + TaskGrooveParameters.h TaskHoleParameters.ui TaskHoleParameters.cpp TaskHoleParameters.h diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index ddf3240840..335d6d5dd6 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -20,24 +20,36 @@ * * ***************************************************************************/ - -#include "PreCompiled.h" -#ifndef _PreComp_ -# include -# include -#endif - -#include -#include -#include -#include -#include -#include - -#include - - -using namespace std; + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +using namespace std; //=========================================================================== // Part_Pad @@ -315,6 +327,82 @@ 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 = sToolTipText; + sStatusTip = sToolTipText; + sPixmap = "PartDesign_Groove"; +} + +void CmdPartDesignGroove::activated(int iMsg) +{ + unsigned int n = getSelection().countObjectsOfType(Part::Part2DObject::getClassTypeId()); + if (n != 1) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select a sketch or 2D object.")); + return; + } + + std::string FeatName = getUniqueObjectName("Groove"); + + std::vector Sel = getSelection().getObjectsOfType(Part::Part2DObject::getClassTypeId()); + Part::Part2DObject* sketch = static_cast(Sel.front()); + const TopoDS_Shape& shape = sketch->Shape.getValue(); + if (shape.IsNull()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The shape of the selected object is empty.")); + return; + } + + // count free wires + int ctWires=0; + TopExp_Explorer ex; + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { + ctWires++; + } + if (ctWires == 0) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The shape of the selected object is not a wire.")); + return; + } + + App::DocumentObject* support = sketch->Support.getValue(); + + 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()); + 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 //=========================================================================== @@ -331,35 +419,130 @@ CmdPartDesignFillet::CmdPartDesignFillet() sStatusTip = sToolTipText; sPixmap = "Part_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(); - 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()); - - 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) +{ + 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()); + + 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()); + + 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) { @@ -382,35 +565,131 @@ CmdPartDesignChamfer::CmdPartDesignChamfer() sStatusTip = sToolTipText; sPixmap = "Part_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(); - 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()); - - 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 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()); + + 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()); + + 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) { @@ -425,6 +704,7 @@ void CreatePartDesignCommands(void) rcCmdMgr.addCommand(new CmdPartDesignPad()); rcCmdMgr.addCommand(new CmdPartDesignPocket()); rcCmdMgr.addCommand(new CmdPartDesignRevolution()); + rcCmdMgr.addCommand(new CmdPartDesignGroove()); rcCmdMgr.addCommand(new CmdPartDesignFillet()); //rcCmdMgr.addCommand(new CmdPartDesignNewSketch()); rcCmdMgr.addCommand(new CmdPartDesignChamfer()); diff --git a/src/Mod/PartDesign/Gui/Resources/Makefile.am b/src/Mod/PartDesign/Gui/Resources/Makefile.am index ab021d8df3..79bee06393 100644 --- a/src/Mod/PartDesign/Gui/Resources/Makefile.am +++ b/src/Mod/PartDesign/Gui/Resources/Makefile.am @@ -25,6 +25,8 @@ EXTRA_DIST = \ translations/PartDesign_nl.ts \ translations/PartDesign_no.qm \ translations/PartDesign_no.ts \ + translations/PartDesign_pl.qm \ + translations/PartDesign_pl.ts \ translations/PartDesign_pt.qm \ translations/PartDesign_pt.ts \ translations/PartDesign_ru.qm \ @@ -35,6 +37,7 @@ EXTRA_DIST = \ translations/PartDesign_uk.ts \ translations/PartDesign_zh.qm \ translations/PartDesign_zh.ts \ + icons/PartDesign_Groove.svg \ icons/PartDesign_Pad.svg \ icons/PartDesign_Pocket.svg \ icons/PartDesign_Revolution.svg \ diff --git a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc index 457ff17198..37804e4039 100644 --- a/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc +++ b/src/Mod/PartDesign/Gui/Resources/PartDesign.qrc @@ -1,5 +1,6 @@ + icons/PartDesign_Groove.svg icons/PartDesign_Pad.svg icons/PartDesign_Pocket.svg icons/PartDesign_Revolution.svg @@ -12,6 +13,7 @@ translations/PartDesign_it.qm translations/PartDesign_nl.qm translations/PartDesign_no.qm + translations/PartDesign_pl.qm translations/PartDesign_pt.qm translations/PartDesign_ru.qm translations/PartDesign_se.qm diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg new file mode 100644 index 0000000000..2c1ca60aa8 --- /dev/null +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Groove.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp new file mode 100644 index 0000000000..79b0278fe8 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.cpp @@ -0,0 +1,287 @@ +/*************************************************************************** + * 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_TaskGrooveParameters.h" +#include "TaskGrooveParameters.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace PartDesignGui; +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) +{ + // 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->doubleSpinBox, 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))); + + this->groupLayout()->addWidget(proxy); + + PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + double l = pcGroove->Angle.getValue(); + bool mirrored = pcGroove->Midplane.getValue(); + bool reversed = pcGroove->Reversed.getValue(); + + ui->doubleSpinBox->setValue(l); + + 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::fromAscii("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::fromAscii("Undefined")); + pos = ui->axis->count()-1; + } + + ui->axis->setCurrentIndex(pos); + + ui->checkBoxMidplane->setChecked(mirrored); + ui->checkBoxReversed->setChecked(reversed); + + setFocus (); +} + +void TaskGrooveParameters::onAngleChanged(double len) +{ + PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + pcGroove->Angle.setValue((float)len); + pcGroove->getDocument()->recomputeFeature(pcGroove); +} + +void TaskGrooveParameters::onAxisChanged(int num) +{ + PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + Sketcher::SketchObject *pcSketch = static_cast(pcGroove->Sketch.getValue()); + if (pcSketch) { + int maxcount = pcSketch->getAxisCount()+2; + if (num == 0) + pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"V_Axis")); + else if (num == 1) + pcGroove->ReferenceAxis.setValue(pcSketch, std::vector(1,"H_Axis")); + 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); + } + pcGroove->getDocument()->recomputeFeature(pcGroove); +} + +void TaskGrooveParameters::onMidplane(bool on) +{ + PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + pcGroove->Midplane.setValue(on); + pcGroove->getDocument()->recomputeFeature(pcGroove); +} + +void TaskGrooveParameters::onReversed(bool on) +{ + PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + pcGroove->Reversed.setValue(on); + pcGroove->getDocument()->recomputeFeature(pcGroove); +} + + +double TaskGrooveParameters::getAngle(void) const +{ + return ui->doubleSpinBox->value(); +} + +QString TaskGrooveParameters::getReferenceAxis(void) const +{ + // get the support and Sketch + PartDesign::Groove* pcGroove = static_cast(GrooveView->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); + } + } + else + buf = QString::fromUtf8("''"); + + return buf; +} + +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); + } +} + +//************************************************************************** +//************************************************************************** +// TaskDialog +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +TaskDlgGrooveParameters::TaskDlgGrooveParameters(ViewProviderGroove *GrooveView) + : TaskDialog(),GrooveView(GrooveView) +{ + assert(GrooveView); + parameter = new TaskGrooveParameters(GrooveView); + + Content.push_back(parameter); +} + +TaskDlgGrooveParameters::~TaskDlgGrooveParameters() +{ + +} + +//==== calls from the TaskView =============================================================== + + +void TaskDlgGrooveParameters::open() +{ + +} + +void TaskDlgGrooveParameters::clicked(int) +{ + +} + +bool TaskDlgGrooveParameters::accept() +{ + std::string name = GrooveView->getObject()->getNameInDocument(); + + //Gui::Command::openCommand("Groove changed"); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle()); + std::string axis = parameter->getReferenceAxis().toStdString(); + 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(),parameter->getMidplane()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); + Gui::Command::commitCommand(); + + return true; +} + +bool TaskDlgGrooveParameters::reject() +{ + // get the support and Sketch + PartDesign::Groove* pcGroove = static_cast(GrooveView->getObject()); + Sketcher::SketchObject *pcSketch; + App::DocumentObject *pcSupport; + 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(); + 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; +} + + + +#include "moc_TaskGrooveParameters.cpp" diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.h b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h new file mode 100644 index 0000000000..8b82f01872 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * 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_TaskGrooveParameters_H +#define GUI_TASKVIEW_TaskGrooveParameters_H + +#include +#include +#include + +#include "ViewProviderGroove.h" + +class Ui_TaskGrooveParameters; + +namespace App { +class Property; +} + +namespace Gui { +class ViewProvider; +} + +namespace PartDesignGui { + + + +class TaskGrooveParameters : public Gui::TaskView::TaskBox +{ + Q_OBJECT + +public: + TaskGrooveParameters(ViewProviderGroove *GrooveView,QWidget *parent = 0); + ~TaskGrooveParameters(); + + QString getReferenceAxis(void) const; + double getAngle(void) const; + bool getMidplane(void) const; + bool getReversed(void) const; + +private Q_SLOTS: + void onAngleChanged(double); + void onAxisChanged(int); + void onMidplane(bool); + void onReversed(bool); + +protected: + void changeEvent(QEvent *e); + +private: + +private: + QWidget* proxy; + Ui_TaskGrooveParameters* ui; + ViewProviderGroove *GrooveView; +}; + +/// simulation dialog for the TaskView +class TaskDlgGrooveParameters : public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDlgGrooveParameters(ViewProviderGroove *GrooveView); + ~TaskDlgGrooveParameters(); + + ViewProviderGroove* getGrooveView() const + { return GrooveView; } + + +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: + ViewProviderGroove *GrooveView; + + TaskGrooveParameters *parameter; +}; + +} //namespace PartDesignGui + +#endif // GUI_TASKVIEW_TASKAPPERANCE_H diff --git a/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui b/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui new file mode 100644 index 0000000000..d7a68d6c20 --- /dev/null +++ b/src/Mod/PartDesign/Gui/TaskGrooveParameters.ui @@ -0,0 +1,93 @@ + + + PartDesignGui::TaskGrooveParameters + + + + 0 + 0 + 278 + 158 + + + + Form + + + + + + + + Axis: + + + + + + + + Vertical sketch axis + + + + + Horizontal sketch axis + + + + + + + + + + + + Angle: + + + + + + + 1 + + + 0.000000000000000 + + + 360.000000000000000 + + + 10.000000000000000 + + + 360.000000000000000 + + + + + + + + + true + + + Symmetric to plane + + + + + + + Reversed + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 8a902b2b96..d7c37b7b3b 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -59,30 +59,106 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,QWidget *parent) connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onLengthChanged(double))); - connect(ui->checkBoxMirrored, SIGNAL(toggled(bool)), - this, SLOT(onMirrored(bool))); + connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), + this, SLOT(onMidplane(bool))); connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), this, SLOT(onReversed(bool))); + connect(ui->doubleSpinBox2, SIGNAL(valueChanged(double)), + this, SLOT(onLength2Changed(double))); + connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), + this, SLOT(onModeChanged(int))); + connect(ui->lineFaceName, SIGNAL(textEdited(QString)), + this, SLOT(onFaceName(QString))); this->groupLayout()->addWidget(proxy); + // Get the feature data PartDesign::Pad* pcPad = static_cast(PadView->getObject()); double l = pcPad->Length.getValue(); - bool mirrored = pcPad->MirroredExtent.getValue(); + bool midplane = pcPad->Midplane.getValue(); bool reversed = pcPad->Reversed.getValue(); + double l2 = pcPad->Length2.getValue(); + int index = pcPad->Type.getValue(); // must extract value here, clear() kills it! + const char* upToFace = pcPad->FaceName.getValue(); + // Fill data into dialog elements ui->doubleSpinBox->setMinimum(0); + ui->doubleSpinBox->setMaximum(INT_MAX); ui->doubleSpinBox->setValue(l); - ui->doubleSpinBox->selectAll(); - ui->checkBoxMirrored->setChecked(mirrored); + ui->doubleSpinBox2->setMinimum(0); + ui->doubleSpinBox2->setMaximum(INT_MAX); + ui->doubleSpinBox2->setValue(l2); + ui->checkBoxMidplane->setChecked(midplane); // According to bug #0000521 the reversed option // shouldn't be de-activated if the pad has a support face ui->checkBoxReversed->setChecked(reversed); + ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace)); + ui->changeMode->clear(); + ui->changeMode->insertItem(0, tr("Dimension")); + ui->changeMode->insertItem(1, tr("To last")); + ui->changeMode->insertItem(2, tr("To first")); + ui->changeMode->insertItem(3, tr("Up to face")); + ui->changeMode->insertItem(4, tr("Two dimensions")); + ui->changeMode->setCurrentIndex(index); - // 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. - QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + // activate and de-activate dialog elements as appropriate + updateUI(index); +} + +void TaskPadParameters::updateUI(int index) +{ + if (index == 0) { // dimension + ui->doubleSpinBox->setEnabled(true); + ui->doubleSpinBox->selectAll(); + // 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. + QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + ui->checkBoxMidplane->setEnabled(true); + ui->checkBoxReversed->setEnabled(true); + ui->doubleSpinBox2->setEnabled(false); + ui->lineFaceName->setEnabled(false); + } else if ((index == 1) || (index == 2)) { // up to first/last + ui->doubleSpinBox->setEnabled(false); + ui->checkBoxMidplane->setEnabled(false); + ui->checkBoxReversed->setEnabled(false); + ui->doubleSpinBox2->setEnabled(false); + ui->lineFaceName->setEnabled(false); + } else if (index == 3) { // up to face + ui->doubleSpinBox->setEnabled(false); + ui->checkBoxMidplane->setEnabled(false); + ui->checkBoxReversed->setEnabled(false); + ui->doubleSpinBox2->setEnabled(false); + ui->lineFaceName->setEnabled(true); + QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection); + } else { // two dimensions + ui->doubleSpinBox->setEnabled(true); + ui->doubleSpinBox->selectAll(); + QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + ui->checkBoxMidplane->setEnabled(false); + ui->checkBoxReversed->setEnabled(false); + ui->doubleSpinBox2->setEnabled(true); + ui->lineFaceName->setEnabled(false); + } +} + +void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + if (pcPad->Type.getValue() != 3) // ignore user selections if mode is not upToFace + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string element(msg.pSubName); + if (element.substr(0,4) != "Face") + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + pcPad->FaceName.setValue(element); + pcPad->getDocument()->recomputeFeature(pcPad); + ui->lineFaceName->setText(tr(element.c_str())); + } } void TaskPadParameters::onLengthChanged(double len) @@ -92,10 +168,10 @@ void TaskPadParameters::onLengthChanged(double len) pcPad->getDocument()->recomputeFeature(pcPad); } -void TaskPadParameters::onMirrored(bool on) +void TaskPadParameters::onMidplane(bool on) { PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - pcPad->MirroredExtent.setValue(on); + pcPad->Midplane.setValue(on); pcPad->getDocument()->recomputeFeature(pcPad); } @@ -106,6 +182,40 @@ void TaskPadParameters::onReversed(bool on) pcPad->getDocument()->recomputeFeature(pcPad); } +void TaskPadParameters::onLength2Changed(double len) +{ + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + pcPad->Length2.setValue((float)len); + pcPad->getDocument()->recomputeFeature(pcPad); +} + +void TaskPadParameters::onModeChanged(int index) +{ + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + + switch (index) { + case 0: pcPad->Type.setValue("Length"); break; + case 1: pcPad->Type.setValue("UpToLast"); break; + case 2: pcPad->Type.setValue("UpToFirst"); break; + case 3: pcPad->Type.setValue("UpToFace"); break; + default: pcPad->Type.setValue("TwoLengths"); + } + + updateUI(index); + + pcPad->getDocument()->recomputeFeature(pcPad); +} + +void TaskPadParameters::onFaceName(const QString& text) +{ + if (text.left(4) != tr("Face")) + return; + + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + pcPad->FaceName.setValue(text.toUtf8()); + pcPad->getDocument()->recomputeFeature(pcPad); +} + double TaskPadParameters::getLength(void) const { return ui->doubleSpinBox->value(); @@ -116,9 +226,24 @@ bool TaskPadParameters::getReversed(void) const return ui->checkBoxReversed->isChecked(); } -bool TaskPadParameters::getMirroredExtent(void) const +bool TaskPadParameters::getMidplane(void) const { - return ui->checkBoxMirrored->isChecked(); + return ui->checkBoxMidplane->isChecked(); +} + +double TaskPadParameters::getLength2(void) const +{ + return ui->doubleSpinBox2->value(); +} + +int TaskPadParameters::getMode(void) const +{ + return ui->changeMode->currentIndex(); +} + +const QString TaskPadParameters::getFaceName(void) const +{ + return ui->lineFaceName->text(); } TaskPadParameters::~TaskPadParameters() @@ -174,7 +299,10 @@ bool TaskDlgPadParameters::accept() //Gui::Command::openCommand("Pad changed"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirroredExtent = %i",name.c_str(),parameter->getMirroredExtent()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length2 = %f",name.c_str(),parameter->getLength2()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!PadView->getObject()->isValid()) throw Base::Exception(PadView->getObject()->getStatusString()); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index c16493cadf..53afdacd06 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -44,7 +44,7 @@ namespace PartDesignGui { -class TaskPadParameters : public Gui::TaskView::TaskBox +class TaskPadParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver { Q_OBJECT @@ -52,19 +52,27 @@ public: TaskPadParameters(ViewProviderPad *PadView,QWidget *parent = 0); ~TaskPadParameters(); + int getMode(void) const; double getLength(void) const; + double getLength2(void) const; bool getReversed(void) const; - bool getMirroredExtent(void) const; + bool getMidplane(void) const; + const QString getFaceName(void) const; private Q_SLOTS: void onLengthChanged(double); - void onMirrored(bool); + void onMidplane(bool); void onReversed(bool); + void onLength2Changed(double); + void onModeChanged(int); + void onFaceName(const QString& text); protected: void changeEvent(QEvent *e); private: + void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(int index); private: QWidget* proxy; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.ui b/src/Mod/PartDesign/Gui/TaskPadParameters.ui index d407bbf316..d1f2601cb4 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.ui @@ -6,8 +6,8 @@ 0 0 - 158 - 116 + 272 + 238 @@ -19,7 +19,7 @@ - Type: + Type @@ -39,7 +39,7 @@ - Length: + Length @@ -55,19 +55,19 @@ 5.000000000000000 - 20.000000000000000 + 10.000000000000000
- + - false + true - Mirrored extent + Symmetric to plane @@ -78,6 +78,47 @@ + + + + + + 2nd length + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + 5.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + Face + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp index 30618f6214..2122bafd1e 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.cpp @@ -58,16 +58,39 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onLengthChanged(double))); + connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), + this, SLOT(onModeChanged(int))); + connect(ui->lineFaceName, SIGNAL(textEdited(QString)), + this, SLOT(onFaceName(QString))); this->groupLayout()->addWidget(proxy); PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); double l = pcPocket->Length.getValue(); + int index = pcPocket->Type.getValue(); // must extract value here, clear() kills it! + const char* upToFace = pcPocket->FaceName.getValue(); - ui->doubleSpinBox->setMaximum(INT_MAX); - ui->doubleSpinBox->setValue(l); - ui->doubleSpinBox->selectAll(); - QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + ui->changeMode->clear(); + ui->changeMode->insertItem(0, tr("Dimension")); + ui->changeMode->insertItem(1, tr("To last")); + ui->changeMode->insertItem(2, tr("To first")); + ui->changeMode->insertItem(3, tr("Through all")); + ui->changeMode->insertItem(4, tr("Up to face")); + ui->changeMode->setCurrentIndex(index); + + if (index == 0) { // Only this option requires a numeric value + ui->doubleSpinBox->setMaximum(INT_MAX); + ui->doubleSpinBox->setValue(l); + ui->doubleSpinBox->selectAll(); + QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + ui->lineFaceName->setEnabled(false); + } else if (index == 4) { // Only this option requires to select a face + ui->doubleSpinBox->setEnabled(false); + ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace)); + } else { // Neither value nor face required + ui->doubleSpinBox->setEnabled(false); + ui->lineFaceName->setEnabled(false); + } //// check if the sketch has support //Sketcher::SketchObject *pcSketch; @@ -81,6 +104,25 @@ TaskPocketParameters::TaskPocketParameters(ViewProviderPocket *PocketView,QWidge //} } +void TaskPocketParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + if (pcPocket->Type.getValue() != 4) // ignore user selections if mode is not upToFace + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string element(msg.pSubName); + if (element.substr(0,4) != "Face") + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + pcPocket->FaceName.setValue(element); + pcPocket->getDocument()->recomputeFeature(pcPocket); + ui->lineFaceName->setText(tr(element.c_str())); + } +} + void TaskPocketParameters::onLengthChanged(double len) { PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); @@ -88,11 +130,59 @@ void TaskPocketParameters::onLengthChanged(double len) pcPocket->getDocument()->recomputeFeature(pcPocket); } +void TaskPocketParameters::onModeChanged(int index) +{ + PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + + switch (index) { + case 0: pcPocket->Type.setValue("Length"); break; + case 1: pcPocket->Type.setValue("UpToLast"); break; + case 2: pcPocket->Type.setValue("UpToFirst"); break; + case 3: pcPocket->Type.setValue("ThroughAll"); break; + case 4: pcPocket->Type.setValue("UpToFace"); break; + default: pcPocket->Type.setValue("Length"); + } + + if (index == 0) { + ui->doubleSpinBox->setEnabled(true); + ui->lineFaceName->setEnabled(false); + ui->doubleSpinBox->setValue(pcPocket->Length.getValue()); + } else if (index == 4) { + ui->lineFaceName->setEnabled(true); + ui->doubleSpinBox->setEnabled(false); + ui->lineFaceName->setText(tr(pcPocket->FaceName.getValue())); + } else { + ui->doubleSpinBox->setEnabled(false); + ui->lineFaceName->setEnabled(false); + } + + pcPocket->getDocument()->recomputeFeature(pcPocket); +} + +void TaskPocketParameters::onFaceName(const QString& text) +{ + if (text.left(4) != tr("Face")) + return; + + PartDesign::Pocket* pcPocket = static_cast(PocketView->getObject()); + pcPocket->FaceName.setValue(text.toUtf8()); + pcPocket->getDocument()->recomputeFeature(pcPocket); +} + double TaskPocketParameters::getLength(void) const { return ui->doubleSpinBox->value(); } +int TaskPocketParameters::getMode(void) const +{ + return ui->changeMode->currentIndex(); +} + +const QString TaskPocketParameters::getFaceName(void) const +{ + return ui->lineFaceName->text(); +} TaskPocketParameters::~TaskPocketParameters() { @@ -145,6 +235,8 @@ bool TaskDlgPocketParameters::accept() //Gui::Command::openCommand("Pocket changed"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); Gui::Command::commitCommand(); @@ -163,7 +255,7 @@ bool TaskDlgPocketParameters::reject() pcSupport = pcSketch->Support.getValue(); } - // role back the done things + // 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.h b/src/Mod/PartDesign/Gui/TaskPocketParameters.h index 077a9ef0c9..bbb6bbb3fe 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.h @@ -44,7 +44,7 @@ namespace PartDesignGui { -class TaskPocketParameters : public Gui::TaskView::TaskBox +class TaskPocketParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver { Q_OBJECT @@ -53,14 +53,19 @@ public: ~TaskPocketParameters(); double getLength(void) const; + int getMode(void) const; + const QString getFaceName(void) const; private Q_SLOTS: void onLengthChanged(double); + void onModeChanged(int); + void onFaceName(const QString& text); protected: void changeEvent(QEvent *e); private: + void onSelectionChanged(const Gui::SelectionChanges& msg); private: QWidget* proxy; diff --git a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui index 34c8979a17..4f313be764 100644 --- a/src/Mod/PartDesign/Gui/TaskPocketParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPocketParameters.ui @@ -6,49 +6,97 @@ 0 0 - 137 - 68 + 241 + 134 + + + 0 + 0 + + + + + 233 + 134 + + Form - - - - - + + + + 10 + 10 + 211 + 34 + + + + + + + Type + + + + + + - Type: + Dimension - - - - - - - Dimension - - - - - - - - - - - - Length - - - - - - - - - + + + + + + + + + 10 + 90 + 211 + 34 + + + + + + + Face + + + + + + + + + + + + 10 + 50 + 211 + 34 + + + + + + + Length + + + + + + + + diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp index 05b01058f1..f78134b743 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.cpp @@ -60,11 +60,18 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol 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))); this->groupLayout()->addWidget(proxy); PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); double l = pcRevolution->Angle.getValue(); + bool mirrored = pcRevolution->Midplane.getValue(); + bool reversed = pcRevolution->Reversed.getValue(); + ui->doubleSpinBox->setValue(l); int count=pcRevolution->getSketchAxisCount(); @@ -95,6 +102,9 @@ TaskRevolutionParameters::TaskRevolutionParameters(ViewProviderRevolution *Revol ui->axis->setCurrentIndex(pos); + ui->checkBoxMidplane->setChecked(mirrored); + ui->checkBoxReversed->setChecked(reversed); + setFocus (); } @@ -126,6 +136,19 @@ void TaskRevolutionParameters::onAxisChanged(int num) pcRevolution->getDocument()->recomputeFeature(pcRevolution); } +void TaskRevolutionParameters::onMidplane(bool on) +{ + PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + pcRevolution->Midplane.setValue(on); + pcRevolution->getDocument()->recomputeFeature(pcRevolution); +} + +void TaskRevolutionParameters::onReversed(bool on) +{ + PartDesign::Revolution* pcRevolution = static_cast(RevolutionView->getObject()); + pcRevolution->Reversed.setValue(on); + pcRevolution->getDocument()->recomputeFeature(pcRevolution); +} double TaskRevolutionParameters::getAngle(void) const { @@ -157,6 +180,16 @@ QString TaskRevolutionParameters::getReferenceAxis(void) const return buf; } +bool TaskRevolutionParameters::getMidplane(void) const +{ + return ui->checkBoxMidplane->isChecked(); +} + +bool TaskRevolutionParameters::getReversed(void) const +{ + return ui->checkBoxReversed->isChecked(); +} + TaskRevolutionParameters::~TaskRevolutionParameters() { delete ui; @@ -210,6 +243,8 @@ bool TaskDlgRevolutionParameters::accept() Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Angle = %f",name.c_str(),parameter->getAngle()); std::string axis = parameter->getReferenceAxis().toStdString(); 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(),parameter->getMidplane()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); Gui::Command::commitCommand(); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h index dcafbd6186..1d9eb71a86 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.h @@ -54,10 +54,14 @@ public: QString getReferenceAxis(void) const; double getAngle(void) const; + bool getMidplane(void) const; + bool getReversed(void) const; private Q_SLOTS: void onAngleChanged(double); void onAxisChanged(int); + void onMidplane(bool); + void onReversed(bool); protected: void changeEvent(QEvent *e); diff --git a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui index a80c300fef..dac292f995 100644 --- a/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskRevolutionParameters.ui @@ -6,8 +6,8 @@ 0 0 - 182 - 68 + 278 + 158 @@ -54,7 +54,7 @@ 1 - -360.000000000000000 + 0.000000000000000 360.000000000000000 @@ -69,6 +69,23 @@ + + + + true + + + Symmetric to plane + + + + + + + Reversed + + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp new file mode 100644 index 0000000000..af7a248547 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + * 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 +#include +#include +#include +#include + +#include "ViewProviderGroove.h" +#include "TaskGrooveParameters.h" + +using namespace PartDesignGui; + +PROPERTY_SOURCE(PartDesignGui::ViewProviderGroove,PartDesignGui::ViewProvider) + +ViewProviderGroove::ViewProviderGroove() +{ +} + +ViewProviderGroove::~ViewProviderGroove() +{ +} + +std::vector ViewProviderGroove::claimChildren(void)const +{ + std::vector temp; + temp.push_back(static_cast(getObject())->Sketch.getValue()); + + return temp; +} + +void ViewProviderGroove::setupContextMenu(QMenu* menu, QObject* receiver, const char* member) +{ + QAction* act; + act = menu->addAction(QObject::tr("Edit Groove"), receiver, member); + act->setData(QVariant((int)ViewProvider::Default)); + PartGui::ViewProviderPart::setupContextMenu(menu, receiver, member); +} + +bool ViewProviderGroove::setEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default ) { + // When double-clicking on the item for this pad the + // object unsets and sets its edit mode without closing + // the task panel + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgGrooveParameters *padDlg = qobject_cast(dlg); + if (padDlg && padDlg->getGrooveView() != 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().closeDialog(); + else + return false; + } + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + //if (ModNum == 1) + // Gui::Command::openCommand("Change Groove parameters"); + + // start the edit dialog + if (padDlg) + Gui::Control().showDialog(padDlg); + else + Gui::Control().showDialog(new TaskDlgGrooveParameters(this)); + + return true; + } + else { + return PartGui::ViewProviderPart::setEdit(ModNum); + } +} + +void ViewProviderGroove::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + // and update the pad + //getSketchObject()->getDocument()->recompute(); + + // when pressing ESC make sure to close the dialog + Gui::Control().closeDialog(); + } + else { + PartGui::ViewProviderPart::unsetEdit(ModNum); + } +} + +bool ViewProviderGroove::onDelete(const std::vector &) +{ + // get the support and Sketch + PartDesign::Groove* pcGroove = static_cast(getObject()); + Sketcher::SketchObject *pcSketch; + App::DocumentObject *pcSupport; + 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 (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; +} + + diff --git a/src/Mod/PartDesign/Gui/ViewProviderGroove.h b/src/Mod/PartDesign/Gui/ViewProviderGroove.h new file mode 100644 index 0000000000..51b1adca49 --- /dev/null +++ b/src/Mod/PartDesign/Gui/ViewProviderGroove.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * 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_ViewProviderGroove_H +#define PARTGUI_ViewProviderGroove_H + +#include "ViewProvider.h" + + +namespace PartDesignGui { + +class PartDesignGuiExport ViewProviderGroove : public ViewProvider +{ + PROPERTY_HEADER(PartGui::ViewProviderGroove); + +public: + /// constructor + ViewProviderGroove(); + /// destructor + virtual ~ViewProviderGroove(); + + /// grouping handling + std::vector claimChildren(void)const; + + void setupContextMenu(QMenu*, QObject*, const char*); + + virtual bool onDelete(const std::vector &); + +protected: + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + +}; + + +} // namespace PartDesignGui + + +#endif // PARTGUI_ViewProviderGroove_H diff --git a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp index 99a56a0147..c818400225 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderPocket.cpp @@ -122,8 +122,8 @@ bool ViewProviderPocket::onDelete(const std::vector &) { // get the support and Sketch PartDesign::Pocket* pcPocket = static_cast(getObject()); - Sketcher::SketchObject *pcSketch; - App::DocumentObject *pcSupport; + Sketcher::SketchObject *pcSketch = 0; + App::DocumentObject *pcSupport = 0; if (pcPocket->Sketch.getValue()){ pcSketch = static_cast(pcPocket->Sketch.getValue()); pcSupport = pcSketch->Support.getValue(); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 50f9f9adfd..961393e703 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -86,6 +86,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", @@ -169,6 +170,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" + << "PartDesign_Groove" << "PartDesign_Fillet" << "PartDesign_Chamfer"; @@ -186,6 +188,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "PartDesign_Pad" << "PartDesign_Pocket" << "PartDesign_Revolution" + << "PartDesign_Groove" << "PartDesign_Fillet" << "PartDesign_Chamfer"; diff --git a/src/Mod/Points/App/PointsPyImp.cpp b/src/Mod/Points/App/PointsPyImp.cpp index 75df742c8e..b0b2819ac8 100644 --- a/src/Mod/Points/App/PointsPyImp.cpp +++ b/src/Mod/Points/App/PointsPyImp.cpp @@ -59,14 +59,20 @@ int PointsPy::PyInit(PyObject* args, PyObject* /*kwd*/) *getPointKernelPtr() = *(static_cast(pcObj)->getPointKernelPtr()); } else if (PyList_Check(pcObj)) { - addPoints(args); + if (!addPoints(args)) + return -1; } else if (PyTuple_Check(pcObj)) { - addPoints(args); + if (!addPoints(args)) + return -1; } else if (PyString_Check(pcObj)) { getPointKernelPtr()->load(PyString_AsString(pcObj)); } + else { + PyErr_SetString(PyExc_TypeError, "optional argument must be list, tuple or string"); + return -1; + } return 0; } diff --git a/src/Mod/Points/Gui/Makefile.am b/src/Mod/Points/Gui/Makefile.am index bf7db853dc..240f526796 100644 --- a/src/Mod/Points/Gui/Makefile.am +++ b/src/Mod/Points/Gui/Makefile.am @@ -100,6 +100,8 @@ EXTRA_DIST = \ Resources/translations/Points_nl.ts \ Resources/translations/Points_no.qm \ Resources/translations/Points_no.ts \ + Resources/translations/Points_pl.qm \ + Resources/translations/Points_pl.ts \ Resources/translations/Points_pt.qm \ Resources/translations/Points_pt.ts \ Resources/translations/Points_ru.qm \ diff --git a/src/Mod/Points/Gui/Resources/Points.qrc b/src/Mod/Points/Gui/Resources/Points.qrc index f581657337..b69922e70d 100644 --- a/src/Mod/Points/Gui/Resources/Points.qrc +++ b/src/Mod/Points/Gui/Resources/Points.qrc @@ -9,6 +9,7 @@ translations/Points_it.qm translations/Points_nl.qm translations/Points_no.qm + translations/Points_pl.qm translations/Points_pt.qm translations/Points_ru.qm translations/Points_se.qm diff --git a/src/Mod/Points/Gui/Resources/translations/Points_de.qm b/src/Mod/Points/Gui/Resources/translations/Points_de.qm index 668c2abcdb..9407ace9b0 100644 Binary files a/src/Mod/Points/Gui/Resources/translations/Points_de.qm and b/src/Mod/Points/Gui/Resources/translations/Points_de.qm differ diff --git a/src/Mod/Points/Gui/Resources/translations/Points_de.ts b/src/Mod/Points/Gui/Resources/translations/Points_de.ts index 8aac390fb3..41c2e2c8f8 100644 --- a/src/Mod/Points/Gui/Resources/translations/Points_de.ts +++ b/src/Mod/Points/Gui/Resources/translations/Points_de.ts @@ -175,7 +175,7 @@ Ascii Points (*.asc);;All Files (*.*) - ASCII-Punkte (.asc); Alle Dateien (*.*) + ASCII-Punkte (.asc);;Alle Dateien (*.*) diff --git a/src/Mod/Raytracing/Gui/Makefile.am b/src/Mod/Raytracing/Gui/Makefile.am index e6de6088f4..b83c798555 100644 --- a/src/Mod/Raytracing/Gui/Makefile.am +++ b/src/Mod/Raytracing/Gui/Makefile.am @@ -118,6 +118,8 @@ EXTRA_DIST = \ Resources/translations/Raytracing_nl.ts \ Resources/translations/Raytracing_no.qm \ Resources/translations/Raytracing_no.ts \ + Resources/translations/Raytracing_pl.qm \ + Resources/translations/Raytracing_pl.ts \ Resources/translations/Raytracing_pt.qm \ Resources/translations/Raytracing_pt.ts \ Resources/translations/Raytracing_ru.qm \ diff --git a/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc b/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc index a7420fd6c0..69d1523663 100644 --- a/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc +++ b/src/Mod/Raytracing/Gui/Resources/Raytracing.qrc @@ -16,6 +16,7 @@ translations/Raytracing_it.qm translations/Raytracing_nl.qm translations/Raytracing_no.qm + translations/Raytracing_pl.qm translations/Raytracing_pt.qm translations/Raytracing_ru.qm translations/Raytracing_se.qm diff --git a/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am b/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am index 24b8a7852a..a22aca9c0a 100644 --- a/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am +++ b/src/Mod/ReverseEngineering/Gui/Resources/Makefile.am @@ -26,6 +26,8 @@ EXTRA_DIST = \ translations/ReverseEngineering_nl.ts \ translations/ReverseEngineering_no.qm \ translations/ReverseEngineering_no.ts \ + translations/ReverseEngineering_pl.qm \ + translations/ReverseEngineering_pl.ts \ translations/ReverseEngineering_pt.qm \ translations/ReverseEngineering_pt.ts \ translations/ReverseEngineering_ru.qm \ diff --git a/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc b/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc index 93af7ddc1d..5063d5c727 100644 --- a/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc +++ b/src/Mod/ReverseEngineering/Gui/Resources/ReverseEngineering.qrc @@ -10,6 +10,7 @@ translations/ReverseEngineering_it.qm translations/ReverseEngineering_nl.qm translations/ReverseEngineering_no.qm + translations/ReverseEngineering_pl.qm translations/ReverseEngineering_pt.qm translations/ReverseEngineering_ru.qm translations/ReverseEngineering_se.qm diff --git a/src/Mod/Robot/Gui/Resources/Makefile.am b/src/Mod/Robot/Gui/Resources/Makefile.am index 14c5cfa1cf..8b536ce973 100644 --- a/src/Mod/Robot/Gui/Resources/Makefile.am +++ b/src/Mod/Robot/Gui/Resources/Makefile.am @@ -38,6 +38,8 @@ EXTRA_DIST = \ translations/Robot_nl.ts \ translations/Robot_no.qm \ translations/Robot_no.ts \ + translations/Robot_pl.qm \ + translations/Robot_pl.ts \ translations/Robot_pt.qm \ translations/Robot_pt.ts \ translations/Robot_ru.qm \ diff --git a/src/Mod/Robot/Gui/Resources/Robot.qrc b/src/Mod/Robot/Gui/Resources/Robot.qrc index 97016da491..e7842fc4fa 100644 --- a/src/Mod/Robot/Gui/Resources/Robot.qrc +++ b/src/Mod/Robot/Gui/Resources/Robot.qrc @@ -22,6 +22,7 @@ translations/Robot_it.qm translations/Robot_nl.qm translations/Robot_no.qm + translations/Robot_pl.qm translations/Robot_pt.qm translations/Robot_ru.qm translations/Robot_se.qm diff --git a/src/Mod/Sandbox/Gui/Makefile.am b/src/Mod/Sandbox/Gui/Makefile.am index 87a548f3de..c936b9cc30 100644 --- a/src/Mod/Sandbox/Gui/Makefile.am +++ b/src/Mod/Sandbox/Gui/Makefile.am @@ -13,7 +13,7 @@ libSandboxGui_la_LDFLAGS = -L../../../Base -L../../../App -L../../../Gui -L../.. $(sim_ac_coin_ldflags) $(sim_ac_coin_libs) $(sim_ac_soqt_ldflags) $(sim_ac_soqt_libs) \ $(QT_LIBS) $(all_libraries) -version-info @LIB_CURRENT@:@LIB_REVISION@:@LIB_AGE@ -libSandboxGui_la_CPPFLAGS = -DSandboxAppExport= -DSandboxGuiExport= +libSandboxGui_la_CPPFLAGS = $(sim_ac_coin_cppflags) -DSandboxAppExport= -DSandboxGuiExport= libSandboxGui_la_LIBADD = \ @BOOST_SYSTEM_LIB@ \ diff --git a/src/Mod/Ship/CMakeLists.txt b/src/Mod/Ship/CMakeLists.txt index 058b9aec1b..7944e4c38e 100644 --- a/src/Mod/Ship/CMakeLists.txt +++ b/src/Mod/Ship/CMakeLists.txt @@ -2,6 +2,7 @@ SET(ShipMain_SRCS InitGui.py ShipGui.py Instance.py + TankInstance.py ) SOURCE_GROUP("" FILES ${ShipMain_SRCS}) @@ -32,6 +33,12 @@ SET(ShipIcons_SRCS Icons/ReparametrizeIco.xpm Icons/Ship.xcf Icons/Ship.xpm + Icons/Weight.png + Icons/Weight.xcf + Icons/Weight.xpm + Icons/Tank.png + Icons/Tank.xcf + Icons/Tank.xpm ) SOURCE_GROUP("shipicons" FILES ${ShipIcons_SRCS}) @@ -92,7 +99,30 @@ SET(ShipUtils_SRCS ) SOURCE_GROUP("shiputils" FILES ${ShipUtils_SRCS}) -SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS}) +SET(ShipWeights_SRCS + tankWeights/__init__.py + tankWeights/Preview.py + tankWeights/TaskPanel.py + tankWeights/TaskPanel.ui +) +SOURCE_GROUP("shipweights" FILES ${ShipWeights_SRCS}) + +SET(ShipCreateTank_SRCS + tankCreateTank/__init__.py + tankCreateTank/TaskPanel.py + tankCreateTank/TaskPanel.ui +) +SOURCE_GROUP("shipcreatetank" FILES ${ShipCreateTank_SRCS}) + +SET(ShipGZ_SRCS + tankGZ/__init__.py + tankGZ/Plot.py + tankGZ/TaskPanel.py + tankGZ/TaskPanel.ui +) +SOURCE_GROUP("shipcreatetank" FILES ${ShipCreateTank_SRCS}) + +SET(all_files ${ShipMain_SRCS} ${ShipIcons_SRCS} ${ShipExamples_SRCS} ${ShipLoadExample_SRCS} ${ShipCreateShip_SRCS} ${ShipOutlineDraw_SRCS} ${ShipAreasCurve_SRCS} ${ShipHydrostatics_SRCS} ${ShipUtils_SRCS} ${ShipWeights_SRCS} ${ShipCreateTank_SRCS} ${ShipGZ_SRCS}) ADD_CUSTOM_TARGET(Ship ALL SOURCES ${all_files} @@ -148,6 +178,24 @@ INSTALL( DESTINATION Mod/Ship/shipUtils ) +INSTALL( + FILES + ${ShipWeights_SRCS} + DESTINATION + Mod/Ship/tankWeights +) +INSTALL( + FILES + ${ShipCreateTank_SRCS} + DESTINATION + Mod/Ship/tankCreateTank +) +INSTALL( + FILES + ${ShipGZ_SRCS} + DESTINATION + Mod/Ship/tankGZ +) INSTALL( FILES ${ShipMain_SRCS} @@ -155,3 +203,4 @@ INSTALL( Mod/Ship ) + diff --git a/src/Mod/Ship/Icons/Tank.png b/src/Mod/Ship/Icons/Tank.png new file mode 100644 index 0000000000..d8efae6a56 Binary files /dev/null and b/src/Mod/Ship/Icons/Tank.png differ diff --git a/src/Mod/Ship/Icons/Tank.xcf b/src/Mod/Ship/Icons/Tank.xcf new file mode 100644 index 0000000000..bd306edc19 Binary files /dev/null and b/src/Mod/Ship/Icons/Tank.xcf differ diff --git a/src/Mod/Ship/Icons/Tank.xpm b/src/Mod/Ship/Icons/Tank.xpm new file mode 100644 index 0000000000..76dc7a95b1 --- /dev/null +++ b/src/Mod/Ship/Icons/Tank.xpm @@ -0,0 +1,1736 @@ +/* XPM */ +static char * Tank_xpm[] = { +"128 128 1605 2", +" c None", +". c #000000", +"+ c #D1D1D1", +"@ c #D2D2D2", +"# c #D3D3D3", +"$ c #D3D4D4", +"% c #D5D5D5", +"& c #CFD0CF", +"* c #D0D0D0", +"= c #D3D2D3", +"- c #D4D4D3", +"; c #D5D6D5", +"> c #D6D6D6", +", c #D7D7D7", +"' c #CDCECE", +") c #CFCECE", +"! c #D0CFCF", +"~ c #D3D3D2", +"{ c #D3D3D4", +"] c #D5D4D5", +"^ c #D6D7D6", +"/ c #D8D8D8", +"( c #D8D8D9", +"_ c #D9D9DA", +": c #CCCCCB", +"< c #CCCCCC", +"[ c #CECECD", +"} c #CECECE", +"| c #CFCFCF", +"1 c #D1D2D2", +"2 c #D5D4D4", +"3 c #D8D9D9", +"4 c #DAD9DA", +"5 c #DADBDB", +"6 c #DBDCDB", +"7 c #CACACA", +"8 c #CACBCB", +"9 c #CBCBCB", +"0 c #CCCDCD", +"a c #CECDCD", +"b c #D2D2D1", +"c c #D2D3D3", +"d c #D4D3D3", +"e c #D9D9D8", +"f c #D9D9D9", +"g c #DADBDA", +"h c #DBDCDC", +"i c #DCDCDC", +"j c #DDDDDD", +"k c #DEDEDE", +"l c #C7C8C8", +"m c #C9C9C9", +"n c #CAC9CA", +"o c #CBCBCC", +"p c #CCCDCC", +"q c #CDCDCD", +"r c #D0D1D1", +"s c #D1D2D1", +"t c #D3D2D2", +"u c #D4D4D5", +"v c #D5D5D6", +"w c #D6D7D7", +"x c #D8D7D8", +"y c #D9D8D9", +"z c #DADAD9", +"A c #DBDADA", +"B c #DBDBDC", +"C c #DDDCDD", +"D c #DDDEDE", +"E c #DEDFDE", +"F c #DFE0E0", +"G c #E0E0E1", +"H c #C6C6C6", +"I c #C7C7C7", +"J c #C8C8C7", +"K c #C9C9C8", +"L c #CACAC9", +"M c #CBCACB", +"N c #D0CFD0", +"O c #D1D0D1", +"P c #D1D1D2", +"Q c #D4D4D4", +"R c #D6D5D6", +"S c #D7D6D7", +"T c #D7D8D8", +"U c #DAD9D9", +"V c #DADADA", +"W c #DBDBDB", +"X c #DCDBDC", +"Y c #DDDDDC", +"Z c #DFDEDF", +"` c #E0DFDF", +" . c #E0E0E0", +".. c #E1E1E1", +"+. c #E2E2E2", +"@. c #C5C4C4", +"#. c #C5C5C5", +"$. c #C8C8C8", +"%. c #C9C8C8", +"&. c #D5D5D4", +"*. c #D8D7D7", +"=. c #D9D8D8", +"-. c #DCDDDD", +";. c #DEDDDD", +">. c #E3E4E3", +",. c #E5E4E4", +"'. c #C4C4C4", +"). c #C6C7C6", +"!. c #C7C8C7", +"~. c #C8C8C9", +"{. c #CACACB", +"]. c #CCCBCB", +"^. c #D0D0D1", +"/. c #D5D6D6", +"(. c #D7D7D6", +"_. c #DFDFDF", +":. c #E1E2E2", +"<. c #E3E3E3", +"[. c #E4E3E4", +"}. c #E6E5E5", +"|. c #E6E6E6", +"1. c #E6E7E7", +"2. c #C4C5C5", +"3. c #C6C6C7", +"4. c #CFD0D0", +"5. c #D1D0D0", +"6. c #D6D5D5", +"7. c #DADADB", +"8. c #DCDDDC", +"9. c #DDDDDE", +"0. c #DEDFDF", +"a. c #E1E1E2", +"b. c #E3E2E2", +"c. c #E4E4E4", +"d. c #E5E5E5", +"e. c #E8E8E7", +"f. c #E9E8E9", +"g. c #EAE9EA", +"h. c #C5C5C4", +"i. c #C6C6C5", +"j. c #C7C7C6", +"k. c #CBCACA", +"l. c #CDCDCC", +"m. c #CECFCF", +"n. c #DBDADB", +"o. c #E0E0DF", +"p. c #E1E1E0", +"q. c #E1E2E1", +"r. c #E3E3E4", +"s. c #E4E5E5", +"t. c #E7E6E7", +"u. c #E7E7E8", +"v. c #E9E9E8", +"w. c #E9EAE9", +"x. c #EAEAEA", +"y. c #EBEBEA", +"z. c #C4C5C4", +"A. c #C6C5C5", +"B. c #C6C7C7", +"C. c #CCCCCD", +"D. c #CECECF", +"E. c #D9DAD9", +"F. c #DBDBDA", +"G. c #DEDEDD", +"H. c #E0DFE0", +"I. c #E0E1E0", +"J. c #E6E5E6", +"K. c #E7E7E6", +"L. c #E7E8E7", +"M. c #E8E8E9", +"N. c #E9E9E9", +"O. c #ECECEC", +"P. c #ECEDED", +"Q. c #EDEDEE", +"R. c #010101", +"S. c #C5C4C5", +"T. c #CBCCCB", +"U. c #CDCCCC", +"V. c #CECFCE", +"W. c #CFCFCE", +"X. c #CFCFD0", +"Y. c #D7D8D7", +"Z. c #DEDDDE", +"`. c #E1E0E0", +" + c #E5E6E6", +".+ c #EBEBEB", +"++ c #ECEBEC", +"@+ c #EDEDED", +"#+ c #EEEEEE", +"$+ c #EFEFEF", +"%+ c #F0F0F0", +"&+ c #C4C4C5", +"*+ c #CFCECF", +"=+ c #D2D1D1", +"-+ c #D6D6D5", +";+ c #D8D9D8", +">+ c #DDDEDD", +",+ c #DFDEDE", +"'+ c #E2E3E3", +")+ c #E7E7E7", +"!+ c #E8E8E8", +"~+ c #EBECEC", +"{+ c #ECEDEC", +"]+ c #EFEFF0", +"^+ c #F1F0F1", +"/+ c #F1F1F1", +"(+ c #C7C6C6", +"_+ c #C9C8C9", +":+ c #C9CAC9", +"<+ c #CACBCA", +"[+ c #D2D2D3", +"}+ c #D4D5D5", +"|+ c #DCDCDB", +"1+ c #E3E3E2", +"2+ c #E4E3E3", +"3+ c #E4E4E5", +"4+ c #E5E5E6", +"5+ c #EAEAE9", +"6+ c #ECEBEB", +"7+ c #F0F0EF", +"8+ c #F0F0F1", +"9+ c #C8C7C8", +"0+ c #C8C9C9", +"a+ c #CBCBCA", +"b+ c #CCCBCC", +"c+ c #D7D6D6", +"d+ c #DDDCDC", +"e+ c #E2E2E1", +"f+ c #E2E3E2", +"g+ c #E3E4E4", +"h+ c #E8E7E8", +"i+ c #E9E8E8", +"j+ c #EAE9E9", +"k+ c #EDECEC", +"l+ c #EEEEED", +"m+ c #EFEEEF", +"n+ c #EFF0F0", +"o+ c #F1F0F0", +"p+ c #C5C6C6", +"q+ c #C7C6C7", +"r+ c #D0D0CF", +"s+ c #D4D5D4", +"t+ c #E1E0E1", +"u+ c #E8E9E9", +"v+ c #EDECED", +"w+ c #EEEDED", +"x+ c #EEEFEF", +"y+ c #F0EFF0", +"z+ c #F0F1F0", +"A+ c #D7D7D8", +"B+ c #C8C7C7", +"C+ c #C9C9CA", +"D+ c #D2D1D2", +"E+ c #D9DADA", +"F+ c #E2E1E1", +"G+ c #E9E9EA", +"H+ c #EAEBEB", +"I+ c #D8D8D7", +"J+ c #CBCCCC", +"K+ c #CDCCCD", +"L+ c #D6D6D7", +"M+ c #E6E6E5", +"N+ c #E7E6E6", +"O+ c #E8E7E7", +"P+ c #EFEEEE", +"Q+ c #CDCECD", +"R+ c #D1D1D0", +"S+ c #D2D3D2", +"T+ c #DFE0DF", +"U+ c #E3E2E3", +"V+ c #E4E5E4", +"W+ c #E5E6E5", +"X+ c #ECECED", +"Y+ c #D4D3D4", +"Z+ c #CECDCE", +"`+ c #E6E6E7", +" @ c #EBEAEB", +".@ c #ECECEB", +"+@ c #F0F1F1", +"@@ c #DCDCDD", +"#@ c #EBEAEA", +"$@ c #F0EFEF", +"%@ c #D3D4D3", +"&@ c #E6E7E6", +"*@ c #EEEDEE", +"=@ c #ADADAD", +"-@ c #565656", +";@ c #DCDBDB", +">@ c #DFDFE0", +",@ c #E7E8E8", +"'@ c #E8E9E8", +")@ c #EDEDEC", +"!@ c #EBEBEC", +"~@ c #EEEFEE", +"{@ c #B7B6B7", +"]@ c #E5E4E5", +"^@ c #EDEEED", +"/@ c #B6B6B6", +"(@ c #B6B7B7", +"_@ c #B7B7B6", +":@ c #B7B6B6", +"<@ c #E5E5E4", +"[@ c #B5B6B5", +"}@ c #B5B6B6", +"|@ c #B5B5B5", +"1@ c #B6B5B5", +"2@ c #B6B5B6", +"3@ c #E2E1E2", +"4@ c #E4E4E3", +"5@ c #B4B4B4", +"6@ c #B4B5B5", +"7@ c #B5B5B4", +"8@ c #B6B6B5", +"9@ c #E2E2E3", +"0@ c #B3B4B4", +"a@ c #B4B4B5", +"b@ c #B4B5B4", +"c@ c #B5B4B4", +"d@ c #B3B3B3", +"e@ c #B3B3B4", +"f@ c #B4B3B3", +"g@ c #B4B4B3", +"h@ c #B5B4B5", +"i@ c #D0D1D0", +"j@ c #B3B3B2", +"k@ c #B3B2B3", +"l@ c #B4B3B4", +"m@ c #90B9D9", +"n@ c #91BAD9", +"o@ c #C6C5C6", +"p@ c #B1B2B2", +"q@ c #B2B2B2", +"r@ c #B2B3B2", +"s@ c #B2B3B3", +"t@ c #8FB7D8", +"u@ c #8EB7D7", +"v@ c #8FB8D8", +"w@ c #90B8D8", +"x@ c #91BBD9", +"y@ c #91BCDA", +"z@ c #C2C2C2", +"A@ c #C3C4C3", +"B@ c #C3C4C4", +"C@ c #C8C9C8", +"D@ c #CDCDCE", +"E@ c #B1B1B1", +"F@ c #B1B2B1", +"G@ c #B2B1B2", +"H@ c #B2B2B3", +"I@ c #B3B2B2", +"J@ c #8CB4D6", +"K@ c #8DB4D6", +"L@ c #8DB5D7", +"M@ c #8EB6D7", +"N@ c #8EB7D8", +"O@ c #8FB7D7", +"P@ c #90B9D8", +"Q@ c #91BBDA", +"R@ c #92BCD9", +"S@ c #92BCDA", +"T@ c #C1C1C0", +"U@ c #C1C1C1", +"V@ c #C2C2C1", +"W@ c #C3C3C2", +"X@ c #C3C3C3", +"Y@ c #C3C3C4", +"Z@ c #CAC9C9", +"`@ c #B1B0B0", +" # c #B2B2B1", +".# c #8BB2D5", +"+# c #8BB2D6", +"@# c #8CB3D6", +"## c #8CB3D7", +"$# c #8DB5D6", +"%# c #8EB5D7", +"&# c #8FB8D7", +"*# c #92BBD9", +"=# c #92BBDA", +"-# c #BFC0C0", +";# c #C0C1C0", +"># c #C2C1C1", +",# c #C3C2C2", +"'# c #C4C4C3", +")# c #C5C6C5", +"!# c #C5C5C6", +"~# c #B0B0B0", +"{# c #B0B1B0", +"]# c #B1B1B2", +"^# c #B2B1B1", +"/# c #0E3459", +"(# c #0E355A", +"_# c #0F355A", +":# c #0F365A", +"<# c #8AB2D5", +"[# c #8CB3D5", +"}# c #8BB3D6", +"|# c #8FB6D7", +"1# c #8FB9D7", +"2# c #90B9D7", +"3# c #90BAD8", +"4# c #90BBD9", +"5# c #92BDDA", +"6# c #93BEDA", +"7# c #BEBEBE", +"8# c #BEBFBE", +"9# c #BFBFBE", +"0# c #BFBFC0", +"a# c #C0C0BF", +"b# c #C2C3C2", +"c# c #C4C3C3", +"d# c #AFB0B0", +"e# c #AFAFB0", +"f# c #B0AFB0", +"g# c #B0B1B1", +"h# c #B0B0B1", +"i# c #B1B0B1", +"j# c #7A9EC5", +"k# c #799FC5", +"l# c #7A9FC5", +"m# c #7AA0C6", +"n# c #0E345A", +"o# c #0F3559", +"p# c #8BB1D5", +"q# c #8CB4D5", +"r# c #8FB9D8", +"s# c #90BAD7", +"t# c #91BBD8", +"u# c #91BCD9", +"v# c #91BDD9", +"w# c #92BEDA", +"x# c #93BFDA", +"y# c #BDBDBD", +"z# c #BDBEBD", +"A# c #BEBEBD", +"B# c #BEBEBF", +"C# c #BEBFBF", +"D# c #BFBFBF", +"E# c #C0C0C0", +"F# c #C1C0C0", +"G# c #C0C1C1", +"H# c #C3C2C3", +"I# c #C4C3C4", +"J# c #AFAEAF", +"K# c #AFAFAF", +"L# c #B0AFAF", +"M# c #789DC5", +"N# c #789EC5", +"O# c #799EC5", +"P# c #7AA1C5", +"Q# c #7BA1C5", +"R# c #0F3659", +"S# c #10375A", +"T# c #8DB6D6", +"U# c #8EB8D7", +"V# c #92BDD9", +"W# c #143F5B", +"X# c #174A6A", +"Y# c #84B0CB", +"Z# c #85B0CC", +"`# c #BCBCBC", +" $ c #BDBCBC", +".$ c #C0C0C1", +"+$ c #C1C2C1", +"@$ c #C2C3C3", +"#$ c #AEAEAE", +"$$ c #AEAFAF", +"%$ c #AFAFAE", +"&$ c #779BC4", +"*$ c #779CC4", +"=$ c #789CC4", +"-$ c #789DC4", +";$ c #789EC4", +">$ c #799FC4", +",$ c #7AA0C5", +"'$ c #10385A", +")$ c #8DB7D7", +"!$ c #8EB7D6", +"~$ c #90BBD8", +"{$ c #133E5B", +"]$ c #83AEC9", +"^$ c #84AFCA", +"/$ c #85B1CB", +"($ c #85B2CB", +"_$ c #BDBCBD", +":$ c #BEBDBD", +"<$ c #C0BFBF", +"[$ c #C1C1C2", +"}$ c #C9CACA", +"|$ c #AEAEAD", +"1$ c #AEAFAE", +"2$ c #AEAEAF", +"3$ c #7599C3", +"4$ c #7699C3", +"5$ c #7699C2", +"6$ c #769AC3", +"7$ c #779BC3", +"8$ c #789BC4", +"9$ c #799EC4", +"0$ c #79A0C4", +"a$ c #8CB5D5", +"b$ c #8CB5D6", +"c$ c #8DB7D6", +"d$ c #426D8A", +"e$ c #16486A", +"f$ c #7AA5C1", +"g$ c #83ADC9", +"h$ c #84B1CB", +"i$ c #85B1CC", +"j$ c #BCBDBD", +"k$ c #BDBDBC", +"l$ c #BFBEBF", +"m$ c #BFC0BF", +"n$ c #ADADAC", +"o$ c #AEADAD", +"p$ c #ADAEAD", +"q$ c #ADAEAE", +"r$ c #7496C2", +"s$ c #7597C2", +"t$ c #7598C2", +"u$ c #769BC2", +"v$ c #779BC2", +"w$ c #779CC3", +"x$ c #789DC3", +"y$ c #7AA0C4", +"z$ c #7AA1C4", +"A$ c #7AA2C5", +"B$ c #7BA2C5", +"C$ c #10395A", +"D$ c #8EB6D6", +"E$ c #8EB8D6", +"F$ c #133D5A", +"G$ c #81ABC8", +"H$ c #82ACC9", +"I$ c #82ADC9", +"J$ c #82AEC9", +"K$ c #83AFC9", +"L$ c #83B0CA", +"M$ c #BDBEBE", +"N$ c #C1C0C1", +"O$ c #C7C7C8", +"P$ c #ADACAC", +"Q$ c #AFAEAE", +"R$ c #7395C1", +"S$ c #7395C2", +"T$ c #7496C1", +"U$ c #7599C2", +"V$ c #769BC3", +"W$ c #779DC3", +"X$ c #789EC3", +"Y$ c #7AA2C4", +"Z$ c #7BA3C4", +"`$ c #7BA3C5", +" % c #11395A", +".% c #113A5A", +"+% c #123C5A", +"@% c #164A6E", +"#% c #4C7694", +"$% c #80AAC7", +"%% c #80ABC8", +"&% c #81ACC9", +"*% c #81ACC8", +"=% c #81ADC9", +"-% c #83AFCA", +";% c #84B0CA", +">% c #84B1CA", +",% c #86B3CB", +"'% c #87B4CC", +")% c #BFBEBE", +"!% c #ACACAC", +"~% c #ABACAC", +"{% c #ACACAD", +"]% c #7294C0", +"^% c #7194C0", +"/% c #7294C1", +"(% c #7394C1", +"_% c #7396C1", +":% c #7497C2", +"<% c #7498C2", +"[% c #799FC3", +"}% c #7CA3C5", +"|% c #123B5A", +"1% c #88B1D0", +"2% c #7EA8C6", +"3% c #7FA9C6", +"4% c #7FAAC7", +"5% c #81ADC8", +"6% c #85B1CA", +"7% c #86B2CB", +"8% c #86B4CB", +"9% c #87B5CB", +"0% c #BCBCBD", +"a% c #C0BFC0", +"b% c #ABABAB", +"c% c #ACABAC", +"d% c #ABABAC", +"e% c #ACADAC", +"f% c #ACADAD", +"g% c #7193C0", +"h% c #7293C0", +"i% c #7193C1", +"j% c #7293C1", +"k% c #7498C1", +"l% c #789FC4", +"m% c #79A1C3", +"n% c #79A1C4", +"o% c #7BA2C4", +"p% c #7CA4C5", +"q% c #7CA4C4", +"r% c #16496F", +"s% c #7DA7C5", +"t% c #7FAAC6", +"u% c #80ABC7", +"v% c #80ACC7", +"w% c #82AFC9", +"x% c #84B1C9", +"y% c #85B2CA", +"z% c #87B5CC", +"A% c #88B6CC", +"B% c #BDBDBE", +"C% c #C1C2C2", +"D% c #AAABAB", +"E% c #AAAAAA", +"F% c #ABAAAB", +"G% c #ABACAB", +"H% c #ACACAB", +"I% c #7192C0", +"J% c #7292C0", +"K% c #7598C1", +"L% c #7599C1", +"M% c #759AC1", +"N% c #769AC2", +"O% c #779CC2", +"P% c #779DC2", +"Q% c #789DC2", +"R% c #78A0C3", +"S% c #7CA3C4", +"T% c #7AA2C2", +"U% c #7CA5C4", +"V% c #7DA5C4", +"W% c #7DA6C5", +"X% c #7EA8C5", +"Y% c #82ADC8", +"Z% c #83B0C9", +"`% c #85B3CA", +" & c #86B5CB", +".& c #87B6CC", +"+& c #BCBDBC", +"@& c #C2C1C2", +"#& c #C2C2C3", +"$& c #AAA9AA", +"%& c #AAABAA", +"&& c #ABAAAA", +"*& c #7091BF", +"=& c #7092BF", +"-& c #7191C0", +";& c #7192BF", +">& c #7092C0", +",& c #7295C0", +"'& c #7497C1", +")& c #759AC2", +"!& c #769CC2", +"~& c #789FC3", +"{& c #79A0C3", +"]& c #79A2C4", +"^& c #7AA4C3", +"/& c #7BA4C4", +"(& c #7DA8C5", +"_& c #7EA9C6", +":& c #80AAC6", +"<& c #81ADC7", +"[& c #82ADC7", +"}& c #82AEC8", +"|& c #88B7CC", +"1& c #A9A9A9", +"2& c #A9AAAA", +"3& c #A9A9AA", +"4& c #A9AAA9", +"5& c #7090BE", +"6& c #7091BE", +"7& c #7092BE", +"8& c #7191BF", +"9& c #7397C1", +"0& c #7499C1", +"a& c #7AA1C3", +"b& c #7AA2C3", +"c& c #79A2C2", +"d& c #7AA3C3", +"e& c #7BA5C4", +"f& c #80ABC6", +"g& c #81ACC7", +"h& c #81AEC8", +"i& c #82AFC8", +"j& c #83B1CA", +"k& c #85B3CB", +"l& c #85B4CA", +"m& c #87B6CB", +"n& c #88B8CC", +"o& c #A8A8A8", +"p& c #6F90BE", +"q& c #6F91BE", +"r& c #7192BE", +"s& c #7193BF", +"t& c #769BC1", +"u& c #779EC3", +"v& c #789FC2", +"w& c #79A1C2", +"x& c #7AA3C2", +"y& c #7BA4C3", +"z& c #7CA6C5", +"A& c #7DA7C4", +"B& c #7EA7C5", +"C& c #7EA9C5", +"D& c #7EAAC6", +"E& c #7FACC6", +"F& c #81AEC7", +"G& c #82AFC7", +"H& c #83B1C9", +"I& c #84B2C9", +"J& c #84B3C9", +"K& c #86B4CA", +"L& c #89B7CC", +"M& c #89B8CD", +"N& c #A8A8A7", +"O& c #6F90BD", +"P& c #6E90BD", +"Q& c #6E90BE", +"R& c #7293BF", +"S& c #7396C0", +"T& c #7397C0", +"U& c #7498C0", +"V& c #759BC1", +"W& c #769CC1", +"X& c #779EC2", +"Y& c #789EC2", +"Z& c #78A0C1", +"`& c #78A1C2", +" * c #7BA6C3", +".* c #7BA6C4", +"+* c #7CA6C4", +"@* c #7FABC6", +"#* c #82AEC7", +"$* c #83AFC8", +"%* c #83B0C8", +"&* c #88B7CB", +"** c #89B9CC", +"=* c #89BACD", +"-* c #6E8FBD", +";* c #6F91BD", +">* c #7093BF", +",* c #7194BF", +"'* c #7294BF", +")* c #7395C0", +"!* c #7398C0", +"~* c #779FC1", +"{* c #77A0C1", +"]* c #78A1C1", +"^* c #7AA4C2", +"/* c #7CA7C4", +"(* c #7DA8C4", +"_* c #7DA9C5", +":* c #7FAAC5", +"<* c #80ACC6", +"[* c #80ADC7", +"}* c #84B1C8", +"|* c #88B8CB", +"1* c #89BACC", +"2* c #BEBDBE", +"3* c #12285A", +"4* c #768CBE", +"5* c #768DBE", +"6* c #6E91BD", +"7* c #7193BE", +"8* c #7295BF", +"9* c #7396BF", +"0* c #7398BF", +"a* c #7499C0", +"b* c #749AC1", +"c* c #779DC1", +"d* c #789FC1", +"e* c #779EC0", +"f* c #769EC0", +"g* c #769FC0", +"h* c #77A0C0", +"i* c #79A2C1", +"j* c #79A3C2", +"k* c #7BA4C2", +"l* c #7CA7C3", +"m* c #7EAAC5", +"n* c #80ADC6", +"o* c #82B0C7", +"p* c #85B2C9", +"q* c #85B3C9", +"r* c #85B4C9", +"s* c #86B5CA", +"t* c #87B6CA", +"u* c #88B9CC", +"v* c #8AB9CC", +"w* c #8ABACC", +"x* c #8BBBCC", +"y* c #758BBE", +"z* c #758CBE", +"A* c #768CBF", +"B* c #6E91BE", +"C* c #7093BE", +"D* c #7397BF", +"E* c #7497BF", +"F* c #749AC0", +"G* c #759AC0", +"H* c #769BC0", +"I* c #769CC0", +"J* c #779EC1", +"K* c #769DC0", +"L* c #759DBF", +"M* c #769DBE", +"N* c #77A1C0", +"O* c #7AA5C2", +"P* c #7DA7C3", +"Q* c #7EA9C4", +"R* c #7EAAC4", +"S* c #7FABC5", +"T* c #81ADC6", +"U* c #81AFC7", +"V* c #82B0C8", +"W* c #83B1C8", +"X* c #84B2C8", +"Y* c #86B6CB", +"Z* c #87B7CA", +"`* c #87B7CB", +" = c #84AFCB", +".= c #143F5A", +"+= c #12275A", +"@= c #758BBD", +"#= c #768BBE", +"$= c #6E8FBC", +"%= c #6E8EBD", +"&= c #7296BF", +"*= c #7297BF", +"== c #779CC1", +"-= c #749BBE", +";= c #749CBF", +">= c #759EBE", +",= c #769FBF", +"'= c #76A0C0", +")= c #779FC0", +"!= c #7BA5C3", +"~= c #7CA6C3", +"{= c #7CA8C4", +"]= c #7DA9C3", +"^= c #7FAAC4", +"/= c #81AFC6", +"(= c #82B1C7", +"_= c #85B5C9", +":= c #86B6CA", +"<= c #82AECA", +"[= c #758ABD", +"}= c #748ABD", +"|= c #758CBD", +"1= c #6D8FBC", +"2= c #759CC1", +"3= c #769DC1", +"4= c #759BBF", +"5= c #739ABE", +"6= c #759DBE", +"7= c #769EBE", +"8= c #769EBF", +"9= c #779FBF", +"0= c #78A1C0", +"a= c #78A2C1", +"b= c #79A2C0", +"c= c #7AA3C1", +"d= c #7CA8C3", +"e= c #7DA9C4", +"f= c #82B0C6", +"g= c #83B2C8", +"h= c #84B3C8", +"i= c #143E5B", +"j= c #11265A", +"k= c #7489BC", +"l= c #748ABC", +"m= c #758ABC", +"n= c #6D8EBC", +"o= c #6E8EBC", +"p= c #6D8FBD", +"q= c #6F8FBD", +"r= c #7092BD", +"s= c #7294BE", +"t= c #7194BE", +"u= c #7295BE", +"v= c #7196BF", +"w= c #759BC0", +"x= c #749ABE", +"y= c #7399BC", +"z= c #729ABD", +"A= c #739ABD", +"B= c #749CBD", +"C= c #769DBF", +"D= c #779EBF", +"E= c #78A2C0", +"F= c #79A3C1", +"G= c #7AA4C1", +"H= c #7BA6C2", +"I= c #7CA9C4", +"J= c #7EABC4", +"K= c #7FACC4", +"L= c #80ADC5", +"M= c #80AEC6", +"N= c #81AEC6", +"O= c #83B1C7", +"P= c #7EA9C7", +"Q= c #7FAAC8", +"R= c #80AAC8", +"S= c #7388BC", +"T= c #7488BC", +"U= c #7389BC", +"V= c #7489BD", +"W= c #6E8EBB", +"X= c #6D8EBD", +"Y= c #7195BE", +"Z= c #7499BF", +"`= c #749ABF", +" - c #749BC0", +".- c #7198BB", +"+- c #7298BC", +"@- c #7299BC", +"#- c #729ABC", +"$- c #739BBD", +"%- c #749BBD", +"&- c #749DBE", +"*- c #76A0BF", +"=- c #77A2C0", +"-- c #78A3C1", +";- c #79A4C1", +">- c #7CA8C2", +",- c #7DAAC4", +"'- c #7FACC5", +")- c #7DA7C6", +"!- c #7FA9C7", +"~- c #133E5A", +"{- c #7387BC", +"]- c #6F92BD", +"^- c #7094BE", +"/- c #7296BE", +"(- c #7399BD", +"_- c #0E3559", +":- c #7096BB", +"<- c #7197BB", +"[- c #7199BB", +"}- c #739BBC", +"|- c #749CBE", +"1- c #749EBE", +"2- c #769FBE", +"3- c #77A0BF", +"4- c #77A1BF", +"5- c #78A3C0", +"6- c #79A4C0", +"7- c #7AA6C2", +"8- c #7BA7C2", +"9- c #7DA8C3", +"0- c #7EACC5", +"a- c #7CA5C5", +"b- c #10255A", +"c- c #7286BB", +"d- c #7287BC", +"e- c #6D8EBB", +"f- c #7093BD", +"g- c #7094BD", +"h- c #7195BF", +"i- c #7399BF", +"j- c #739ABF", +"k- c #7398BE", +"l- c #6F95BA", +"m- c #7096BA", +"n- c #7097BB", +"o- c #739ABC", +"p- c #739CBD", +"q- c #759EBF", +"r- c #78A2BF", +"s- c #7CA7C2", +"t- c #10245A", +"u- c #7185BB", +"v- c #7286BC", +"w- c #7387BB", +"x- c #7487BC", +"y- c #6E90BC", +"z- c #6F93BE", +"A- c #7196BE", +"B- c #7297BE", +"C- c #7298BF", +"D- c #7297BD", +"E- c #6E94BA", +"F- c #6F95B9", +"G- c #6F96BA", +"H- c #7097BA", +"I- c #729ABB", +"J- c #749DBD", +"K- c #77A0BE", +"L- c #78A4C0", +"M- c #7AA5C0", +"N- c #7CA7C5", +"O- c #7185BA", +"P- c #7286BA", +"Q- c #7285BB", +"R- c #7386BB", +"S- c #7288BC", +"T- c #7589BD", +"U- c #6E91BC", +"V- c #6F91BC", +"W- c #6E92BC", +"X- c #6F93BD", +"Y- c #7194BD", +"Z- c #7195BD", +"`- c #7298BE", +" ; c #7297BC", +".; c #6D93B8", +"+; c #6E94B8", +"@; c #6E95B9", +"#; c #7096B9", +"$; c #739CBC", +"%; c #76A0BE", +"&; c #78A1BF", +"*; c #79A1C1", +"=; c #79A4C2", +"-; c #7BA3C3", +";; c #7084BA", +">; c #7184BB", +",; c #7085BB", +"'; c #7186BB", +"); c #7287BB", +"!; c #7388BB", +"~; c #6C8EBB", +"{; c #6D8FBB", +"]; c #6F92BC", +"^; c #7095BD", +"/; c #7196BD", +"(; c #7195BC", +"_; c #0E3359", +":; c #6C92B7", +"<; c #6D94B8", +"[; c #6F96B9", +"}; c #6F97BA", +"|; c #7299BB", +"1; c #729BBB", +"2; c #749DBC", +"3; c #759EBD", +"4; c #759FBE", +"5; c #10235A", +"6; c #7083BA", +"7; c #7084BB", +"8; c #7085BA", +"9; c #7093BC", +"0; c #7095BC", +"a; c #6C91B7", +"b; c #6E95B8", +"c; c #7198BA", +"d; c #739BBB", +"e; c #78A2C2", +"f; c #0F225A", +"g; c #6F82B9", +"h; c #7083B9", +"i; c #6F83B9", +"j; c #6F83BA", +"k; c #7184BA", +"l; c #6C8DBB", +"m; c #6C8FBB", +"n; c #6D90BB", +"o; c #6E91BB", +"p; c #6F93BC", +"q; c #7094BC", +"r; c #6F94BB", +"s; c #0D3259", +"t; c #6A8FB6", +"u; c #6B91B7", +"v; c #6E93B8", +"w; c #7098BA", +"x; c #7099BA", +"y; c #7199BA", +"z; c #729BBC", +"A; c #6E81B9", +"B; c #6E82B9", +"C; c #6E90BB", +"D; c #6E93BA", +"E; c #698EB6", +"F; c #6A8EB6", +"G; c #6A90B6", +"H; c #6B90B6", +"I; c #6B92B7", +"J; c #6D93B7", +"K; c #6E96B8", +"L; c #6F97B9", +"M; c #7098BB", +"N; c #78A0C0", +"O; c #6E80B8", +"P; c #6E81B8", +"Q; c #6F81B8", +"R; c #6F81B9", +"S; c #6F82B8", +"T; c #6F92BB", +"U; c #6E92BA", +"V; c #0D3159", +"W; c #688DB4", +"X; c #698EB5", +"Y; c #698FB5", +"Z; c #6A90B7", +"`; c #6C93B7", +" > c #518FC8", +".> c #6F96B8", +"+> c #123A5A", +"@> c #0F215A", +"#> c #6D80B8", +"$> c #6D81B8", +"%> c #6C8FBA", +"&> c #6E90BA", +"*> c #6E92BB", +"=> c #6E93BC", +"-> c #0C3159", +";> c #678CB4", +">> c #678DB4", +",> c #688EB4", +"'> c #698EB4", +")> c #6A90B5", +"!> c #6B91B6", +"~> c #6D94B7", +"{> c #6D95B8", +"]> c #6E96B9", +"^> c #0E2159", +"/> c #6C7FB8", +"(> c #6D7FB7", +"_> c #6D7FB8", +":> c #507FC9", +"<> c #6D8FBA", +"[> c #6D91BB", +"}> c #6D91B9", +"|> c #0C3059", +"1> c #678AB3", +"2> c #678BB3", +"3> c #678DB3", +"4> c #6B91B5", +"5> c #6B92B5", +"6> c #6C92B6", +"7> c #6B92B6", +"8> c #6C93B6", +"9> c #0E2059", +"0> c #6C7EB7", +"a> c #6D7EB7", +"b> c #6E80B7", +"c> c #6E82B8", +"d> c #7084B9", +"e> c #6F84BA", +"f> c #6C90B9", +"g> c #668AB2", +"h> c #698FB4", +"i> c #6A90B4", +"j> c #719ABB", +"k> c #749BBC", +"l> c #6B7EB7", +"m> c #6B7DB6", +"n> c #6C7DB7", +"o> c #6C7FB7", +"p> c #6D80B7", +"q> c #6F84B9", +"r> c #7186BA", +"s> c #6C8EB9", +"t> c #6589B1", +"u> c #678CB2", +"v> c #678DB2", +"w> c #688EB3", +"x> c #6A8FB5", +"y> c #6A91B5", +"z> c #6C92B5", +"A> c #6C94B7", +"B> c #6D95B7", +"C> c #759DBD", +"D> c #0E1F5A", +"E> c #6A7CB6", +"F> c #6A7DB6", +"G> c #6C7EB6", +"H> c #7082B9", +"I> c #7285BA", +"J> c #7085B9", +"K> c #0E335A", +"L> c #658BB1", +"M> c #668BB1", +"N> c #668CB1", +"O> c #678CB1", +"P> c #688DB3", +"Q> c #688FB3", +"R> c #698FB3", +"S> c #6990B4", +"T> c #7097B9", +"U> c #7197BA", +"V> c #739CBE", +"W> c #0E1F59", +"X> c #6A7BB6", +"Y> c #6B7CB6", +"Z> c #6C7DB6", +"`> c #6B7DB7", +" , c #6F82B6", +"., c #648AB0", +"+, c #658AB1", +"@, c #658BB0", +"#, c #668CB2", +"$, c #688FB4", +"%, c #6B90B5", +"&, c #0D1E59", +"*, c #697BB5", +"=, c #6A7CB7", +"-, c #6B7EB6", +";, c #6C7EB8", +">, c #6E82B7", +",, c #6389B0", +"', c #6489B0", +"), c #658AB0", +"!, c #668AB1", +"~, c #688DB2", +"{, c #6990B5", +"], c #697AB5", +"^, c #697BB6", +"/, c #6A7BB5", +"(, c #6D7EB8", +"_, c #6D81B6", +":, c #6388AE", +"<, c #6388AF", +"[, c #6389AF", +"}, c #6489AF", +"|, c #668BB0", +"1, c #6979B4", +"2, c #6879B5", +"3, c #6879B4", +"4, c #6979B5", +"5, c #6A7AB5", +"6, c #6B7CB7", +"7, c #6D80B5", +"8, c #6287AE", +"9, c #6288AE", +"0, c #0D1D59", +"a, c #6878B4", +"b, c #6778B4", +"c, c #6C7EB5", +"d, c #6186AC", +"e, c #6186AD", +"f, c #6286AE", +"g, c #668DB1", +"h, c #678EB3", +"i, c #0D1C59", +"j, c #6777B3", +"k, c #6777B4", +"l, c #697AB4", +"m, c #6A7CB5", +"n, c #6E81B7", +"o, c #6084AC", +"p, c #6185AC", +"q, c #6086AD", +"r, c #6187AE", +"s, c #6387AE", +"t, c #0C1C59", +"u, c #6676B3", +"v, c #6776B3", +"w, c #6877B4", +"x, c #687AB5", +"y, c #697CB6", +"z, c #6A7DB7", +"A, c #6B7DB5", +"B, c #5F83AC", +"C, c #6083AC", +"D, c #6185AD", +"E, c #6288AD", +"F, c #668BB2", +"G, c #6A91B4", +"H, c #6675B3", +"I, c #6575B3", +"J, c #6677B3", +"K, c #6677B4", +"L, c #6A7DB4", +"M, c #5E82AB", +"N, c #5F83AB", +"O, c #5F84AC", +"P, c #6085AD", +"Q, c #6085AC", +"R, c #10365A", +"S, c #0C1B59", +"T, c #6575B2", +"U, c #6675B2", +"V, c #6676B2", +"W, c #6676B4", +"X, c #6776B4", +"Y, c #687AB4", +"Z, c #5D81AA", +"`, c #5D81AB", +" ' c #5D82AA", +".' c #5E83AB", +"+' c #6083AB", +"@' c #6286AD", +"#' c #648AB1", +"$' c #6473B3", +"%' c #6474B2", +"&' c #697CB3", +"*' c #5D80A9", +"=' c #5E82AA", +"-' c #5F84AB", +";' c #6287AD", +">' c #6389AE", +",' c #0B1A59", +"'' c #6473B2", +")' c #6574B2", +"!' c #6574B3", +"~' c #6778B3", +"{' c #6779B4", +"]' c #687BB2", +"^' c #5B7FA9", +"/' c #5B80A9", +"(' c #5C80A9", +"_' c #5D81A9", +":' c #5E81AA", +"<' c #6184AC", +"[' c #638AB0", +"}' c #678DB1", +"|' c #0B1A58", +"1' c #6372B1", +"2' c #6472B2", +"3' c #6472B1", +"4' c #6473B1", +"5' c #6573B2", +"6' c #6576B3", +"7' c #6878B3", +"8' c #687AB3", +"9' c #5B7EA7", +"0' c #5B7FA8", +"a' c #5B80A8", +"b' c #5C81AA", +"c' c #5F82AB", +"d' c #668DB2", +"e' c #11268E", +"f' c #11268D", +"g' c #0B1958", +"h' c #6373B2", +"i' c #6877B3", +"j' c #6879B2", +"k' c #0C2F59", +"l' c #5A7DA7", +"m' c #5A7EA7", +"n' c #5B7FA7", +"o' c #5B7EA8", +"p' c #5C7FA8", +"q' c #5F83AA", +"r' c #6084AB", +"s' c #6589B0", +"t' c #0C196C", +"u' c #152064", +"v' c #11258D", +"w' c #6371B1", +"x' c #6271B1", +"y' c #6372B2", +"z' c #6778B1", +"A' c #0C2E59", +"B' c #597CA6", +"C' c #5A7CA6", +"D' c #597DA6", +"E' c #5D80AA", +"F' c #5E83AA", +"G' c #0E355B", +"H' c #0C1A6F", +"I' c #131E62", +"J' c #414C90", +"K' c #10258E", +"L' c #6271B0", +"M' c #6272B1", +"N' c #6373B1", +"O' c #6677B1", +"P' c #0B2E59", +"Q' c #577BA5", +"R' c #587BA6", +"S' c #587CA6", +"T' c #5A7EA8", +"U' c #5D82AB", +"V' c #6289AE", +"W' c #1A5FA3", +"X' c #0D1C75", +"Y' c #131E61", +"Z' c #404B8E", +"`' c #475296", +" ) c #10258D", +".) c #6270B0", +"+) c #6272B0", +"@) c #6576B2", +"#) c #6576B1", +"$) c #577AA4", +"%) c #577BA4", +"&) c #587BA5", +"*) c #5C81A9", +"=) c #648AAF", +"-) c #0E345B", +";) c #0D1D79", +">) c #101B5F", +",) c #3C478B", +"') c #11258E", +")) c #6371B0", +"!) c #6575B1", +"~) c #0B2E58", +"{) c #5679A3", +"]) c #5779A4", +"^) c #567AA4", +"/) c #577AA5", +"() c #577BA6", +"_) c #597BA6", +":) c #175797", +"<) c #0E1F82", +"[) c #101B5E", +"}) c #384487", +"|) c #0B1858", +"1) c #6170B0", +"2) c #6575B0", +"3) c #5578A2", +"4) c #5678A3", +"5) c #5679A4", +"6) c #5A7DA6", +"7) c #102394", +"8) c #111C60", +"9) c #141F63", +"0) c #293578", +"a) c #0A1859", +"b) c #616FAF", +"c) c #616FB0", +"d) c #6270AF", +"e) c #6372B0", +"f) c #6474AF", +"g) c #0B2D58", +"h) c #5576A2", +"i) c #5577A2", +"j) c #5577A3", +"k) c #5578A4", +"l) c #5578A3", +"m) c #587CA5", +"n) c #597DA7", +"o) c #5D82A9", +"p) c #6187AD", +"q) c #154F8D", +"r) c #1227A5", +"s) c #0D185C", +"t) c #1B266A", +"u) c #313C80", +"v) c #445093", +"w) c #10248D", +"x) c #6170AF", +"y) c #6474B1", +"z) c #6373AF", +"A) c #5375A1", +"B) c #5476A2", +"C) c #587AA4", +"D) c #5C7FA9", +"E) c #6084AD", +"F) c #102393", +"G) c #0C196A", +"H) c #0E1A5D", +"I) c #242F73", +"J) c #3A4589", +"K) c #626FAF", +"L) c #626FB0", +"M) c #6475B2", +"N) c #6272AE", +"O) c #0A2C59", +"P) c #5275A1", +"Q) c #5376A2", +"R) c #5477A2", +"S) c #144A84", +"T) c #0E1E7F", +"U) c #121D61", +"V) c #2B3679", +"W) c #0A1858", +"X) c #6370B0", +"Y) c #6271AF", +"Z) c #0A2C58", +"`) c #5173A0", +" ! c #5274A1", +".! c #5274A0", +"+! c #0D1B74", +"@! c #10248E", +"#! c #6171AE", +"$! c #51729F", +"%! c #51739F", +"&! c #5273A0", +"*! c #5476A1", +"=! c #5576A3", +"-! c #114379", +";! c #102291", +">! c #0C196B", +",! c #1F2A6E", +"'! c #364185", +")! c #465195", +"!! c #10238D", +"~! c #616EAF", +"{! c #616FAD", +"]! c #0A2B59", +"^! c #50729E", +"/! c #50729F", +"(! c #5375A0", +"_! c #134C8D", +":! c #0E1E81", +"~ c #323D81", +",~ c #0A2D5D", +"'~ c #1354AE", +")~ c #10228F", +"!~ c #212C70", +"~~ c #374286", +"{~ c #0F228B", +"]~ c #1251A7", +"^~ c #283377", +"/~ c #3E4A8D", +"(~ c #0F4085", +"_~ c #0B2F62", +":~ c #1328A8", +"<~ c #0D1C77", +"[~ c #303B7F", +"}~ c #104289", +"|~ c #0B3063", +"1~ c #112497", +"2~ c #1C276A", +"3~ c #0C175B", +"4~ c #0F438A", +"5~ c #0B3266", +"6~ c #0F2088", +"7~ c #0C3367", +"8~ c #365885", +"9~ c #0B3369", +"0~ c #0E1D7C", +"a~ c #0B2F60", +"b~ c #0C366E", +" ", +" ", +" ", +" ", +" ", +" . . ", +" . . . . . . . ", +" . . . . + @ # $ % . . . . ", +" . . . . & * + @ = - % ; > , . . . . ", +" . . . . ' ) ! * + @ ~ { ] % ^ , / ( _ . . . ", +" . . . . : < [ } | * + 1 = $ 2 ; > , / 3 4 5 6 . . . . ", +" . . . . 7 8 9 0 a } | * + b c d 2 % > , / e f g h i j k . . . . ", +" . . . . l m n 9 o p q } | * r s t # u % v w x y z A B i C D E F G . . . ", +" . . . . H I J K L M 9 < q ' | N O P t # Q % R S T / U V W X Y D Z ` ...+.. . . . ", +" . . . . @.#.H I $.%.L M 9 < q } } N r + @ # Q &.R S *.=.f V W X -.;.k ` ...+.+.>.,.. . . . ", +" . . . . '.'.'.#.H ).!.~.n {.].< 0 ' } | ^.b @ # Q ] /.(., / f 4 5 B i D k _. ...:.<.[.,.}.|.1.. . . . ", +" . . . . '.'.'.'.'.2.H 3.J %.m 7 9 < p } ) 4.5.+ @ ~ Q Q 6.> , / 3 4 7.X 8.9.k 0. ...a.b.<.c.d.|.1.e.f.g.. . . ", +" . . . . . '.'.'.'.'.'.'.h.i.j.$.$.m 7 k.< l.a m.| * + @ c Q Q % > , / f f n.B i j k _.o.p.q.+.r.c.s.|.t.u.v.w.x.y.. . . . ", +" . . . . . '.'.'.'.'.'.'.'.z.A.B.I $.m 7 9 ].C.q D.| * + P t # Q 6.> (.T f E.F.6 i j G.0.H.I...+.<.c.d.J.K.L.M.N.x.y.O.P.Q.. . . . ", +" R.. . '.'.'.'.'.'.'.'.'.'.'.S.A.3.I $.m n k.T.U.q V.W.X.+ + t # Q % /.S Y./ z F.W i -.Z.k _.`.a.+.<.r.s. +|.L.M.N.g..+++O.@+#+$+%+. . . ", +" . . . . . '.'.'.'.'.'.'.'.'.&+i.H I $.K n 8 < < q } *+* ^.=+@ { Q ] -+, , ;+_ V W B 8.>+,+_.G ..+.'+c.d.d.t.)+!+M.x.x.~+{+Q.#+$+]+^+/+. . . . ", +" . . =.f . . . . . '.'.'.'.'.'.2.A.H (+$._+:+<+].< q } | N ^.s [+# Q }+6.> *./ f V 5 |+C D 0._. ...q.1+2+3+4+|.1.!+N.5+y.6+O.Q.#+$+7+8+/+/+/+/+. . . . ", +" . . / / y e . . . . . '.'.'.'.&+#.H I 9+0+m a+9 b+l.} m.X.5.+ @ = $ % > c+Y./ f U W X d+k k _. ...e+f+g+c.d.J.)+h+i+j+x.6+k+@+l+m+n+o+/+/+/+/+/+/+/+. . . . ", +" . . S , *.x T / / 3 . . . . . '.'.#.p+q+!.~.m 7 9 < 0 ' } r+* P @ # { s+% w , / e V 5 B -.j k _. .t+e+1+2+3+d.|.K.u.u+N.x..+O.v+w+x+y+z+/+/+/+/+/+/+/+/+/+/+. . . ", +" . . ; > > ^ , A+/ / e y ( . . . . . i.).B+$.C+7 9 : l.a } | * + D+t d Q % > , / f E+5 6 d+j k _.o.p.F+<.r.c.d.J.)+h+!+G+x.H+O.@+@+$+y+%+/+/+/+/+/+/+/+/+/+/+/+/+. . . . ", +" . . 2 % % /.-+> ^ S , Y.I+/ =.e . . . . . I $.C+L 9 J+K+a } & 4.+ P c d Q v L+S / f f g |+i j k ,+H.t+:.+.<.c.s.M+N+O+i+N.x..+~+@+#+P+]+%+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+. . . . ", +" . . # $ Q 2 s+6./.> > , , , , / / ;+y . . . . . 7 a+< U.Q+} | N R+P S+# u % > , / ( f V W i -.Z._.T+I...+.U+c.V+W+t.O+!+N.x.y.++X+@+#+$+%+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+. . . . ", +" . . @ t # Y+Y+Q Q &.% v v > c+c+S , , / =.( f . . . . . < q Z+) X.^.D+c Q Q % /., Y./ 4 V W i d+k Z T+`.q.+.<.r.d.}.`+)+!+N.x. @.+k+@+#+x+%+z+/+/+/+/+/+/+/+/+/+/+/+/+/+. . . . f f . ", +" . . + D+@ c # # $ Q Q Q }+% % /./.S S , *.T / ;+;+f . . . . . m.4.5.b @ # Q % R > , e f V W i 8.j k _.G ..+.'+<.c.4+`+)+h+v.w.y..@O.@+#+x+n++@/+/+/+/+/+/+/+/+/+/+/+. . . . f f f f f . ", +" . . . ^.+ + P b @ c t # - - u u &.% /.R c+c+S , A+/ / y f . . . . . 5.+ @ # Q ] /.L+A+=.f V W |+@@9.k _. .t++.b.g+c.W+|.1.!+u+j+#@~+O.@+l+#+$@8+/+/+/+/+/+/+/+/+/+. . . . f f f f f f f f . ", +" . . | N * * + + =+=+D+@ S+# %@%@- Q 2 % 6.v /.> , , , / T y f f . . . . . # Q % % > , / f E+V B -.9.k _.o.p.F+f+r.c.d.|.&@O+u+N.x..+++@+*@#+]+%+/+/+/+/+/+/+/+. . . =@f f f f f f f f f f -@. ", +" . . . W.D.| | 4.* 5.r + P b @ S+# # Y+- Q Q }+% ; -+> w w S , I+/ / 3 f . . . . . ; > , A+f V g ;@i j k _.>@`...+.r.c.d.|.&@,@'@G+x..+O.)@@+x+$+z+/+/+/+/+/+. . . T / ( y f f f f f f f f f f . . ", +" . . . a } V.} W.| r+4.* ^.* + D+@ @ @ # # - Q Q ] 2 ; /.-+> w (., A+Y./ f f . . . . . , / / U V X @@j k Z .t+a.+.<.c.d.|.K.O+!+G+x.y.!@P.Q.~@$+8+/+/+/+. . . ; > w ^ , T / 3 f f f f f f f f f . . ", +" . {@. . . . Z+} ) D.m.| r+* * 5.r + D+@ S+c # # - Q Q s+% % -+> c+(., , / / / / f . . . . . f g B i j k _._.`.q.+.<.c.]@ +1.O+!+N.x..+!@)@^@#+$+%+%+. . . # - Q % % % > L+w Y./ / / f f f f f f f . . ", +" . /@(@_@:@. . . . [ } } W.| N ! * * R++ + @ @ c c # # # Q u 2 % % ; > L+, , *./ / =.;+f . . . . . i j 9.E >@G ..+.'+c.<@4+&@)+!+N.G+.+O.O.l+#+@+. . . O s @ c c $ Q Q 2 % % > c+, I+x ;+f f f f f f . ", +" . [@/@}@/@/@/@. . . . q } } W.V.! ! N * + O + b b [+t c # $ Q u 2 ] % v R > > ^ *.A+I+/ e f f . . . . 9.E _. ...+.'+[.V+}.|.)+!+v.x..+6+{+.+. . . *+X.r+* r + s @ S+c { - Q s+% > > (., *./ f f f f f . ", +" . |@|@|@1@}@2@/@}@/@. . . . Q+[ } W.| N & * * R++ D+=+@ S+~ # # %@Q Q ] % R -+> ^ , w , , / =.;+f . . . . . ...3@<.4@3+}.|.)+!+u+w.x.)+. . . 0 q } [ V.| & 4.+ R++ b @ # # Q Q &.% 6.> > , A+x ( f f . ", +" . 5@5@6@|@7@|@|@8@}@}@2@/@. . . . ' } ) | | X.| * * ^.+ P 1 @ @ ~ # d Y+Q Q % % v > v w , , *.T / =.f f . . . . . 9@2+,.d.|.t.!+!+b.. . . <+9 o b+p 0 q Z+} ) | N * O + s @ t = d - Q % % -+> ^ , *./ . ", +" . 0@5@a@a@b@c@6@7@|@|@[@8@|@8@. . . . . } ) W.W.N & r+* * r + s 1 @ # # # { - Q u % % ; ; > c+, , , I+/ ( f f . . . . . d.M+t.j . . . $.0+m :+7 M 9 9 < U.q Z+} ) *+& 4.* O + @ @ c # { - }+% % R ^ , . ", +" . d@e@f@f@g@5@5@h@b@5@h@|@b@|@|@|@|@. . . . Z+} } | | & X.r+5.i@+ s D+@ [+t # # Q Q 2 &.% % /.R > c+, , T T / y f . . . . . . . . H 3.I !.$.%.~.C+7 {.a+T.: C.< q q } D.| r+* ^.+ =+1 @ c # - Q s+% v . ", +" . j@k@d@d@d@d@g@f@e@d@l@5@5@a@b@6@c@6@|@|@. . . . [ } } m.| | r+* * + + =+D+@ ~ ~ # m@n@n@Q &.% % v > c+(., , Y./ / =.f . . . '.h.#.#.o@H I I J $.K m C+7 M M ].< U.p q ' D.m.| ! * O + @ @ c @ d d 2 . ", +" . p@q@q@r@r@r@j@s@d@d@f@e@5@l@0@5@5@b@b@c@7@7@7@. . . . } V.V.) | & * * * + s t@u@v@v@w@m@n@x@y@u % v % > > (., , *.x / Y.. . z@A@B@'.2.#.#.p+j.I !.$.C@_+:+C+<+8 9 o < U.0 D@} W.m.| r+* O + s @ t # . ", +" . E@E@F@F@G@q@q@H@H@I@d@H@d@d@d@d@5@f@5@5@5@5@5@c@h@. . . . [ Z+) ) m.| 4.J@K@L@M@N@O@v@w@m@P@x@Q@R@S@] % 6.6.> > w , , . . T@U@V@W@X@Y@X@h.2.#.#.H B.I !.$.$._+Z@7 7 9 T.o < l.q q } } | | X.^.r D+=+. ", +" . `@E@E@E@E@F@G@ #p@q@q@q@q@d@k@d@H@d@d@g@f@g@d@5@0@5@5@6@. . . . Z+} .#+#@###$#L@%#M@O@O@&#P@P@n@n@*#=#S@&.}+% 6.-+> > . . -#T@;#U@>#z@,#X@Y@'#@.#.)#!#H I I I $.K m 7 7 7 9 9 T.< q q } } D.r+4.* 5.. ", +" . ~#~#~#{#~#E@E@E@]#G@^#^# #p@q@q@q@j@k@j@k@d@d@d@d@0@0@e@l@0@5@/#(#_#:#<#.#[#}#K@K@L@M@|#O@#2#3#4#4#x@R@5#6#% }+v . . 7#8#9#0#a#U@T@U@U@,#b#X@c#'.#.#.)#H 3.I l $.$.m m 7 7 M 9 9 < 0 q D@} *+| | . ", +" . d#e#f#~#~#~#g#h#{#{#E@i#E@E@q@F@p@]#q@q@q@q@q@j@d@k@d@d@d@j#k#l#m#n#o#:#:#p#+#}#q#$#$#$#M@M@u@v@1#r#s#3#t#u#v#5#w#x#. . y#z#A#B#C#D#a#E#F#G#V@z@H#X@I#'.@.#.#.H H B.I $.$.0+K :+7 M M : : < q q ' } . ", +" . J#K#K#K#K#L#~#~#~#~#~#~#{#{#i#E@E@^#]#G@]#q@q@^#q@I@H@M#M#N#O#k#k#l#P#Q#_#R#:#S#[#[#J@$#$#T#T#u@U#1#1#P@3#t#t#u#V#W#X#Y#Z#`# $y#z#7#7#D#D#-#.$U@U@+$z@@$H#'#'.2.2.#.p+j.I I l $.%.m m 7 7 9 ].< C.q . ", +" . #$J#K#$$$$%$K#K#L#K#L#f#~#f#~#~#`@`@E@E@E@E@E@E@q@&$*$=$=$-$-$;$O#>$>$,$,$Q#:#:#S#S#'$q#J@$#$#T#)$!$U#1#1#s#~$t#t#{$W#]$^$^$/$($`#_$y#:$7#9#D#<$a#E#U@+$[$b#X@X@A@'.2.#.p+H H B.!.!.~._+m }$7 a+9 ].. ", +" . =@|$#$#$#$1$2$K##$%$K#K#L#e#f#e#~#L#~#~#~#{#3$4$5$6$7$7$8$&$*$-$-$9$9$>$0$0$P#P#Q#S#S#'$'$'$a$b$T#c$!$!$#2#3#d$e$f$g$]$^$^$h$/$i$`#j$k$y#7#7#l$<$m$E#;#U@+$z@z@H#'.'.@.#.#.i.H q+I J $.K K :+C+7 . ", +" . n$o$p$=@o$q$#$q$#$#$#$J##$$$%$$$K#K#e#e#r$s$s$t$4$5$5$u$v$7$w$w$w$-$x$9$>$>$0$y$P#z$A$B$'$'$'$C$b$T#D$D$!$E$#F$F$G$H$I$J$K$^$L$Y#h$($($`#`#y#y#M$7#C#D#E#E#N$U@>#z@b#X@'#'.z.#.#.p+H j.!.O$K 0+m . ", +" . P$P$n$=@=@=@=@p$p$o$#$#$#$#$#$Q$K#Q$R$R$S$T$r$s$t$t$U$5$6$V$6$w$w$W$x$-$X$;$>$0$y$y$z$z$Y$Z$`$'$ % %.%T#T#!$u@+%@%#%$%%%&%*%=%J$K$-%;%>%>%($,%'%`#`#y#z#7#)%D#0#E#;#N$U@z@,#@$X@Y@'.S.#.o@H I j.I J . ", +" . !%!%~%P${%!%n$!%=@=@=@=@=@p$#$]%^%/%/%/%(%S$T$_%:%s$<%t$5$5$5$6$u$7$w$w$-$X$X$>$[%>$y$y$Y$Y$A$`$}%C$ %.%.%|%1%+%+%2%3%4%$%%%*%5%I$J$K$^$;%>%6%7%,%8%9%0%k$:$7#8#8#D#a%E#.$U@[$z@z@X@Y@Y@S.@.#.A.H q+. ", +" . b%b%c%b%d%d%!%!%!%e%f%e%n$g%g%g%^%h%h%i%j%/%R$R$T$_%:%s$k%U$U$4$6$u$V$w$7$w$x$X$X$l%l%0$m%n%z$A$o%`$p%q%.%.%|%r%+%s%2%2%3%t%u%v%*%5%J$]$w%L$x%y%6%7%,%'%z%A%`#y#B%7#l$l$D#E#E#T@[$C%z@H#X@A@I#z.#.A.. ", +" . D%E%F%F%b%b%G%b%~%~%H%I%I%I%J%J%J%g%I%I%g%]%(%R$_%R$T$T$K%k%K%U$L%M%N%u$w$O%P%Q%X$X$X$[%R%0$n%n%z$Y$Z$Z$S%q%T%|%U%V%W%s%X%3%t%4%u%v%*%Y%J$J$Z%;%;%y%y%`%8% &9%.&`#+&y#7#7#B#D#0#E#E#U@U@@&#&W@X@B@&+. ", +" . $&E%E%E%%&E%&&b%b%*&=&-&;&I%;&I%>&I%I%I%I%g%h%]%/%,&_%_%'&'&k%k%L%U$M%)&N%u$!&O%x$x$W$X$~&~&{&{&0$]&z$Y$Z$Z$T%.%^&/&U%W%s%(&2%_&3%:&u%v%<&[&}&K$K$;%>%y%y%,%8%9%9%z%|&`#y#:$7#7#C#m$E#E#.$U@U@z@@$X@. ", +" . 1&$&E%2&3&4&5&6&6&*&7&6&=&=&*&=&>&-&8&-&I%I%J%g%h%]%,&(%R$_%9&9&'&k%0&L%)&)&u$v$O%!&W$P%W$X$~&~&[%a&z$Y$b&o%c&.%d&d&e&/&U%W%s%X%2%3%t%f&f&g&<&<&h&i&Z%Z%j&y%y%k&l& &m&.&|&n&0%y#z#A#)%D#<$E#;#T@>#@&. ", +" . o&1&1&1&p&p&q&q&p&6&6&6&6&6&*&*&r&8&7&=&8&8&I%;&s&g%]%]%]%,&,&_%9&'&:%K%L%L%U$t&)&!&!&!&W$P%u&v&~&[%{&{&a&Y$w& %T%T%x&y&y&U%z&A&A&B&C&D&D&E&v%v%v%F&G&i&Z%H&x%I&J&K&8%9%m&.&|&L&M& $y#M$7#8#D#m$a%U@. ", +" . N&o&O&O&P&Q&q&q&p&6&q&q&6&6&5&6&6&6&6&=&7&*&*&=&;&;&g%R&^%^%,&,&S&T&T&U&U&k%L%L%M%N%V&W&O%!&X&u&v&Y&v&{&m%m%Z&C$Z&`&c&x&x&y&y& *.*+*s%2%C&D&t%@*f&v%<&#*G&$*%*H&x%y%`%l&8%9%m&A%&*n&**=*y#y#7#7#9#m$. ", +" . -*-*P&O&P&P&P&P&O&p&;*Q&p&p&p&q&q&5&6&q&6&6&6&6&*&=&=&>*s&s&,*'*,&)*S&T&T&!*k%k%L%M%M%V&t&!&O%P%P%X&Y&v&v&{&~*'$~*{*]*]*c&x&x&^*^& *+*/*(*_*D&t%:*E&<*[*F&#*G&$*%*}*I&I&`%K& &9%m&&*|*n&**1* $y#2*2*. ", +" 3*4*5*-*-*-*-*O&-*P&O&P&6*P&P&Q&p&p&q&p&6&5&q&6&6&6&q&6&*&7*7*>*s&,*8*8*9*S&T&U&0*U&a*b*M%M%V&W&W&c*c*X&X&Y&d*e*'$f*g*h*{*]*i*j*x&x&k* * *l*(*(*_*C&m*@*f&n*[*F&#*G&o*%*}*p*q*r*K&s*t*m&&*|*u*v*w*x*k$. ", +" 3*y*z*4*4*A*-*-*-*-*-*-*P&P&P&O&P&p&p&P&P&;*B*p&p&q&q&q&6&6&7&=&C*7*,*8*8*8*9*T&D*E*!*a*a*F*G*H*V&I*W&W&c*J*~*K*'$L*M*f*g*h*N*]*i*c&x&^*y&O* *l*P*(*Q*R*m*S*E&<*T*F&U*G&V*W*X*X*q*r*l&s*Y*Z*`*|***** =.= ", +" +=y*@=@=#=4*4*4*5*$=%=-*-*-*-*O&O&P&-*P&P&Q&Q&P&q&p&;*q&q&q&7&q&7&C*s&,*,*'*8*9*&=*=D*!*U&a*F*G*M%V&t&W&W&==c*I*S#-=;=L*>=,='=)=h*]*i*j*j*^*O*!=~=/*{=]=Q*^=S*S*<*<*T*F&/=o*(=W*X*X*J&r*_=s*:=`*I$<=-%.= ", +" +=[=}=}=[=y*@=y*z*|=z*4*1=1=-*$=-*%=-*-*-*P&P&-*P&P&P&Q&p&q&q&p&q&7&7&C*7*,*,*8*8*D*&=D*!*!*a*a*a*F*G*V&2=W&3=4=:#5=-=-=6=7=>=8=9=h*0=a=b=c=^*O*O*!=l*d={=e=R*R*R*S*E&n*F&U*U*f=o*W*g=X*h=r*G$G$&%H$I$i= ", +" j=k=l=m=l=}=}=}=}=[=@=#=@=4*#=n=1=$=o=-*1=p=-*-*P&q=-*q=-*P&O&O&;*q&6&r=C*7*7*s=t=u=&=v=9*D*0*0*a*a*F*w=w=w=2=x=:#y=z=A=B=B=6=8=C=D='=h*N*E=F=F=G=^*H=H=l*d={=I=e=R*J=K=L=L=M=N=U*o*O=P=4%Q=R=R=G$*%H${$ ", +" j=S=T=k=U=k=V=k=k=}=m=[=[=@=@=y*y*@=n=W=1=X=X=$=-*-*p=-*-*-*q=-*-*O&;*;*7&7&7&C*t=t=Y=v=&=&=*=D*D*0*a*Z=G*`= -5=_#.-+-@-#-$-%-B=&-6=7=,=*-N*=-E=----;-O*O* *l*>-d=]=,-J='-'-L=n*N=)-B&X%X%_&_&!-Q=R=R=~- ", +" j={-S={-S=S=T=S=T=k=k=V=k=V=l=[=[=[=y*y*y*n=n=o=o=n=$=p=1=%=%=$=-*-*P&O&;*;*]-r=r&C*^-t=t=/-&=/-0*0*0*0*Z=`=F*(-_-:-<-.-[-#-A=}-$-|-&-1-2-*-3-4-0=E=5-6-;-f$7-8-l*d=9-]=,-J=0-U%a-z&W%W%s%2%2%2%_&3%4%F$ ", +" b-c-c-c-d-{-d-{-S=S=S=S=T=T=k=k=V=k=V=}=[=[=y*@=n=o=e-n=1=o=1=$=p=%=-*-*P&O&;*r=]-7&f-g-t=t=Y=h-&=D**=0*0*i-j-k-(#l-m-n-.-[-@-#-o-$-p-B=&-q-2-2-3-4-r-E=5-;-G=f$H=s-8-d=x&x&y&y&q%U%U%z&W%s%s%X%2%_&2%F$ ", +" t-c-u-c-c-c-v-d-{-w-{-w-S=x-S=S=S=U=k=l=k=k=V=}=}=[=e-e-e-W=e-e-o=o=n=$=$=-*y-O&;*]-]-z-C*g-^-Y=Y=A-&=B-B-C-i-D-n#E-F-l-G-H-.-.-@-I-}-}-B=J-1->=2-3-K-4-r-5-L-6-M-f$]*]*i*c&j*x&^*^*y&e&q%z&z&N-A&s%B&+% ", +" t-O-u-u-u-u-P-Q-c-c-c-v-c-R-{-S-{-S=S=T=S=k=S=k=k=T-}=m=}=e-e-e-e-e-n=1=n=$=$=y-U-6*V-W-X-f-f-g-Y-Z-A-/-B-B-`- ;/#.;+;@;l-#;H-H-.-[-I-I-}-$;p-J->=>=2-%;4-&;r-,=3-,={*Z&]**;a=i*c&=;x&-;y&!=/&U%a-+*s%+% ", +" t-;;>;,;;;O-u-u-';Q-u-Q-Q-P-c-d-);d-);w-!;S=S=U=T=T=k=T=k=V=}=l=e-~;e-e-e-n=$={;y-$=y-U-V-];]-f-f-Y-^;Z-/;/;/;(;_;:;.;.;<;@;l-[;};n-.-|;I-1;}-$;2;J-3;4;%;6=6=6=8=8=,=3-3-h*]*a=a=i*c&j*x&x&^&!=y&U%+*+% ", +" 5;6;;;;;;;;;;;7;8;O-u-O-O-';';';';Q-c-c-);{-);w-{-{-S=k=S=U=T=k=V=k=m=e-e-~;e-e-{;1={;U-U-];V-];9;9;g-Y-^;^;/;0;_;a;a;:;.;.;b;@;[;G-H-c;[-|;I-d;$;$;J-o-}-B=B=|-&-6=8=8=,=9=3-h*0=]*`&e;a=c&x&d&^&^&y&|% ", +" f;g;g;h;h;i;j;j;;;;;8;>;k;O-u-u-O-c-u-u-';c-c-c-);c-d-w-w-S=S=S=S=T=U=k=k=V=l;l;~;m;e-1=n;o;V-U-];p;9;g-q;g-0;r;s;t;u;u;:;:;.;v;+;b;[;};w;w;x;y;[-|;|;I-o-z;}-$-%-B=&-6=6=8=8=,=*-h*h*0=]*]*i*j*j*j*x&|% ", +" f;A;B;g;g;g;g;g;h;j;6;6;;;k;;;;;O-;;O-k;u-u-c-Q-';';';c-v-);c-w-);d-S=S=U=S=S=T=S=l;~;m;{;{;C;y-y-V-];9;p;p;g-D;s;E;F;G;H;I;:;:;J;<;<;K;[;L;L;H-H-M;y;[-|;I-I-}-}-$-%-p-B=6=6=C=7=8=,=)=h*N;0=]*]*i*c&|% ", +" f;O;P;Q;R;P;Q;S;g;g;g;g;g;i;j;j;;;;;;;;;7;k;O-O-u-u-u-P-';P-u-c-c-);d-w-S={-S=!;S=S=U=k=~;{;{;n;y-o;U-T;p;p;p;U;V;W;X;Y;Y;G;Z;u;:;`;J; >b;b;.>[;};H-n-n-c;[-[-I-#-#-o-$-$-p-|-&-6=6=q-8=8=9=9=h*h*0=]*+> ", +" @>O;#>O;$>#>O;P;P;P;P;S;g;g;g;g;i;h;j;6;6;6;;;;;;;,;>;k;u-u-u-u-';u-';c-c-c-);{-);{-{-S-S=S=U=%>{;&>&>o;*>W-=>U;->;>>>,>'>Y;)>)>!>`;J;~>~>{>{>K;@;]>[;G-H-M;w;y;|;[-@-I-d;z;$-p-B=B=|-6=6=M*8=9=9=h*h*.% ", +" ^>/>(>_>(>_>_>O;O;O;$>O;A;A;P;P;S;R;g;g;i;i;i;6;6;;;;;;;;;k;k;u-O-u-O-u-Q-u-c-c-';c-c-);w-d-S=S-S-:><>n;[>[>o;}>|>1>2>3>W;'>'>)>4>5>6>7>8>J;~>~>{>{>b;K;[;[;H-H-.-c;y;[-[-#-#-}-}-p-$-B=|-&-6=>=8=,=,=.% ", +" 9>0>0>0>a>a>(>/>_>_>#>b>O;O;P;$>P;P;P;Q;g;S;c>g;g;h;i;d>j;6;e>;;;;;;k;u-;;O-u-O-Q-Q-';c-';c-);););{-S-S=n;n;[>f>|>g>g>2>'>h>h>h>h>i>)>!>7>7>8>`;`;~>~>b;b;K;.>[;[;m-w;w;c;.-[-j>I-#-z;}-k>B=B=B=&->=>=.% ", +" 9>l>m>n>0>0>0>0>a>o>(>(>_>_>p>#>p>O;O;P;P;Q;P;Q;g;g;g;g;i;g;i;h;e>j;q>;;;;;;8;7;8;>;u-O-u-u-O-';r>c-c-););w-);s>|>t>u>v>3>w>,>,>'>h>x>)>i>y>5>z>7>`;`;A>~>B>{>K;b;[;L;};H-<-w;c;[-|;#-I-#-}-}-$-B=B=C> % ", +" D>E>F>m>m>m>G>0>0>n>0>0>0>o>_>o>(>_>_>#>#>#>O;#>P;P;P;A;P;B;g;B;g;i;H>i;i;6;;;h;;;;;8;7;O-O-O-u-u-Q-I>';Q-c-c-J>K>L>M>N>O>u>v>w>P>w>Q>R>S>h>)>)>4>!>7>6>`;`;J;~>b;{>b;.>K;[;T>H-U>c;c;[-|;@-#-#-$-}-V> % ", +" W>X>E>E>m>Y>m>Y>Z>`>n>0>0>0>l>0>0>0>(>0>(>/>(>_>_>#>#>O;P;P;P;P;A;B;A;R;g;g;g;j;i;i;i;;;;;;;;;;;8;k;8;O-u-O-u- ,K>.,+,@,M>M>#,u>v>3>P>,>Q>$,$,h>)>i>%,4>6>7>6>`;J;~>~>+;b;]>]>[;L;H-w;w;y;.-[-|;#-#-o-'$ ", +" &,X>X>*,X>X>X>X>E>E>=,m>`>m>`>l>-,l>n>0>0>0>;,;,a>o>(>_>_>O;P;#>#>P;O;P;c>B;P;c>B;g;i;i;i;6;;;e>6;;;7;;;,;O-O->,_;,,',.,),!,L>N>N>#,v>v>~,w>w>w>h>h>{,i>y>4>4>7>6>:;`;J;~>{>{>b;]>.>[;L;w;w;c;[-.-[-#-'$ ", +" &,],],],],^,*,],/,X>X>E>E>E>Y>m>m>m>`>n>`>l>G>l>0>0>0>(,;,o>(>_>(>#>O;p>#>#>P;P;P;c>A;S;g;g;g;g;i;j;i;;;;;6;;;_,s;:,<,[,},.,),+,|,L>M>N>#,v>v>P>w>w>$,h>h>S>)>)>4>7>7>6>`;A>~>{>b;b;b;]>.>[;L;w;H-c;[-'$ ", +" &,1,2,3,4,2,],],],5,^,^,X>X>E>E>E>F>6,E>Y>`>`>l>`>`>`>n>l>0>o>a>_>(>_>_>_>#>p>O;O;P;$>P;P;P;g;c>g;c>g;g;i;q>i;7,s;8,8,9,:,[,[,',),.,),M>N>N>N>v>v>v>w>w>,>Q>$,Y;i>)>y>!>5>6>:;`;`;~>{>{>b;K;[;[;};H-U>'$ ", +" 0,a,a,b,a,3,3,2,3,4,],],],*,^,],^,X>X>E>E>E>E>E>6,`>m>m>`>Z>G>`>l>0>0>0>a>_>(>p>(>#>#>#>$>P;#>P;P;P;P;P;B;g;i;c,s;d,e,f,8,:,<,:,[,[,',',),@,M>N>M>#,g,v>h,P>w>'>$,h>S>)>y>y>4>6>7>`;`;~>B>b;b;b;]>[;L;S# ", +" i,j,k,k,b,j,b,a,3,3,3,2,l,3,],l,],],*,/,/,X>m,E>X>Y>Y>=,F>F>F>m>-,-,l>n>`>0>0>0>o>o>o>p>(>#>p>#>#>b>O;P;n,P;c>c,V;o,p,q,e,r,r,s,9,9,<,,,},.,.,+,L>M>M>N>O>v>v>3>w>Q>'>h>h>{,)>y>4>4>6>6>`;`;~>~>b;b;b;S# ", +" t,u,u,j,v,k,k,j,k,a,w,a,b,a,a,3,1,4,x,],l,],],/,X>X>^,y,E>Y>=,=,m>z,`>`>m>l>n>n>l>0>G>0>0>o>(>/>_>#>#>#>O;$>$>A,V;B,C,o,p,D,e,e,r,8,E,9,<,[,},',.,.,!,M>M>F,O>O>~,3>P>w>$,Q>h>S>Y;G,y>4>7>6>8>`;J;~>~>:# ", +" t,H,I,u,u,J,u,j,j,K,k,j,j,k,k,b,b,a,a,3,1,4,4,],4,],],/,/,^,X>/,*,E>E>E>E>`>m>`>`>`>`>m>0>-,0>0>0>0>(>/>_>/>p>L,|>M,N,N,C,O,P,Q,D,e,f,e,8,9,9,<,[,',.,),),|,M>N>N>u>u>v>P>w>w>,>$,h>S>)>y>4>4>7>:;8>`;R, ", +" S,T,H,H,I,U,V,V,u,v,W,u,X,j,k,k,b,b,b,b,a,a,a,3,3,3,Y,x,x,],],],],],X>X>E>E>E>E>=,F>`>`>z,`>m>`>0>G>l>0>0>0>0>L,|>Z,`, '.'N,N,+'o,P,P,e,e,@'8,9,8,:,<,[,,,#'),),M>M>F,N>u>v>3>w>,>,>h>h>h>S>i>y>4>4>6>:# ", +" S,$'%'%'T,T,I,U,I,V,U,H,u,u,J,J,u,v,v,j,j,k,b,b,a,a,b,3,3,1,l,3,],l,x,*,],*,*,/,m,X>m,E>F>Y>`>z,m>m>`>`>m>-,G>&'|>*'Z,Z,Z,=' 'M,N,B,-'o,o,d,D,e,;'8,8,9,>'[,,,',),),+,M>M>N>N>v>v>h,w>$,h>h>h>{,)>)>%,:# ", +" ,''''''''')')')'!')'I,T,T,I,H,u,u,u,u,v,W,v,j,j,j,j,k,~'~'{'a,3,3,3,2,x,4,],],],],/,*,y,/,X>m,E>z,E>F>F>Y>`>`>]'|>^'/'('*'Z,_':'M,M,M,N,o,o,<'P,D,D,e,8,s,9,:,<,[,['.,.,),M>@,M>#,O>}'v>3>w>w>h>h>h>S>_# ", +" |'1'2'3'4'''''''5'''%'T,)'T,T,I,H,u,I,6'u,u,u,v,u,u,X,v,j,j,j,7'b,a,a,b,3,3,3,Y,l,],Y,],*,*,*,*,*,X>X>E>E>E>Y>8'|>9'9'0'a'('('b'*'Z,='M,N,c'B,o,o,Q,P,Q,q,e,8,8,9,<,<,[,.,.,),),M>M>F,N>d'u>h,w>w>,>$,o# ", +" e'f'g'1'1'1'2'h'4'''4'''''''%'%'%'I,T,T,I,T,u,6'u,u,u,u,J,v,j,J,j,k,k,j,i'b,a,a,3,3,2,],4,x,],],],],^,/,/,*,X>j'k'l'l'm'n'o'p'/'('('*'_'Z,='M,q'.'-'r'o,Q,D,e,e,8,8,8,9,<,[,',',s'),L>M>M>N>O>v>3>3>w>/# ", +" t'u'v'v'e'w'x'w'1'y'1'3'3'4'4'''''5'%''')')'T,T,T,T,I,u,u,u,u,u,v,J,K,j,v,k,k,b,b,a,a,b,3,3,3,3,1,l,l,],*,*,],z'A'B'C'D'l'l'9'n'0'^'('('E'*'_'='='='F'N,O,o,P,P,P,D,e,f,8,9,:,[,[,,,.,),L>@,M>N>O>u>u>G' ", +" H'I'J'K'K'v'g'L'L'w'w'M'1'1'y'''3'N'2'''%'%'%')'%'T,T,T,T,I,T,I,u,H,u,u,u,u,j,j,k,~'b,b,~'7'3,7'3,3,3,2,1,Y,O'P'Q'R'S'B'B'l'l'o'o'T'0'p'('*'E'_' 'U'='.'N,N,O,o,D,e,D,e,f,8,8,:,V'[,[,.,',),@,|,M>/#W' ", +" X'Y'Z'`'`' ) ) )g'L'.)L'+)1'w'1'1'3'1'2'''''''''%'%'%'!')'T,)'I,T,H,@)u,H,u,u,u,J,j,j,j,k,k,b,b,a,a,b,a,3,#)P'$)%)&)R'R'S'B'D'l'l'9'9'0'0'p'('*)Z,Z, 'U'='.'N,N,r'P,D,P,D,@'e,8,s,9,<,[,=)',),@,-) ", +" ;)>),)`'`'`'`'') )g'.).).)L'))w'w'))w'1'1'4'1'3'4'N'''''%'%')'%'T,T,T,T,I,T,V,H,u,u,u,u,K,v,J,J,k,~'b,~'!)~){)])^)/)/)()R'_)S'B'l'l'm'9'n'0'('('('b'Z,Z,=' 'M,N,N,C,o,o,p,e,e,e,8,8,9,:,<,[,_;:) ", +" <)[)})`'`'`'`'`' ) ) )|)1).).)L'L'L'L'L'w'))1'1'1'3'2'3'h'h'''%'%')')'T,!'T,T,T,T,6'u,u,H,u,u,u,j,J,j,2)P'3)4){)5)5)$)$)Q'Q'S'S'B'D'6)l'T'o'o'0'0'('('*)Z,Z,M,M,.'N,-'o,o,o,P,d,e,;'8,8,:,K> ", +" 7)8)9)0)J'`'`'`'`'`' ) )a)b)c)d).).)d).)L'.)e)1'))x'1'1'1'4'''''''''%'%')'%'!')')'I,I,U,U,V,u,I,u,u,f)g)h)i)j)4)k)l)5)])$)&)&)m)S'B'D'n)6)l'9'n'o'0'p'('E'_'o)Z,M,.'F'N,r'o,P,o,e,D,p)s;q) ", +" r)X's)t)u)v)`'`'`'`'K'w)K'a)b)b)x)1).).).).).)L'w'))))1'1'1'3'1'N'1'4'''y)''%')')'T,T,T,T,6'I,V,z)g)A)A)B)h)i)i)l){){)$)$)/)C)()R'S'B'B'C'l'm'9'o'0'a'D)('_'Z,_'M,='F'N,N,r'o,P,E)s; ", +" F)G)H)I)J)`'`'`'`'`'w) )w)b)b)b)c)K)L)d).).)d).)L'))))w'e)e)1'1'y'2'''4'4'%''')'%'M)T,T,T,N)O)P)A)A)Q)B)B)R)j)j){)5)5)5)$)$)Q'&)S'S'B'D'l'l'9'0'0'p'p'('('*'Z,:'M,F'M,N,-'V;S) ", +" T)U)I'V)J'`'`'`'`'w)w)w)W)c)c)b)c)c)c)L)b)d).).).)X)L'+)w'e)e)1'1'1'h'2'4'''''%')'%'Y)Z)`) !.!P)A)A)A)B)i)j)4)4)4)4)5)$)$)/)Q'&)S'S'B'D'l'm'9'0'0'p'a'('*'_'Z,Z,:'M,V; ", +" r)+!s)t)u)v)`'`'`'`'w)w)@!W)b)b)b)c)b)c)b)L)K).).)d)d)L'L'L'w'w'1'e)1'1'1'3'4'''#!Z)$!$!%!&!.! ! !P)A)*!B)=!i)l)l)4)5)5)$)$)Q'R'S'S'B'6)l'l'l'9'n'0'D)('*)E'_'|>-! ", +" ;!>!s),!'!)!`'`'`'`'!!w)W)b)~!b)b)b)c)b)b)b)c)b)K).).)L'.).)L'))))e)+)1'1'{!]!^!/!$!$!%!%!&!.! !P)(!Q)B)B)h)j)l){)5)^)$)$)Q'&)R'S'S'B'D'6)m'm'9'9'p'|>|>_! ", +" :!)[!}!`'`'`'`'!!!!!!|!~!~!~!c)b)b)c)c)b)b)c)K)x)L).)1).)X)L'L'))1!2!3!3!4!^!/!/!$!%!5!&!.!.! !A)A)B)h)i)i)l)4)5)5)$)$)%)R'&)R'S'B'n)l'k'6!7! ", +" 8!9![)0!a!b!`'`'`'`'!!!!!!|!~!~!b)~!c)c)b)b)b)c)b)c)c)L)d).).).)c!2!d!e!3!f!4!4!g!/!%!`)`)&!.!.!P)A)h!B)B)i)i!4)4){)5)])$)$)%)&)S'k'j!k! ", +" l!H's)m!n!o!`'`'`'`'!!!!|!~!~!~!~!p!b)b)c)c)b)b)b)b)b)b)K)q!2!r!r!s!e!e!3!3!4!4!/!/!`)%!`)`).!P)t!A)Q)B)u!i)j)l)l)4)5)5)P'v! ", +" w!x![)y!z!`'`'`'`'!!!!!!A!~!~!~!~!~!p!~!b)b)c)b)b)c)q!2!B!B!B!B!r!C!e!e!3!f!D!4!/!$!%!`)E!.!.!P)A)F!B)B)G!R)P'P'H! ", +" I!>)J!K!L!`'`'`'`'!!!!|!~!~!~!~!~!~!~!b)~!b)c)M!2!B!B!B!B!B!r!r!N!C!e!3!O!3!4!^!/!/!%!P!`).!.!t!(!Q!g)R! ", +" S!T!s)U!V!o!`'`'`'!!!!!!|!W!~!~!W!~!~!~!~!X!2!B!B!B!B!B!B!B!r!B!r!Y!e!Z!e!`!D!4!^!$!$!%!5!Z)O) ~ ", +" .~+~@~I)#~`'`'`'`'!!!!A!|!W!~!W!W!W!X!2!B!B!B!B!B!B!B!B!B!B!r!r!r!r!e!Z!3!D!D!g!Z)O)$~ ", +" %~8)u'&~L!`'`'`'`'!!!!|!W!~!W!X!2!B!B!B!B!B!B!B!B!B!B!B!B!B!B!r!r!d!3!2!*~=~ ", +" -~T!s);~>~v)`'`'`'!!!!!!A!X!2!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!2!,~'~ ", +" )~t)s)!~~~)!`'`'`'!!{~2!B!B!B!B!B!B!B!B!B!B!B!B!B!B!2!,~]~ ", +" :!U)U)^~/~`'`'`'(~2!B!B!B!B!B!B!B!B!B!B!B!2!_~ ", +" :~<~@~+~[~b!`'}~2!B!B!B!B!B!B!B!B!2!|~ ", +" 1~2~3~,!'!4~2!B!B!B!B!B!2!5~ ", +" 6~x!@~7~2!B!8~2!9~ ", +" 0~a~2!b~ ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/src/Mod/Ship/Icons/Weight.png b/src/Mod/Ship/Icons/Weight.png new file mode 100644 index 0000000000..b613fa569e Binary files /dev/null and b/src/Mod/Ship/Icons/Weight.png differ diff --git a/src/Mod/Ship/Icons/Weight.xcf b/src/Mod/Ship/Icons/Weight.xcf new file mode 100644 index 0000000000..e10ea8e991 Binary files /dev/null and b/src/Mod/Ship/Icons/Weight.xcf differ diff --git a/src/Mod/Ship/Icons/Weight.xpm b/src/Mod/Ship/Icons/Weight.xpm new file mode 100644 index 0000000000..7d17453db4 --- /dev/null +++ b/src/Mod/Ship/Icons/Weight.xpm @@ -0,0 +1,721 @@ +/* XPM */ +static char * Weight_xpm[] = { +"128 128 590 2", +" c None", +". c #5F5F5F", +"+ c #606060", +"@ c #60605F", +"# c #5F6060", +"$ c #616160", +"% c #606161", +"& c #616161", +"* c #626262", +"= c #626261", +"- c #616162", +"; c #616261", +"> c #767576", +", c #90908F", +"' c #A1A2A2", +") c #ACACAC", +"! c #A1A1A1", +"~ c #8F8E8F", +"{ c #777776", +"] c #636363", +"^ c #636364", +"/ c #636263", +"( c #636362", +"_ c #767676", +": c #9D9D9D", +"< c #B0B0B1", +"[ c #B1B1B0", +"} c #B0B0B0", +"| c #AFAFAF", +"1 c #9C9C9C", +"2 c #767777", +"3 c #656565", +"4 c #646463", +"5 c #868787", +"6 c #AFAFB0", +"7 c #AEAEAE", +"8 c #ADAEAE", +"9 c #ADADAE", +"0 c #868687", +"a c #666667", +"b c #676766", +"c c #656665", +"d c #7B7B7C", +"e c #AFAEAE", +"f c #ACADAC", +"g c #ACACAB", +"h c #7C7C7C", +"i c #686867", +"j c #686868", +"k c #666767", +"l c #A0A0A0", +"m c #ADADAD", +"n c #ADADAC", +"o c #ABAAAA", +"p c #ABABAA", +"q c #9E9E9E", +"r c #6A6969", +"s c #696969", +"t c #676768", +"u c #676868", +"v c #7F7F7F", +"w c #ABABAC", +"x c #A9A9A9", +"y c #A8A8A9", +"z c #80807F", +"A c #6B6B6B", +"B c #6B6C6B", +"C c #696A69", +"D c #939394", +"E c #AAAAAA", +"F c #A7A8A8", +"G c #A8A7A8", +"H c #929292", +"I c #6D6C6D", +"J c #6D6D6D", +"K c #6A6A6A", +"L c #A6A6A6", +"M c #9D9E9E", +"N c #6D6E6E", +"O c #6E6E6D", +"P c #6C6C6C", +"Q c #A0A09F", +"R c #A8A7A7", +"S c #A4A4A5", +"T c #706F6F", +"U c #706F70", +"V c #6D6E6D", +"W c #A6A5A6", +"X c #A3A3A3", +"Y c #919191", +"Z c #717070", +"` c #707171", +" . c #6F6F6F", +".. c #6F6F6E", +"+. c #818281", +"@. c #A4A4A4", +"#. c #A2A2A2", +"$. c #A2A2A1", +"%. c #727272", +"&. c #707071", +"*. c #717071", +"=. c #9A9A9A", +"-. c #A2A2A3", +";. c #A0A1A0", +">. c #989897", +",. c #737473", +"'. c #737474", +"). c #727172", +"!. c #808080", +"~. c #9F9F9F", +"{. c #9E9F9F", +"]. c #808181", +"^. c #747574", +"/. c #757575", +"(. c #737373", +"_. c #737374", +":. c #888888", +"<. c #A09FA0", +"[. c #9F9FA0", +"}. c #A09F9F", +"|. c #878888", +"1. c #767675", +"2. c #949494", +"3. c #9D9D9E", +"4. c #9D9C9C", +"5. c #9C9C9D", +"6. c #787778", +"7. c #777778", +"8. c #777777", +"9. c #8C8C8C", +"0. c #999A99", +"a. c #818181", +"b. c #797878", +"c. c #797879", +"d. c #605F60", +"e. c #605F5F", +"f. c #606160", +"g. c #616061", +"h. c #626162", +"i. c #616262", +"j. c #636262", +"k. c #626363", +"l. c #636463", +"m. c #646464", +"n. c #646564", +"o. c #646465", +"p. c #656564", +"q. c #656666", +"r. c #666666", +"s. c #666565", +"t. c #676666", +"u. c #676767", +"v. c #686768", +"w. c #686767", +"x. c #696869", +"y. c #5F5F60", +"z. c #616060", +"A. c #626161", +"B. c #626263", +"C. c #636464", +"D. c #656464", +"E. c #656566", +"F. c #696868", +"G. c #6A6A69", +"H. c #69696A", +"I. c #B3B3B3", +"J. c #B3B2B2", +"K. c #B2B2B2", +"L. c #B2B2B1", +"M. c #B2B1B1", +"N. c #B1B1B1", +"O. c #B0B1B1", +"P. c #AFB0AF", +"Q. c #AEAFAF", +"R. c #ACADAD", +"S. c #ABABAB", +"T. c #AAABAA", +"U. c #AAA9AA", +"V. c #6B6B6A", +"W. c #6B6C6C", +"X. c #6C6B6C", +"Y. c #B2B3B3", +"Z. c #B2B3B2", +"`. c #B2B1B2", +" + c #B1B2B1", +".+ c #B1B1B2", +"++ c #B1B0B0", +"@+ c #B0AFB0", +"#+ c #AFAEAF", +"$+ c #AEADAE", +"%+ c #ADACAC", +"&+ c #ACACAD", +"*+ c #ABACAC", +"=+ c #ACABAB", +"-+ c #AAAAAB", +";+ c #A9A9AA", +">+ c #A8A8A8", +",+ c #6D6C6C", +"'+ c #6C6D6D", +")+ c #B1B2B2", +"!+ c #B0B1B0", +"~+ c #AFB0B0", +"{+ c #AEAFAE", +"]+ c #AFAFAE", +"^+ c #AEADAD", +"/+ c #ACABAC", +"(+ c #A9AAAA", +"_+ c #A9A8A9", +":+ c #A7A7A7", +"<+ c #A6A7A6", +"[+ c #6E6E6E", +"}+ c #B1B0B1", +"|+ c #ADAEAD", +"1+ c #ADACAD", +"2+ c #A9A8A8", +"3+ c #A7A8A7", +"4+ c #A7A6A7", +"5+ c #A5A5A6", +"6+ c #A6A6A5", +"7+ c #A6A5A5", +"8+ c #A5A5A5", +"9+ c #6F6F70", +"0+ c #5F605F", +"a+ c #B3B2B3", +"b+ c #AAABAB", +"c+ c #A9AAA9", +"d+ c #A4A5A5", +"e+ c #A3A4A4", +"f+ c #A4A3A3", +"g+ c #A3A3A4", +"h+ c #B0AFAF", +"i+ c #AEAEAF", +"j+ c #A8A9A8", +"k+ c #A7A7A8", +"l+ c #A7A7A6", +"m+ c #A7A6A6", +"n+ c #A5A4A4", +"o+ c #A4A3A4", +"p+ c #A3A4A3", +"q+ c #A3A3A2", +"r+ c #B2B2B3", +"s+ c #AAAAA9", +"t+ c #A6A6A7", +"u+ c #A5A6A6", +"v+ c #A5A6A5", +"w+ c #A4A5A4", +"x+ c #A4A4A3", +"y+ c #A1A2A1", +"z+ c #A1A1A0", +"A+ c #737273", +"B+ c #747374", +"C+ c #AEAEAD", +"D+ c #A6A7A7", +"E+ c #A2A3A2", +"F+ c #A2A1A2", +"G+ c #A0A1A1", +"H+ c #A1A0A1", +"I+ c #A0A0A1", +"J+ c #747474", +"K+ c #B0B0AF", +"L+ c #ABACAB", +"M+ c #ABAAAB", +"N+ c #A5A4A5", +"O+ c #A3A2A3", +"P+ c #A2A1A1", +"Q+ c #9FA09F", +"R+ c #9E9F9E", +"S+ c #757676", +"T+ c #AAA9A9", +"U+ c #A5A5A4", +"V+ c #A2A3A3", +"W+ c #A1A1A2", +"X+ c #9F9E9E", +"Y+ c #9E9D9D", +"Z+ c #9C9D9D", +"`+ c #9D9D9C", +" @ c #777877", +".@ c #A8A8A7", +"+@ c #9FA0A0", +"@@ c #9F9E9F", +"#@ c #9D9E9D", +"$@ c #9C9D9C", +"%@ c #9B9C9C", +"&@ c #787879", +"*@ c #676867", +"=@ c #A9A9A8", +"-@ c #9E9E9D", +";@ c #9C9C9B", +">@ c #9B9B9B", +",@ c #9B9B9A", +"'@ c #9A9B9B", +")@ c #797A79", +"!@ c #797A7A", +"~@ c #7A797A", +"{@ c #686969", +"]@ c #9D9C9D", +"^@ c #9A9B9A", +"/@ c #999A9A", +"(@ c #999999", +"_@ c #999899", +":@ c #7A7B7B", +"<@ c #7B7B7B", +"[@ c #A3A2A2", +"}@ c #A1A0A0", +"|@ c #9E9E9F", +"1@ c #9C9B9C", +"2@ c #9C9B9B", +"3@ c #9A9A99", +"4@ c #9A999A", +"5@ c #989998", +"6@ c #989898", +"7@ c #979898", +"8@ c #989797", +"9@ c #979797", +"0@ c #7C7C7D", +"a@ c #6B6A6A", +"b@ c #6B6A6B", +"c@ c #000000", +"d@ c #9F9F9E", +"e@ c #9B9A9A", +"f@ c #9A9999", +"g@ c #989899", +"h@ c #969796", +"i@ c #969696", +"j@ c #7D7E7D", +"k@ c #7E7E7E", +"l@ c #9B9B9C", +"m@ c #999898", +"n@ c #979897", +"o@ c #969697", +"p@ c #969595", +"q@ c #959596", +"r@ c #959595", +"s@ c #959594", +"t@ c #959495", +"u@ c #7E7F7F", +"v@ c #6C6D6C", +"w@ c #9E9D9E", +"x@ c #979798", +"y@ c #969596", +"z@ c #969695", +"A@ c #949594", +"B@ c #939494", +"C@ c #949493", +"D@ c #939493", +"E@ c #807F80", +"F@ c #9B9C9B", +"G@ c #969797", +"H@ c #959696", +"I@ c #959494", +"J@ c #949394", +"K@ c #939393", +"L@ c #939293", +"M@ c #929392", +"N@ c #939292", +"O@ c #818282", +"P@ c #6E6F6F", +"Q@ c #989999", +"R@ c #979696", +"S@ c #939392", +"T@ c #929393", +"U@ c #919291", +"V@ c #919190", +"W@ c #828283", +"X@ c #828382", +"Y@ c #707070", +"Z@ c #9B9A9B", +"`@ c #9A9A9B", +" # c #949595", +".# c #929291", +"+# c #929191", +"@# c #919091", +"## c #909090", +"$# c #908F90", +"%# c #8F8F90", +"&# c #848383", +"*# c #838384", +"=# c #848484", +"-# c #717171", +";# c #999998", +"># c #979697", +",# c #909190", +"'# c #919090", +")# c #8F8F8F", +"!# c #8E8E8E", +"~# c #8E8F8E", +"{# c #858484", +"]# c #858585", +"^# c #727372", +"/# c #99999A", +"(# c #959695", +"_# c #949495", +":# c #949393", +"<# c #919292", +"[# c #908F8F", +"}# c #8F8F8E", +"|# c #8F8E8E", +"1# c #8E8F8F", +"2# c #8E8D8E", +"3# c #8E8D8D", +"4# c #8D8E8D", +"5# c #8D8C8D", +"6# c #8D8D8D", +"7# c #868686", +"8# c #747473", +"9# c #929192", +"0# c #909091", +"a# c #8D8E8E", +"b# c #8D8D8E", +"c# c #8C8D8D", +"d# c #8B8C8B", +"e# c #878787", +"f# c #878887", +"g# c #747475", +"h# c #747575", +"i# c #979796", +"j# c #8E8E8F", +"k# c #8E8E8D", +"l# c #8D8D8C", +"m# c #8B8C8C", +"n# c #8B8B8B", +"o# c #8A8B8B", +"p# c #8B8A8A", +"q# c #8A8A8A", +"r# c #888988", +"s# c #898989", +"t# c #8F9090", +"u# c #8D8C8C", +"v# c #8C8B8C", +"w# c #8B8B8A", +"x# c #8C8C8B", +"y# c #8A8A8B", +"z# c #89898A", +"A# c #898A89", +"B# c #8A8989", +"C# c #888788", +"D# c #8C8B8B", +"E# c #777878", +"F# c #8B8A8B", +"G# c #8A8B8A", +"H# c #8A898A", +"I# c #8A8A89", +"J# c #888989", +"K# c #898888", +"L# c #888887", +"M# c #868786", +"N# c #797978", +"O# c #797979", +"P# c #929293", +"Q# c #878788", +"R# c #878687", +"S# c #868586", +"T# c #858485", +"U# c #7A7A7A", +"V# c #898A8A", +"W# c #898889", +"X# c #888889", +"Y# c #888787", +"Z# c #878786", +"`# c #868685", +" $ c #858685", +".$ c #838483", +"+$ c #8F908F", +"@$ c #7B7C7C", +"#$ c #8C8C8D", +"$$ c #898988", +"%$ c #878686", +"&$ c #868585", +"*$ c #848585", +"=$ c #858584", +"-$ c #838383", +";$ c #828282", +">$ c #838282", +",$ c #7D7C7C", +"'$ c #858586", +")$ c #838484", +"!$ c #838382", +"~$ c #818182", +"{$ c #828181", +"]$ c #808180", +"^$ c #919192", +"/$ c #7E7D7D", +"($ c #8C8D8C", +"_$ c #838283", +":$ c #828383", +"<$ c #828281", +"[$ c #818180", +"}$ c #7F807F", +"|$ c #7E7E7F", +"1$ c #7E7F7E", +"2$ c #7F7E7F", +"3$ c #858686", +"4$ c #848384", +"5$ c #818081", +"6$ c #818080", +"7$ c #807F7F", +"8$ c #7F7F7E", +"9$ c #7F7F80", +"0$ c #909191", +"a$ c #8B8B8C", +"b$ c #848584", +"c$ c #848483", +"d$ c #7E7E7D", +"e$ c #7E7D7E", +"f$ c #7D7D7D", +"g$ c #828182", +"h$ c #7F8080", +"i$ c #7D7C7D", +"j$ c #7C7D7D", +"k$ c #7C7D7C", +"l$ c #7C7C7B", +"m$ c #7B7C7B", +"n$ c #7D7E7E", +"o$ c #7D7D7E", +"p$ c #7D7D7C", +"q$ c #7C7B7C", +"r$ c #7B7B7A", +"s$ c #7A7B7A", +"t$ c #7A7A7B", +"u$ c #7A7A79", +"v$ c #787979", +"w$ c #848485", +"x$ c #7F7E7E", +"y$ c #7C7B7B", +"z$ c #7A7979", +"A$ c #787878", +"B$ c #787777", +"C$ c #787877", +"D$ c #808081", +"E$ c #787978", +"F$ c #777677", +"G$ c #767776", +"H$ c #7B7A7A", +"I$ c #767677", +"J$ c #757576", +"K$ c #757475", +"L$ c #747373", +"M$ c #727373", +"N$ c #737372", +"O$ c #737272", +"P$ c #7B7A7B", +"Q$ c #757675", +"R$ c #757574", +"S$ c #717272", +"T$ c #717172", +"U$ c #777676", +"V$ c #70706F", +"W$ c #79797A", +"X$ c #757474", +"Y$ c #727271", +"Z$ c #727171", +"`$ c #6F6E6F", +" % c #767575", +".% c #6F6E6E", +"+% c #6E6F6E", +"@% c #6E6D6D", +"#% c #6D6D6E", +"$% c #6D6D6C", +"%% c #717271", +"&% c #6C6C6D", +"*% c #6B6B6C", +"=% c #717170", +"-% c #6F706F", +";% c #6E6D6E", +">% c #6C6C6B", +",% c #6A6B6B", +"'% c #6A6B6A", +")% c #707170", +"!% c #6F7070", +"~% c #6A6A6B", +"{% c #6E6E6F", +"]% c #696A6A", +"^% c #696968", +"/% c #686968", +"(% c #666766", +"_% c #6C6B6B", +":% c #676667", +"<% c #6A696A", +"[% c #656465", +"}% c #666566", +"|% c #666665", +"1% c #646565", +"2% c #646364", +"3% c #646363", +"4% c #989798", +"5% c #686869", +"6% c #626362", +"7% c #606061", +"8% c #B3B3B2", +"9% c #A8A9A9", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" . . + @ + # + ", +" + + $ + % & & & * * = ", +" - - ; > , ' ) ! ~ { ] ] ^ ", +" / ( _ : < [ < } } | | 1 2 3 3 ", +" 4 4 5 } 6 | | 7 7 8 9 0 a b ", +" 3 c d e 7 7 f ) g h i j ", +" k k l m n o p q r s ", +" t u v ) w x y z A B ", +" C s D o E F G H I J ", +" K A l x L M N O ", +" P P Q R S 1 T U ", +" V V H L W X X Y Z ` ", +" ...+.@.S #.$.+.%.%. ", +" &.*.=.-.X ;.l >.,.'. ", +" ).%.!.! ! ! ~.~.{.].^./. ", +" (._.:.<.[.}.~. q q q M |.1._ ", +" /./.v 2.q M 3.: : 4.5.H !.6.7. ", +" 2 { 8.!.9.2.0.2.9.a.b.b.c. ", +" . . . . . . . . . . . . . . . . . . . . . . . . . . d.. e.@ f.f.g.& & h.& = i.j.j.j.k.] ] l.4 m.n.o.p.3 3 q.r.s.r.r.t.t.u.u.j v.w.j j x. ", +" . . . . . . . . . . . . . . . . . . . . . . . @ d.y.+ z.z.f.$ & A.A.= * * j.B.] ] C.m.4 m.m.D.p.p.3 E.E.r.r.t.r.u.u.u.u t i j j x.F.s s G.H.K K ", +" . . . . I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.J.K.K.K.L.M.N.O.} } } } } P.| | Q.7 7 8 m m 9 m f R.) ) ) S.S.S.S.T.E E U.E x V.A W.X. ", +" . . . I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.Y.Z.K.`. +M..+N.++N.++} @+| | | | e #+7 $+$+m m %+&+) ) ) *+=+g S.o E -+;+E ;+x x x >+>+>+F G ,+'+J ", +" . . I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.J.I.K.K.K.K.)+M.[ ++!+} ~+} ~+| | {+]+{+$+7 $+^+m n n %+) /+w S.S.S.o E E E U.(+x x x _+>+>+>+:+R :+:+<+:+L O [+ ", +" . . . I.I.I.I.I.I.I.I.I.I.I.I.I.I.J.Z.K.K..+`.N.N.}+++} ~+} 6 | | | e 7 7 7 m |+m &+1+f ) *+*+w S.T.-+o E E E (+x x 2+2+>+>+3+F R :+4+L L L 5+6+7+8+@. .9+T ", +" 0+@ I.I.I.I.I.I.I.I.I.Y.a+Z.K.K.L.N.N.[ !+} } } ~+} 6 | {+7 7 7 $+m ^+m ) ) 1+) g /+S.S.S.b+E E E (+c+x x y >+>+>+F F :+:+:+L L L W W 5+8+S d+@.@.e+f+g+Z &. ", +" & $ I.I.I.I.I.I.J.K.K. +L.N.N.!+} } h+| | 6 | | {+i+7 7 8 m R.R.) ) ) ) *+w S.b+b+E E E (+x x _+j+y >+G G 3+k+:+l+m+m+L 7+5+5+d+8+n+@.o+o+p+X q+X #.#.#.).%. ", +" & * * r+K.L.)+.+N.N.++N.!+} } h+@+| | | 7 7 7 9 m m 1+&+&+f ) ) w S.S.o E T.s+s+x (+x 2+j+y >+F k+:+:+4+t+t+L u+u+v+v+8+8+w+@.x+o+@.X X q+-.-.#.' y+! ! z+A+(.B+ ", +" ] / +.+N.N.} !+} @+@+P.| | ]+i+7 |+C+m m m &+f f g *+=+S.S.S.o E E U.s+(+x x j+2+>+F k+k+:+D+m+L L 6+8+7+8+8+8+n+@.@.o+x+f+X -.E+#.' F+' ! ! ;.G+H+I+}.}.<.J+/. ", +" 4 m.m.!+K+@+~+h+| #+7 {+7 C+^+8 m m &+&+) g L+S.S.S.p M+E U.s+x x x x 2+2+>+R F k+:+<+l+L L L W 8+v+N+w+@.S x+x+X X q+X O+E+F+P+F+! ! H+I+;.Q l Q+~.~.{.~.R+q S+_ _ ", +" 3 3 h+| | {+e 7 ^+^+^+m m ) ) ) ) =+w S.S.b+-+T.U.c+T+;+x x 2+2+>+>+R :+:+D+L L L L 6+7+8+N+U+w+@.e+x+o+p+V+X #.E+' y+W+! H+l l l l [.[.~.{.~.q X+q 3.Y+: : Z+`+8. @ ", +" r.r.7 m 7 ^+m n R.) ) L+*+=+L+S.-+b+E E (+T+x x x >+j+>+.@G :+l+:+D+L L u+7+5+8+N+8+@.@.f+X f+f+q+X #.#.y+' $.! ! ;.I+l Q +@Q+}.@@~.q q q #@3.: : : $@$@1 1 %@%@&@c. ", +" u.w.*@m &+&+) /+w S.S.S.S.o o E x c+T+x y =@>+>+R G :+:+:+m+:+6+7+6+8+8+8+n+S @.e+@.x+X q+#.#.E+#.y+! ! ! z+I+l l +@l }.~.~.R+R+q -@#@: : `+5.1 1 ;@>@>@>@>@,@'@=.)@!@~@ ", +" j {@g S.S.S.S.E p E c+T+U.x x 2+_+>+>+F R R t+:+m+L L 5+v+8+8+8+N+w+@.@.f+p+f+X X #.#.#.! ! ! ! I+z+l l [.~.~.~.{.X+q q M M : : ]@5.1 1 %@;@>@>@>@>@^@=./@(@(@0.(@_@:@<@ ", +" H.s r M+T.E E T+;+x =@x y >+>+G F :+:+D+L L L L 7+8+8+n+U+@.@.p+p+X X O+V+#.[@#.$.P+! ! }@G+l <.Q [.[.~.@@|@q q M #@: : : 4.1 1 1@2@>@>@>@=.=.=.3@4@3@(@(@_@5@6@7@8@9@h h 0@ ", +" a@b@T+;+x =@y >+>+>+3+G :+:+l+c@c@c@c@c@c@d+8+N+@.@.@.X o+X X q+#.#.P+P+W+! ! G+H+l +@+@<.~.~.d@R+q q 3.M 3.: ]@Z+5.1@2@1 >@>@=.=.e@=.=.f@(@(@(@g@6@6@6@6@9@8@h@9@i@i@i@j@k@ ", +" P W.j+>+G R 3+:+:+t+:+L L 7+7+c@c@c@c@c@c@@.@.X X O+X #.' #.F+P+! G+H+l l l ~.Q ~.~.X+q R+-@M M #@Z+]@4.1 1 ;@2@l@>@e@^@^@=.4@=.0.(@(@5@m@6@>.8@n@9@9@i@o@i@p@q@p@r@s@t@v u@ ", +" J J v@:+:+:+l+L 5+6+5+8+d+d+@.@.c@c@c@c@c@c@#.#.#.#.' P+! ! ! I+l Q ~.~.~.d@q X+q q w@3.: : 5.1 4.1 %@2@>@>@>@e@=.=.3@4@0._@_@5@5@6@6@x@9@8@9@9@i@i@i@y@z@r@r@t@A@2.B@C@D@!.E@!. ", +" O [+L L v+8+8+8+8+S @.e+x+x+X X c@c@c@c@c@c@! H+! }@}@l l l [.~.{.d@q q M w@Y+: : ]@1 $@1 1 %@F@>@'@'@=.=.4@=.(@(@g@(@6@6@7@9@n@9@9@o@G@i@z@H@y@r@r@I@r@2.2.2.J@K@K@L@M@N@H a.O@ ", +" P@T N+w+n+@.@.g+X X V+O+V+[@#.y+c@c@c@c@c@c@l Q Q+~.~.~.{.{.q q q : : `+: `+1 ;@2@F@l@>@,@^@=.=./@/@(@Q@Q@m@5@6@x@x@x@9@9@i@R@i@z@r@q@r@r@t@A@A@D 2.K@D@K@S@T@H H U@H Y Y V@W@X@ ", +" Y@Y@Y@p+g+X [@X #.-.#.F+W+! ! ! ! c@c@c@c@c@c@|@q q q M 3.: : ]@]@5.1 1 1 >@>@^@Z@=.`@=.f@f@(@Q@m@6@Q@6@x@9@8@9@9@o@R@i@i@y@q@r@ #I@I@2.J@B@K@K@S@N@M@H .#+#.#Y Y V@@#####$#%#&#*#=# ", +" -#-#-.O+#.' ! P+W+z+}@I+}@l l Q [.c@c@c@c@c@c@Y+: ]@Z+: 1 1 %@>@>@>@>@'@=.=./@3@(@(@;#6@6@6@6@7@9@n@>#9@i@R@i@i@q@r@r@ #s@2.2.J@D D@K@S@K@H N@H +#Y Y Y ,#'#####, $#)#)#)#!#~#!#{#]# ", +" %.^#! ! ! }@z+}@l +@+@~.~.X+{.R+q c@c@c@c@c@c@1 1 ;@;@F@>@=.e@'@=./#3@f@(@Q@_@5@m@>.>.n@9@G@R@>#o@i@(#z@H@r@t@2._#2.:#B@D K@N@T@H H .#<#Y Y Y Y ######$#[#)#}#|#1#|#!#2#3#4#5#6#7#7# ", +" (.(.8#l l l ~.[.d@~.q X+q Y+#@3.: Z+c@c@c@c@c@c@>@>@^@`@=.=./@c@c@c@c@c@c@6@>.8@9@9@h@9@i@i@c@c@c@c@c@c@2.2.2.c@c@c@c@c@c@H U@9#U@Y Y Y 0#####%#)#)#)#)#!#}#a#b#b#6#c#5#c#9.9.9.d#e#f#e# ", +" g#h#~.|@@@|@q -@q #@: : : 4.$@F@%@%@c@c@c@c@c@c@4@4@(@(@Q@Q@c@c@c@c@c@c@i#i#o@i@z@i@H@r@c@c@c@c@c@c@c@c@c@N@M@c@c@c@c@c@c@Y '#'#####%#%#)#)#j#!#!#!#k#!#6#6#5#9.l#9.9.m#d#n#o#o#p#q#r#s# ", +" S+/.S+q q 3.: ]@$@`+4.1 %@l@>@Z@,@e@=.c@c@c@c@c@c@(@m@6@>.8@n@c@c@c@c@c@i@y@q@r@r@s@s@2.c@c@c@c@c@c@c@c@c@c@c@U@c@c@c@c@c@c@t#, )#1#}#|#!#!#2#4#6#6#c#u#9.9.v#n#n#n#w#q#q#q#q#q#s#s#s#q#q#p# ", +" 2 8.`+`+1 1 %@1 F@2@>@>@^@=./@3@4@/@(@c@c@c@c@c@c@9@9@9@>#h@c@c@c@c@c@r@r@t@I@2.B@D@K@K@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@|#!#!#6#b#6#5#l#9.9.9.x#9.n#n#n#o#y#q#z#A#B#s#s#r#:.:.f#C#f#d#D# ", +" 7.E#%@l@>@>@`@'@e@3@=.4@(@(@5@5@6@6@6@c@c@c@c@c@c@i@i@r@r@c@c@c@c@c@c@K@K@D@K@S@S@L@H c@c@c@c@c@c@c@##$#$#$#c@c@c@c@c@c@c@c@6#6#9.5#9.9.d#D#n#n#F#q#G#q#H#I#A#s#J#K#K#:.C#C#L#e#e#M#7#7#9.9. ", +" N#c.O#e@=.=.=.(@0.(@(@_@5@>.6@7@9@9@9@G@c@c@c@c@c@c@s@r@r@c@c@c@c@c@c@S@S@P#H U@Y Y Y Y c@c@c@c@c@c@)#~ 1#~#!#2#c@c@c@c@c@c@c@x#n#9.n#n#w#G#q#I#H#B#A#s#r#s#:.:.:.Q#L#e#R#R#7#7#S#7#]#]#T#a#!#~# ", +" ~@U#f@f@(@Q@m@g@7@>.x@n@9@i@9@i@H@y@r@y@c@c@c@c@c@c@2.D c@c@c@c@c@c@H U@Y Y V@,#,###, c@c@c@c@c@c@c@a#a#k#6#5#6#c@c@c@c@c@c@c@o#y#q#q#I#s#V#W#s#X#:.:.Y#:.C#e#Z#7#7#`#7# $]#]#T#]#{#=#=#=#.$)#+$ ", +" <@@$6@8@9@x@9@9@o@o@i@i@y@H@r@r@ #I@A@2.c@c@c@c@c@c@M@c@c@c@c@c@c@Y 0#####$#)#)#)#1#~#c@c@c@c@c@c@u#6##$9.9.D#D#d#c@c@c@c@c@c@A#s#$$J#X#r#:.:.f#e#e#%$R#7#7#&$]#`#*$=$=$=#=#=#*#-$-$-$;$W@>$,#Y ", +" h h ,$9@i@i@i@i@y@H@r@r@r@r@_#2.J@:#K@K@N@c@c@c@c@c@c@c@c@c@c@c@c@##$#%#)#1#|#~#!#a#a#6#c@c@c@c@c@c@D#9.n#o#p#q#q#B#c@c@c@c@c@c@:.|.:.L#e#5 Z#R#7#7#'$ $]#]#{#=#=#=#=#)$&#-$-$W@!$X@;$~${$a.]$H H ^$ ", +" j@/$H@y@p@r@r@t@2.2.2.2.J@:#K@K@P#M@H H +#c@c@c@c@c@c@c@c@c@c@c@c@c@!#2#k#b#3#5#c##$($9.c@c@c@c@c@c@o#q#V#z#B#s#s#W#c@c@c@c@c@c@e#e#0 7#`#`#S#]#]#=$T#=#=#)$*#-$-$_$:$;$;$<$O@{$a.]$[$!.!.!.v }$K@:# ", +" |$1$2$s@2.2.C@:#D@K@K@K@H M@H H U@Y Y Y 0###c@c@c@c@c@c@c@c@c@c@c@c@c@c#5##$9.9.m#D#v#n#o#c@c@c@c@c@c@s#J#$$:.:.:.L#Y#c@c@c@c@c@c@`#3$]#]#]#*$]#=#*#4$)$-$!$X@!$;$;$~$a.a.].5$5$6$!.}$7$v 8$v u@2$2.2.r@ ", +" 9$}$:#B@K@K@L@H N@<#H <#<#@#0$0$######, +$)#c@c@c@c@c@c@c@c@c@c@c@c@c@c@a$D#y#p#q#q#q#q#s#c@c@c@c@c@c@C#e#:.e#e#5 %$7#c@c@c@c@c@c@b$=#c$=#-$-$-$W@;$;$;$;$+.a.a.a.[$[$!.!.!.}$v u@2$k@k@k@d$e$f$,$f$r@z@ ", +" a.].L@T@H U@+#U@Y Y Y ######, +$)#)#j#!#!#k#c@c@c@c@c@c@c@c@a$c@c@c@c@c@p#q#I#B#s#s#K#s#K#c@c@c@c@c@c@%$%$7#7#'$'$]#{#c@c@c@c@c@c@-$-$:$!$X@g$~$O@+.a.a.[$!.!.}$E@h$v 2$2$|$k@k@f$/$f$i$j$k$h l$@$m$9@9@ ", +" g$~$<$+#Y @#'#V@t#[#[#%#)#1#|#j#!#k#b#6#4#l#l#c@c@c@c@c@c@n#w#y#c@c@c@c@c@c@W#J#:.:.:.|.e#e#c@c@c@c@c@c@3$]#*$=$=$=#4$*#c@c@c@c@c@c@<$a.+.a.a.[$].!.z E@z v v v |$1$k@n$k@f$o$f$j$p$0@h q$<@<@r$r$s$s$6@6@5@ ", +" >$-$,###+$[#[#)#}#}#!#!#b#b#6#6#6#6##$u#9.x#d#c@c@c@c@c@c@I#B#s#s#c@c@c@c@c@c@Q#5 Z#M#7#7#7#c@c@c@c@c@c@=#c$c$-$-$-$>$X@c@c@c@c@c@c@a.[$!.!.7$h$v 8$8$8$1$k@n$j@/$f$f$j$0@h q$<@l$<@<@t$U#U#~@u$O#O#O#v$f@/@ ", +" c$)$=#)#)#!#~#!#3#a#4#6#5#9.#$9.v#m#n#n#n#w#G#q#c@c@c@c@c@c@$$K#:.C#c@c@c@c@c@c@7#7# $ $]#T#w$c@c@c@c@c@c@c@!$X@;$;$a.<$c@c@c@c@c@c@c@v v v k@x$k@k@k@o$o$f$k$f$i$h l$q$y$<@<@<@t$U#U#u$O#z$c.&@b.A$E#B$C$,@^@,@ ", +" ]#]#!#6#k#3#6#6#l#($9.9.m#n#n#n#F#y#q#I#V#z#s#s#c@c@c@c@c@c@e#e#M#M#7#c@c@c@c@c@c@b$=#=#)$.$-$-$c@c@c@c@c@c@g${$a.!.a.D$c@c@c@c@c@c@c@x$k@d$/$f$f$j$p$h h h c@c@c@c@c@c@U#U#z$~@O#b.E$c.A$A$C$7.8.8.F$G$_ _ 1 1 ", +" 7#7##$9.c#9.x#n#n#n#n#n#p#q#I#H#s#s#s#s#J#:.:.L#c@c@c@c@c@c@3$ $&$]#]#c@c@c@c@c@c@-$-$>$>$;$;$O@c@c@c@c@c@c@c@!.E@9$v c@c@c@c@c@c@c@c@f$f$0@0@h <@l$y$<@t$H$c@c@c@c@c@c@c.O#c.&@A$A$8.B$8.{ I$_ > S+/.J$/.h#: #@ ", +" e#e#Y#v#n#n#o#p#q#q#q#A#z#s#J#K#X#:.:.Q#e#e#e#Z#0 c@c@c@c@c@c@b$*$b$=#=#)$c@c@c@c@c@c@O@;$a.a.]$].6$c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@d <@<@r$:@<@H$U#u$u$U#c@c@c@c@c@c@7.7.8.I$2 I$_ S+S+S+/.g#/./.^.J+'.8#q @@{. ", +" :.:.F#p#q#q#q#A#s#J#s#X#:.:.|.L#Y#5 %$7#7#7# $`#]#c@c@c@c@c@c@c$-$-$-$>$;$;$c@c@c@c@c@c@!.!.!.}$v v c@c@c@c@c@c@c@c@c@c@c@h c@c@c@c@c@c@r$U#U#~@u$O#O#N#E$A$A$c@c@c@c@c@c@2 _ _ 1.J$J$/.K$h#J+J+L$'.(.M$N$%.O$%.l +@ ", +" z#V#z#$$W#X#r#:.:.Q#e#Q#R#Z#%$7#S#'$]#]#]#]#=#{#=#c@c@c@c@c@c@W@;$;$+.a.a.5$c@c@c@c@c@c@v u@1$1$k@k@d$c@c@c@c@c@c@c@c@c@<@P$c@c@c@c@c@c@z$O#v$b.A$A$A$B$B$8.8.c@c@c@c@c@c@Q$K$J+R$J+J+B+L$'.(.(.%.O$%.S$T$-#-#` H+! ", +" p#F#w#:.:.:.Y#e#Z#Z#7#7#7#`#&$]#]#T#b$=#=#c$-$*#-$!$c@c@c@c@c@c@a.].]$]$!.E@}$9$c@c@c@c@c@c@e$f$f$f$f$i$h h c@c@c@c@c@s$U#U#u$c@c@c@c@c@c@A$ @6. @8.{ 2 U$_ _ _ c@c@c@c@c@c@B+J+_.(.A+A+^#%.%.%.%.S$` *.-#Y@Y@U V$#.q+E+ ", +" v#9.e#5 e#7#7#S#3$]#]#]#*$=$b$4$&#-$-$-$:$_$;$;$<$<${$a.].]$!.!.!.z v 8$v 8$x$k@k@d$j@f$f$p$f$h l$m$d <@<@:@U#t$u$W$O#O#O#v$v$c@c@c@c@c@c@{ { G$_ _ _ /./.h#X$^.^.8#(.,.(.(.A+%.%.Y$Z$S$-#-#*.Z Y@Y@U U . .`$`$[+[+e+o+ ", +" c#5#6#7#`#]#]#=$=$w$=#c$=#-$4$-$_$X@;$;${$a.{$a.a.a.6$!.h$7$}$2$2$k@k@k@n$/$f$f$f$k$k$h h q$m$<@P$r$U#U#U#U#u$O#O#c.E$A$E#7. @7.c@c@c@c@c@c@J$ %/./.X$J+J+_.B+(.(.A+M$^#%.%.S$S$-#-#*.&.Z Y@U . ....%+%[+[+@%#%#%J $%U+8+8+ ", +" 2#!#*$b$w$=#.$-$-$-$W@-$;$;$;${${$a.a.!.!.!.h$h$9$v v 2$2$1$e$k@k@j@p$h ,$h h l$h <@<@<@U#s$U#U#W$W$O#c@c@c@c@c@c@8.E#8.2 8._ c@c@c@c@c@c@R$g#J+_.8#,.(.A+M$%.A+%%S$-#-#-#` Y@Y@Y@V$ .9+ .[+`$.%[+[+N J J I &%,+P P P *%<+<+ ", +" ~ )#-$-$-$:$_$>$;$g$g$+.a.a.6$5$!.!.E@7$v v |$|$k@k@k@f$/$f$k$h k$h @$l$<@<@:@<@r$U#~@u$z$)@O#b.A$E$C$c@c@c@c@c@c@c@S+1.S+Q$c@c@c@c@c@c@c@L$(.(.N$%.%.%.Z$).-#-#=%*.Y@Y@U -% . . .[++%O V ;%J J J v@P W.>%A A A ,%'%V.K :+3+ ", +" )###,#;$;$g$a.+.a.a.[$a.!.h$9$E@v 8$v x$x$n$e$/$f$f$i$0@k$h q$q$d <@H$t$U#U#~@U#!@O#v$&@A$b.7.6.7.8.8.F$8.c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@O$%.S$Y$-#-#=%` )%Y@!%9+T T ..%P@[+N ;%O J J '+$%I P P B A A a@b@~%K r s s s F.2+=@_+ ", +" Y Y a.a.a.5$!.]$E@z z v u@u@k@x$k@e$f$f$j$f$h 0@h h d <@<@<@H$U#U#U#u$O#O#N#A$E$A$A$C$A$8.8.U$_ _ > > _ /./.c@c@c@c@c@c@c@c@c@c@c@c@c@c@c@-#Z )%&.Y@Y@T !% . .{%+%[+[+N V @%I $%,+&%P W.P A A A ,%K K G.]%s s s x.j j j u w.E E ", +" S@M@!.E@}$v v v 8$1$k@k@k@e$f$f$j$h k$h y$q$<@<@U#r$U#U#u$U#O#v$E$N#b.A$B$ @8.8.{ I$U$2 > %S+Q$h#/.g#J+,.J+,.c@c@c@c@c@c@c@c@c@c@c@c@` Y@!%!%T . .`$[+[+N O J J J $%I P P P P A A A ,%'%K s H.H.s ^%/%^%j t u t u.u.(%b a S.L+ ", +" D K@C@v u@k@k@k@j@f$/$f$f$h h h d d <@<@P$:@H$u$U#!@z$O#&@O#c.A$E#6.8.8.F$F$G$_ _ %> /.X$/.^.J+J+_.J+(.(.(.A+^#%.Y$c@c@c@c@c@c@c@c@T . .P@P@{%[+O N N J J $%P ,+B _%*%_%,%b@,%K K K H.s s s j j j i *@u.u.k :%(%a r.3 c s.3 ) R.1+ ", +" 2.s@k@e$j@j@p$f$p$h h q$<@<@<@s$t$t$U#U#W$O#O#c.A$A$A$A$ @7.8.{ { I$_ Q$J$> /./.g#J+J+J+J+8#(.(.M$A+%.%.S$T$-#-#*.)%Y@Y@U Y@-% .+%{%+%[+[+;%@%J $%&%P P X.X._%A A A V.,%K <%C C s /%s ^%u j u.u.u.u.a :%r.r.E.3 3 p.p.[%m.m.m.] 9 ^+ ", +" z@i@H@,$j$h @$m$d <@<@P$U#U#)@U#u$O#E$b.b.A$A$6.C$7.8.G$I$_ _ _ S+Q$/.K$R$^.J+'.(._.(.(.(.O$O$%.%.-#-#-#-#-#)%V$Y@T -% . . .{%[+N N J J J v@,+P _%>%X.B A '%A K G.G.<%r s /%{@j j j v.*@u.t.t.r.r.}%E.|%3 1%o.p.m.2%m.] 3%] / j.j.#+| | ", +" 9@9@h l$<@<@t$H$U#u$W$O#O#O#O#A$b.A$E# @8.8.8.I$_ _ /.S+1./.R$/.J+J+L$8#(.(.(.^#A+%.S$Z$%%-#*.-#)%=%Y@T V$-% ...`$+%[+O J J J '+&%J P P X._%A A V.A K K ]%C r ^%{@^%j j v.*@w.u.u.:%t.r.r.c q.3 1%1%3 m.4 ] 4 ] ] / * * * A.& & f.& < ++ ", +" 4%6@H$U#!@z$W$O#O#b.c.A$A$C$7.7.8.I$U$G$_ /.1.1././.R$^.J+_._.'.(.(.^#A+%.%.Z$T$-#-#=%)%Y@Y@T T . .`$`$+%[+[+O @%J ,+&%P P P W._%A A A K K K K G.s ^%F.s j u u j u u.k b r.|%s.s.3 3 [%p.[%m.m.] ^ ] ] k.( * = * - & $ % z.+ + # + .+.+ ", +" _@(@(@O#E$E$A$A$6.8.C$8.8.8._ _ _ S+S+/././.X$X$J+J+(.L$(.(.N$M$%.%.%%%%-#-#Y@)%Z 9+Y@ . . .`$+%[+O N O #%J J v@$%P P A *%A V.,%~%a@K K s s ^%^%5%/%i u.*@u.u.b r.r.r.|%3 s.3 3 1%m.m.m.] m.] 6%] * * i.- - - & + 7%+ + + y.. . . . . a+I.I. ", +" =.=.A$A$B$8. @I$F$G$G$_ S+ %/./.^.J+^.8#J+B+(.(.O$A+%.%.Y$%.T$-#-#=%Y@Y@!%-%U . ...[++%[+O @%J J '+P v@P W.B _%A A ,%,%K K <%s s {@{@^%j v.i t u.u.t.a r.r.r.E.E.3 o.D.m.m.C.l.3%] ( / j.* = A.& & g.g.z.+ d.y.. . . . . . . . . . . . I.I. ", +" >@>@>@8.8._ G$> > _ S+R$g#^.J+J+8#_.(.(.N$^#O$%.T$-#-#-#-#=%Y@Y@Y@!%9+ .[+P@..[+[+O J J J ,+$%P P B W.*%A ~%K K K <%s <%s F.5%/%j u v.u.w.u.k t.r.r.3 }%3 [%D.1%m.m.4 C.2%] ] ( 6%* A.- & & & + + + d.0+y.. . . . . . . . . . . . . . . . I.I.I. ", +" 1 1 _ J$/.J$/.R$J+R$J+8#_.(.(.M$O$O$%.Y$S$T$=%-#Z &.Y@Y@ .T ...`$[+[+N [+N J I '+v@P P W._%A A ,%A K ]%K C s s s s /%j v.w.j u.u.k :%r.|%r.q.3 3 3 n.m.m.2%C.] ] / B.* * * A.h.& z.+ + + 0++ 0+0+. . . . . . . . . . . . . . . . . . . . . I.I. ", +" : 3.R$K$J+J+(.L$(.A+N$N$%.%.Y$-#T$-#&.&.` Y@-%V$ . ...+%{%[+N [+J J ,+&%P P P P A A A A K K K K G.s s x.F.5%j j w.u.u.a u.r.r.r.3 q.c 1%1%o.m.m.2%C.] ] ] k.6%* = & ; & $ f.f.d.@ d.. . . . . . . . . . . . . . . . . . . . . . . . . . . . I.I. ", +" |@d@8#(.(.A+^#%.Y$-#-#-#-#*.&.Y@Y@Y@9+9+ .+%+%[+[+[+[+#%J J v@P P W.*%_%A A a@'%K K H.C <%x.F.5%j j i i *@u.:%b r.r.r.}%3 3 3 [%o.o.2%m.^ ^ ] / 6%j.= h.= h.& & f.+ + + y.y.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . I.I. ", +" Q+[.l %.Y$Y$-#-#-#&.Z !%V$9+ . . . ..%[+V [+J J J v@J P P X._%A A a@V.~%]%K r s s s {@j j j i u.u.u.k (%r.}%|%c 3 1%p.3 m.^ C.] ] ] * * j.h.- ; & % 7%f.+ + + e.e.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . I.I.I. ", +" ! ! -#)%Y@V$V$9+ . ...{%[+O [+@%J J '+I $%P P P A B A ~%b@V.<%r C s s s /%j j *@w.i u.u.k r.r.r.3 3 3 3 D.m.m.] 3%] ] 6%k.* * * = h.& & g.f.+ + y.# d.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . I.I. ", +" #.#.E+U ..%[+{%[+V @%[+J J v@v@P B W.*%A V.a@'%K r <%C H.s /%j j j i *@u.u.k b t.r.q.|%|%3 3 n.1%4 m.3%] ] j.B.j.* * * & & & g.+ f.+ . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . I.I.I. ", +" f+x+@.@.N+d+N+8+u+5+u+L L l+l+<+:+:+F >+>+>+2+2+x x c+(+E E T.E b+S.g S.g ) ) f n m m m 8 $+^+7 i+e 7 | | ~+K+K+++}+[ }+N.N.K.`.K.Z.K.8%I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I. ", +" 8+8+5+L L L <+D+:+4+F .@:+>+>+>+9%x x T+U.E U.E b+b+S.S.g w ) ) f R.n m m m ^+7 8 7 7 ]+Q.| | P.h+} < N.}+N.N.)+ +)+K.Z.Y.8%I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I. ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/src/Mod/Ship/InitGui.py b/src/Mod/Ship/InitGui.py index b20c552af2..aa8a409aff 100644 --- a/src/Mod/Ship/InitGui.py +++ b/src/Mod/Ship/InitGui.py @@ -34,9 +34,13 @@ class ShipWorkbench ( Workbench ): # ToolBar list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] self.appendToolbar("Ship design",list) + list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] + self.appendToolbar("Loading",list) # Menu list = ["Ship_LoadExample", "Ship_CreateShip", "Ship_OutlineDraw", "Ship_AreasCurve", "Ship_Hydrostatics"] self.appendMenu("Ship design",list) + list = ["Ship_Weights", "Ship_CreateTank", "Ship_GZ"] + self.appendToolbar("Loading",list) Gui.addWorkbench(ShipWorkbench()) diff --git a/src/Mod/Ship/Instance.py b/src/Mod/Ship/Instance.py index 64eecd5cc7..adba4d22b1 100644 --- a/src/Mod/Ship/Instance.py +++ b/src/Mod/Ship/Instance.py @@ -39,7 +39,6 @@ class Ship: """ Creates a new ship on active document. @param faces Ship faces (Part::Shape entities). """ - self.faces = faces # Add uniqueness property to identify Ship instances obj.addProperty("App::PropertyBool","IsShip","Ship", str(Translator.translate("True if is a valid ship instance"))).IsShip=True # Add main dimensions @@ -47,7 +46,7 @@ class Ship: obj.addProperty("App::PropertyLength","Beam","Ship", str(Translator.translate("Ship beam (B) [m]"))).Beam=0.0 obj.addProperty("App::PropertyLength","Draft","Ship", str(Translator.translate("Ship draft (T) [m]"))).Draft=0.0 # Add shapes - obj.addProperty("Part::PropertyPartShape","Shape","Ship", str(Translator.translate("Ship surfaces"))).Shape = Part.makeShell(self.faces) + obj.Shape = Part.makeShell(faces) obj.Proxy = self self.obj = obj @@ -55,12 +54,12 @@ class Ship: ''' Print the name of the property that has changed ''' # FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") if prop == "Length" or prop == "Beam" or prop == "Draft": - fp.Shape = Part.makeShell(self.faces) + pass def execute(self, obj): ''' Print a short message when doing a recomputation, this method is mandatory ''' # FreeCAD.Console.PrintMessage("Recompute Ship\n") - obj.Shape = Part.makeShell(self.faces) + obj.Shape = Part.makeShell(obj.Shape.Faces) def lineFaceSection(self,line,surface): """ Returns the point of section of a line with a face @@ -147,7 +146,7 @@ class Ship: wire = wires[j].Edges for k in range(0,len(wire)): edges.append(wire[k]) - # Slice curves to get points (Length based) + # Slice curves to get points points = [] for k in range(0,nP): planePoints = [] @@ -664,7 +663,7 @@ class ViewProviderShip: def sections(obj): """ Returns the discretization points of sections, with the advantage that is a list of nSections lists, with the points. - @param Ship object + @param obj Ship object @return Sections points """ histogram = obj.nPoints[:] @@ -675,3 +674,42 @@ def sections(obj): for j in range(histogram[i],histogram[i+1]): sections[i].append(points[j]) return sections + +def weights(obj): + """ Returns Ship weights list. If weights has not been sets, + this tool creates it. + @param obj Ship object + @return Weights list. None if errors + """ + # Test if is a ship instance + props = obj.PropertiesList + try: + props.index("IsShip") + except ValueError: + return None + if not obj.IsShip: + return None + # Test if properties already exist + try: + props.index("WeightNames") + except ValueError: + obj.addProperty("App::PropertyStringList","WeightNames","Ship", str(Translator.translate("Ship Weights names"))).WeightNames=[Translator.translate("Lightweight").__str__()] + try: + props.index("WeightMass") + except ValueError: + # Compute mass aproximation + from shipHydrostatics import Tools + disp = Tools.Displacement(obj,obj.Draft,0.0) + obj.addProperty("App::PropertyFloatList","WeightMass","Ship", str(Translator.translate("Ship Weights masses"))).WeightMass=[1000.0 * disp[1]] + try: + props.index("WeightPos") + except ValueError: + # Compute mass aproximation + from shipHydrostatics import Tools + disp = Tools.Displacement(obj,obj.Draft,0.0) + obj.addProperty("App::PropertyVectorList","WeightPos","Ship", str(Translator.translate("Ship Weights centers of gravity"))).WeightPos=[Vector(disp[2],0.0,obj.Draft)] + # Setup list + weights = [] + for i in range(0,len(obj.WeightNames)): + weights.append([obj.WeightNames[i], obj.WeightMass[i], obj.WeightPos[i]]) + return weights diff --git a/src/Mod/Ship/Makefile.am b/src/Mod/Ship/Makefile.am index 380d8aed84..a6d38f5002 100644 --- a/src/Mod/Ship/Makefile.am +++ b/src/Mod/Ship/Makefile.am @@ -4,7 +4,8 @@ datadir = $(prefix)/Mod/Ship data_DATA = \ InitGui.py \ ShipGui.py \ - Instance.py + Instance.py \ + TankInstance.py nobase_data_DATA = \ Icons/AreaCurveIco.png \ @@ -33,6 +34,12 @@ nobase_data_DATA = \ Icons/ReparametrizeIco.xpm \ Icons/Ship.xcf \ Icons/Ship.xpm \ + Icons/Weight.png \ + Icons/Weight.xcf \ + Icons/Weight.xpm \ + Icons/Tank.png \ + Icons/Tank.xcf \ + Icons/Tank.xpm \ Examples/s60.fcstd \ Examples/barehull5415.fcstd \ Examples/s60_katamaran.fcstd \ @@ -61,7 +68,18 @@ nobase_data_DATA = \ shipUtils/__init__.py \ shipUtils/Math.py \ shipUtils/Paths.py \ - shipUtils/Translator.py + shipUtils/Translator.py \ + tankWeights/__init__.py \ + tankWeights/Preview.py \ + tankWeights/TaskPanel.py \ + tankWeights/TaskPanel.ui \ + tankCreateTank/__init__.py \ + tankCreateTank/TaskPanel.py \ + tankCreateTank/TaskPanel.ui \ + tankGZ/__init__.py \ + tankGZ/Plot.py \ + tankGZ/TaskPanel.py \ + tankGZ/TaskPanel.ui CLEANFILES = $(BUILT_SOURCES) diff --git a/src/Mod/Ship/ShipGui.py b/src/Mod/Ship/ShipGui.py index 8f50b4be07..c97f1e9087 100644 --- a/src/Mod/Ship/ShipGui.py +++ b/src/Mod/Ship/ShipGui.py @@ -84,8 +84,47 @@ class Hydrostatics: ToolTip = str(Translator.translate('Plot ship hydrostatics')) return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} +class SetWeights: + def Activated(self): + import tankWeights + tankWeights.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/Weight.png" + MenuText = str(Translator.translate('Set ship weights')) + ToolTip = str(Translator.translate('Set ship weights, tanks must be added later')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class CreateTank: + def Activated(self): + import tankCreateTank + tankCreateTank.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/Tank.png" + MenuText = str(Translator.translate('Create a new tank')) + ToolTip = str(Translator.translate('Create a new ship tank')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + +class GZ: + def Activated(self): + import tankGZ + tankGZ.load() + + def GetResources(self): + from shipUtils import Paths, Translator + IconPath = Paths.iconsPath() + "/HydrostaticsIco.png" + MenuText = str(Translator.translate('GZ curve')) + ToolTip = str(Translator.translate('Transversal stability GZ curve computation')) + return {'Pixmap' : IconPath, 'MenuText': MenuText, 'ToolTip': ToolTip} + FreeCADGui.addCommand('Ship_LoadExample', LoadExample()) FreeCADGui.addCommand('Ship_CreateShip', CreateShip()) FreeCADGui.addCommand('Ship_OutlineDraw', OutlineDraw()) FreeCADGui.addCommand('Ship_AreasCurve', AreasCurve()) FreeCADGui.addCommand('Ship_Hydrostatics', Hydrostatics()) +FreeCADGui.addCommand('Ship_Weights', SetWeights()) +FreeCADGui.addCommand('Ship_CreateTank', CreateTank()) +FreeCADGui.addCommand('Ship_GZ', GZ()) diff --git a/src/Mod/Ship/TankInstance.py b/src/Mod/Ship/TankInstance.py new file mode 100644 index 0000000000..6e44795f86 --- /dev/null +++ b/src/Mod/Ship/TankInstance.py @@ -0,0 +1,1946 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +import time + +# COIN +from pivy.coin import * +from pivy import coin + +# FreeCAD +import FreeCAD,FreeCADGui +from FreeCAD import Part, Base, Vector + +# Ship design module +from shipUtils import Paths, Translator, Math + +class ShipTank: + def __init__(self, obj, solid, level=0, density=998.0): + """ Creates a new tank on active document. + @param obj Created Part::FeaturePython object. + @param solid Solid shape that represent the tank. + @param level Tank filling level. + @param density Fluid density. + """ + # Add uniqueness property to identify Tank instances + obj.addProperty("App::PropertyBool","IsShipTank","ShipTank", str(Translator.translate("True if is a valid ship tank instance"))).IsShipTank=True + # Add general options + obj.addProperty("App::PropertyFloat","Level","ShipTank", str(Translator.translate("Fluid filling level percentage"))).Level=level + obj.addProperty("App::PropertyFloat","Density","ShipTank", str(Translator.translate("Inside fluid density"))).Density=density + # Add shapes + shape = self.computeShape(solid) + if not shape: + obj.IsShipTank=False + return + # obj.addProperty("Part::PropertyPartShape","Shape","ShipTank", str(Translator.translate("Tank solid"))).Shape = shape + obj.Shape = shape + obj.Proxy = self + self.obj = obj + + def onChanged(self, fp, prop): + """ Property changed, tank must be recomputed """ + if prop == "IsShipTank": + FreeCAD.Console.PrintWarning("Ussually you don't want to modify manually this option.\n") + elif prop == "Level": + if fp.Level > 100.0: + fp.Level = 100.0 + elif fp.Level < 0.0: + fp.Level = 0.0 + + def execute(self, obj): + """ Shape recomputation called """ + obj.Shape = self.computeShape(obj.Shape) + + def computeShape(self, solid): + """ Create faces shape. This method also calls to generate boxes. + @param solid Solid shape that represent the tank. + @return Computed solid shape. None if can't build it. + """ + # Study input to try to build a solid + if solid.isDerivedFrom('Part::Feature'): + # Get shape + shape = solid.Shape + if not shape: + return None + solid = shape + if not solid.isDerivedFrom('Part::TopoShape'): + return None + # Get shells + shells = solid.Shells + if not shells: + return None + # Build solids + solids = [] + for s in shells: + solid = Part.Solid(s) + if solid.Volume < 0.0: + solid.reverse() + solids.append(solid) + # Create compound + shape = Part.CompSolid(solids) + return shape + +class ViewProviderShipTank: + def __init__(self, obj): + """ Set this object to the proxy object of the actual view provider """ + obj.Proxy = self + + def attach(self, obj): + """ Setup the scene sub-graph of the view provider, this method is mandatory """ + return + + 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 setDisplayMode(self,mode): + ''' Map the display mode defined in attach with those defined in getDisplayModes. + Since they have the same names nothing needs to be done. This method is optinal. + ''' + return mode + + def onChanged(self, vp, prop): + ''' Print the name of the property that has changed ''' + # FreeCAD.Console.PrintMessage("Change property: " + str(prop) + "\n") + + 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 + + def getIcon(self): + return """ + /* XPM */ + static char * Tank_xpm[] = { + "128 128 1605 2", + " c None", + ". c #000000", + "+ c #D1D1D1", + "@ c #D2D2D2", + "# c #D3D3D3", + "$ c #D3D4D4", + "% c #D5D5D5", + "& c #CFD0CF", + "* c #D0D0D0", + "= c #D3D2D3", + "- c #D4D4D3", + "; c #D5D6D5", + "> c #D6D6D6", + ", c #D7D7D7", + "' c #CDCECE", + ") c #CFCECE", + "! c #D0CFCF", + "~ c #D3D3D2", + "{ c #D3D3D4", + "] c #D5D4D5", + "^ c #D6D7D6", + "/ c #D8D8D8", + "( c #D8D8D9", + "_ c #D9D9DA", + ": c #CCCCCB", + "< c #CCCCCC", + "[ c #CECECD", + "} c #CECECE", + "| c #CFCFCF", + "1 c #D1D2D2", + "2 c #D5D4D4", + "3 c #D8D9D9", + "4 c #DAD9DA", + "5 c #DADBDB", + "6 c #DBDCDB", + "7 c #CACACA", + "8 c #CACBCB", + "9 c #CBCBCB", + "0 c #CCCDCD", + "a c #CECDCD", + "b c #D2D2D1", + "c c #D2D3D3", + "d c #D4D3D3", + "e c #D9D9D8", + "f c #D9D9D9", + "g c #DADBDA", + "h c #DBDCDC", + "i c #DCDCDC", + "j c #DDDDDD", + "k c #DEDEDE", + "l c #C7C8C8", + "m c #C9C9C9", + "n c #CAC9CA", + "o c #CBCBCC", + "p c #CCCDCC", + "q c #CDCDCD", + "r c #D0D1D1", + "s c #D1D2D1", + "t c #D3D2D2", + "u c #D4D4D5", + "v c #D5D5D6", + "w c #D6D7D7", + "x c #D8D7D8", + "y c #D9D8D9", + "z c #DADAD9", + "A c #DBDADA", + "B c #DBDBDC", + "C c #DDDCDD", + "D c #DDDEDE", + "E c #DEDFDE", + "F c #DFE0E0", + "G c #E0E0E1", + "H c #C6C6C6", + "I c #C7C7C7", + "J c #C8C8C7", + "K c #C9C9C8", + "L c #CACAC9", + "M c #CBCACB", + "N c #D0CFD0", + "O c #D1D0D1", + "P c #D1D1D2", + "Q c #D4D4D4", + "R c #D6D5D6", + "S c #D7D6D7", + "T c #D7D8D8", + "U c #DAD9D9", + "V c #DADADA", + "W c #DBDBDB", + "X c #DCDBDC", + "Y c #DDDDDC", + "Z c #DFDEDF", + "` c #E0DFDF", + " . c #E0E0E0", + ".. c #E1E1E1", + "+. c #E2E2E2", + "@. c #C5C4C4", + "#. c #C5C5C5", + "$. c #C8C8C8", + "%. c #C9C8C8", + "&. c #D5D5D4", + "*. c #D8D7D7", + "=. c #D9D8D8", + "-. c #DCDDDD", + ";. c #DEDDDD", + ">. c #E3E4E3", + ",. c #E5E4E4", + "'. c #C4C4C4", + "). c #C6C7C6", + "!. c #C7C8C7", + "~. c #C8C8C9", + "{. c #CACACB", + "]. c #CCCBCB", + "^. c #D0D0D1", + "/. c #D5D6D6", + "(. c #D7D7D6", + "_. c #DFDFDF", + ":. c #E1E2E2", + "<. c #E3E3E3", + "[. c #E4E3E4", + "}. c #E6E5E5", + "|. c #E6E6E6", + "1. c #E6E7E7", + "2. c #C4C5C5", + "3. c #C6C6C7", + "4. c #CFD0D0", + "5. c #D1D0D0", + "6. c #D6D5D5", + "7. c #DADADB", + "8. c #DCDDDC", + "9. c #DDDDDE", + "0. c #DEDFDF", + "a. c #E1E1E2", + "b. c #E3E2E2", + "c. c #E4E4E4", + "d. c #E5E5E5", + "e. c #E8E8E7", + "f. c #E9E8E9", + "g. c #EAE9EA", + "h. c #C5C5C4", + "i. c #C6C6C5", + "j. c #C7C7C6", + "k. c #CBCACA", + "l. c #CDCDCC", + "m. c #CECFCF", + "n. c #DBDADB", + "o. c #E0E0DF", + "p. c #E1E1E0", + "q. c #E1E2E1", + "r. c #E3E3E4", + "s. c #E4E5E5", + "t. c #E7E6E7", + "u. c #E7E7E8", + "v. c #E9E9E8", + "w. c #E9EAE9", + "x. c #EAEAEA", + "y. c #EBEBEA", + "z. c #C4C5C4", + "A. c #C6C5C5", + "B. c #C6C7C7", + "C. c #CCCCCD", + "D. c #CECECF", + "E. c #D9DAD9", + "F. c #DBDBDA", + "G. c #DEDEDD", + "H. c #E0DFE0", + "I. c #E0E1E0", + "J. c #E6E5E6", + "K. c #E7E7E6", + "L. c #E7E8E7", + "M. c #E8E8E9", + "N. c #E9E9E9", + "O. c #ECECEC", + "P. c #ECEDED", + "Q. c #EDEDEE", + "R. c #010101", + "S. c #C5C4C5", + "T. c #CBCCCB", + "U. c #CDCCCC", + "V. c #CECFCE", + "W. c #CFCFCE", + "X. c #CFCFD0", + "Y. c #D7D8D7", + "Z. c #DEDDDE", + "`. c #E1E0E0", + " + c #E5E6E6", + ".+ c #EBEBEB", + "++ c #ECEBEC", + "@+ c #EDEDED", + "#+ c #EEEEEE", + "$+ c #EFEFEF", + "%+ c #F0F0F0", + "&+ c #C4C4C5", + "*+ c #CFCECF", + "=+ c #D2D1D1", + "-+ c #D6D6D5", + ";+ c #D8D9D8", + ">+ c #DDDEDD", + ",+ c #DFDEDE", + "'+ c #E2E3E3", + ")+ c #E7E7E7", + "!+ c #E8E8E8", + "~+ c #EBECEC", + "{+ c #ECEDEC", + "]+ c #EFEFF0", + "^+ c #F1F0F1", + "/+ c #F1F1F1", + "(+ c #C7C6C6", + "_+ c #C9C8C9", + ":+ c #C9CAC9", + "<+ c #CACBCA", + "[+ c #D2D2D3", + "}+ c #D4D5D5", + "|+ c #DCDCDB", + "1+ c #E3E3E2", + "2+ c #E4E3E3", + "3+ c #E4E4E5", + "4+ c #E5E5E6", + "5+ c #EAEAE9", + "6+ c #ECEBEB", + "7+ c #F0F0EF", + "8+ c #F0F0F1", + "9+ c #C8C7C8", + "0+ c #C8C9C9", + "a+ c #CBCBCA", + "b+ c #CCCBCC", + "c+ c #D7D6D6", + "d+ c #DDDCDC", + "e+ c #E2E2E1", + "f+ c #E2E3E2", + "g+ c #E3E4E4", + "h+ c #E8E7E8", + "i+ c #E9E8E8", + "j+ c #EAE9E9", + "k+ c #EDECEC", + "l+ c #EEEEED", + "m+ c #EFEEEF", + "n+ c #EFF0F0", + "o+ c #F1F0F0", + "p+ c #C5C6C6", + "q+ c #C7C6C7", + "r+ c #D0D0CF", + "s+ c #D4D5D4", + "t+ c #E1E0E1", + "u+ c #E8E9E9", + "v+ c #EDECED", + "w+ c #EEEDED", + "x+ c #EEEFEF", + "y+ c #F0EFF0", + "z+ c #F0F1F0", + "A+ c #D7D7D8", + "B+ c #C8C7C7", + "C+ c #C9C9CA", + "D+ c #D2D1D2", + "E+ c #D9DADA", + "F+ c #E2E1E1", + "G+ c #E9E9EA", + "H+ c #EAEBEB", + "I+ c #D8D8D7", + "J+ c #CBCCCC", + "K+ c #CDCCCD", + "L+ c #D6D6D7", + "M+ c #E6E6E5", + "N+ c #E7E6E6", + "O+ c #E8E7E7", + "P+ c #EFEEEE", + "Q+ c #CDCECD", + "R+ c #D1D1D0", + "S+ c #D2D3D2", + "T+ c #DFE0DF", + "U+ c #E3E2E3", + "V+ c #E4E5E4", + "W+ c #E5E6E5", + "X+ c #ECECED", + "Y+ c #D4D3D4", + "Z+ c #CECDCE", + "`+ c #E6E6E7", + " @ c #EBEAEB", + ".@ c #ECECEB", + "+@ c #F0F1F1", + "@@ c #DCDCDD", + "#@ c #EBEAEA", + "$@ c #F0EFEF", + "%@ c #D3D4D3", + "&@ c #E6E7E6", + "*@ c #EEEDEE", + "=@ c #ADADAD", + "-@ c #565656", + ";@ c #DCDBDB", + ">@ c #DFDFE0", + ",@ c #E7E8E8", + "'@ c #E8E9E8", + ")@ c #EDEDEC", + "!@ c #EBEBEC", + "~@ c #EEEFEE", + "{@ c #B7B6B7", + "]@ c #E5E4E5", + "^@ c #EDEEED", + "/@ c #B6B6B6", + "(@ c #B6B7B7", + "_@ c #B7B7B6", + ":@ c #B7B6B6", + "<@ c #E5E5E4", + "[@ c #B5B6B5", + "}@ c #B5B6B6", + "|@ c #B5B5B5", + "1@ c #B6B5B5", + "2@ c #B6B5B6", + "3@ c #E2E1E2", + "4@ c #E4E4E3", + "5@ c #B4B4B4", + "6@ c #B4B5B5", + "7@ c #B5B5B4", + "8@ c #B6B6B5", + "9@ c #E2E2E3", + "0@ c #B3B4B4", + "a@ c #B4B4B5", + "b@ c #B4B5B4", + "c@ c #B5B4B4", + "d@ c #B3B3B3", + "e@ c #B3B3B4", + "f@ c #B4B3B3", + "g@ c #B4B4B3", + "h@ c #B5B4B5", + "i@ c #D0D1D0", + "j@ c #B3B3B2", + "k@ c #B3B2B3", + "l@ c #B4B3B4", + "m@ c #90B9D9", + "n@ c #91BAD9", + "o@ c #C6C5C6", + "p@ c #B1B2B2", + "q@ c #B2B2B2", + "r@ c #B2B3B2", + "s@ c #B2B3B3", + "t@ c #8FB7D8", + "u@ c #8EB7D7", + "v@ c #8FB8D8", + "w@ c #90B8D8", + "x@ c #91BBD9", + "y@ c #91BCDA", + "z@ c #C2C2C2", + "A@ c #C3C4C3", + "B@ c #C3C4C4", + "C@ c #C8C9C8", + "D@ c #CDCDCE", + "E@ c #B1B1B1", + "F@ c #B1B2B1", + "G@ c #B2B1B2", + "H@ c #B2B2B3", + "I@ c #B3B2B2", + "J@ c #8CB4D6", + "K@ c #8DB4D6", + "L@ c #8DB5D7", + "M@ c #8EB6D7", + "N@ c #8EB7D8", + "O@ c #8FB7D7", + "P@ c #90B9D8", + "Q@ c #91BBDA", + "R@ c #92BCD9", + "S@ c #92BCDA", + "T@ c #C1C1C0", + "U@ c #C1C1C1", + "V@ c #C2C2C1", + "W@ c #C3C3C2", + "X@ c #C3C3C3", + "Y@ c #C3C3C4", + "Z@ c #CAC9C9", + "`@ c #B1B0B0", + " # c #B2B2B1", + ".# c #8BB2D5", + "+# c #8BB2D6", + "@# c #8CB3D6", + "## c #8CB3D7", + "$# c #8DB5D6", + "%# c #8EB5D7", + "&# c #8FB8D7", + "*# c #92BBD9", + "=# c #92BBDA", + "-# c #BFC0C0", + ";# c #C0C1C0", + "># c #C2C1C1", + ",# c #C3C2C2", + "'# c #C4C4C3", + ")# c #C5C6C5", + "!# c #C5C5C6", + "~# c #B0B0B0", + "{# c #B0B1B0", + "]# c #B1B1B2", + "^# c #B2B1B1", + "/# c #0E3459", + "(# c #0E355A", + "_# c #0F355A", + ":# c #0F365A", + "<# c #8AB2D5", + "[# c #8CB3D5", + "}# c #8BB3D6", + "|# c #8FB6D7", + "1# c #8FB9D7", + "2# c #90B9D7", + "3# c #90BAD8", + "4# c #90BBD9", + "5# c #92BDDA", + "6# c #93BEDA", + "7# c #BEBEBE", + "8# c #BEBFBE", + "9# c #BFBFBE", + "0# c #BFBFC0", + "a# c #C0C0BF", + "b# c #C2C3C2", + "c# c #C4C3C3", + "d# c #AFB0B0", + "e# c #AFAFB0", + "f# c #B0AFB0", + "g# c #B0B1B1", + "h# c #B0B0B1", + "i# c #B1B0B1", + "j# c #7A9EC5", + "k# c #799FC5", + "l# c #7A9FC5", + "m# c #7AA0C6", + "n# c #0E345A", + "o# c #0F3559", + "p# c #8BB1D5", + "q# c #8CB4D5", + "r# c #8FB9D8", + "s# c #90BAD7", + "t# c #91BBD8", + "u# c #91BCD9", + "v# c #91BDD9", + "w# c #92BEDA", + "x# c #93BFDA", + "y# c #BDBDBD", + "z# c #BDBEBD", + "A# c #BEBEBD", + "B# c #BEBEBF", + "C# c #BEBFBF", + "D# c #BFBFBF", + "E# c #C0C0C0", + "F# c #C1C0C0", + "G# c #C0C1C1", + "H# c #C3C2C3", + "I# c #C4C3C4", + "J# c #AFAEAF", + "K# c #AFAFAF", + "L# c #B0AFAF", + "M# c #789DC5", + "N# c #789EC5", + "O# c #799EC5", + "P# c #7AA1C5", + "Q# c #7BA1C5", + "R# c #0F3659", + "S# c #10375A", + "T# c #8DB6D6", + "U# c #8EB8D7", + "V# c #92BDD9", + "W# c #143F5B", + "X# c #174A6A", + "Y# c #84B0CB", + "Z# c #85B0CC", + "`# c #BCBCBC", + " $ c #BDBCBC", + ".$ c #C0C0C1", + "+$ c #C1C2C1", + "@$ c #C2C3C3", + "#$ c #AEAEAE", + "$$ c #AEAFAF", + "%$ c #AFAFAE", + "&$ c #779BC4", + "*$ c #779CC4", + "=$ c #789CC4", + "-$ c #789DC4", + ";$ c #789EC4", + ">$ c #799FC4", + ",$ c #7AA0C5", + "'$ c #10385A", + ")$ c #8DB7D7", + "!$ c #8EB7D6", + "~$ c #90BBD8", + "{$ c #133E5B", + "]$ c #83AEC9", + "^$ c #84AFCA", + "/$ c #85B1CB", + "($ c #85B2CB", + "_$ c #BDBCBD", + ":$ c #BEBDBD", + "<$ c #C0BFBF", + "[$ c #C1C1C2", + "}$ c #C9CACA", + "|$ c #AEAEAD", + "1$ c #AEAFAE", + "2$ c #AEAEAF", + "3$ c #7599C3", + "4$ c #7699C3", + "5$ c #7699C2", + "6$ c #769AC3", + "7$ c #779BC3", + "8$ c #789BC4", + "9$ c #799EC4", + "0$ c #79A0C4", + "a$ c #8CB5D5", + "b$ c #8CB5D6", + "c$ c #8DB7D6", + "d$ c #426D8A", + "e$ c #16486A", + "f$ c #7AA5C1", + "g$ c #83ADC9", + "h$ c #84B1CB", + "i$ c #85B1CC", + "j$ c #BCBDBD", + "k$ c #BDBDBC", + "l$ c #BFBEBF", + "m$ c #BFC0BF", + "n$ c #ADADAC", + "o$ c #AEADAD", + "p$ c #ADAEAD", + "q$ c #ADAEAE", + "r$ c #7496C2", + "s$ c #7597C2", + "t$ c #7598C2", + "u$ c #769BC2", + "v$ c #779BC2", + "w$ c #779CC3", + "x$ c #789DC3", + "y$ c #7AA0C4", + "z$ c #7AA1C4", + "A$ c #7AA2C5", + "B$ c #7BA2C5", + "C$ c #10395A", + "D$ c #8EB6D6", + "E$ c #8EB8D6", + "F$ c #133D5A", + "G$ c #81ABC8", + "H$ c #82ACC9", + "I$ c #82ADC9", + "J$ c #82AEC9", + "K$ c #83AFC9", + "L$ c #83B0CA", + "M$ c #BDBEBE", + "N$ c #C1C0C1", + "O$ c #C7C7C8", + "P$ c #ADACAC", + "Q$ c #AFAEAE", + "R$ c #7395C1", + "S$ c #7395C2", + "T$ c #7496C1", + "U$ c #7599C2", + "V$ c #769BC3", + "W$ c #779DC3", + "X$ c #789EC3", + "Y$ c #7AA2C4", + "Z$ c #7BA3C4", + "`$ c #7BA3C5", + " % c #11395A", + ".% c #113A5A", + "+% c #123C5A", + "@% c #164A6E", + "#% c #4C7694", + "$% c #80AAC7", + "%% c #80ABC8", + "&% c #81ACC9", + "*% c #81ACC8", + "=% c #81ADC9", + "-% c #83AFCA", + ";% c #84B0CA", + ">% c #84B1CA", + ",% c #86B3CB", + "'% c #87B4CC", + ")% c #BFBEBE", + "!% c #ACACAC", + "~% c #ABACAC", + "{% c #ACACAD", + "]% c #7294C0", + "^% c #7194C0", + "/% c #7294C1", + "(% c #7394C1", + "_% c #7396C1", + ":% c #7497C2", + "<% c #7498C2", + "[% c #799FC3", + "}% c #7CA3C5", + "|% c #123B5A", + "1% c #88B1D0", + "2% c #7EA8C6", + "3% c #7FA9C6", + "4% c #7FAAC7", + "5% c #81ADC8", + "6% c #85B1CA", + "7% c #86B2CB", + "8% c #86B4CB", + "9% c #87B5CB", + "0% c #BCBCBD", + "a% c #C0BFC0", + "b% c #ABABAB", + "c% c #ACABAC", + "d% c #ABABAC", + "e% c #ACADAC", + "f% c #ACADAD", + "g% c #7193C0", + "h% c #7293C0", + "i% c #7193C1", + "j% c #7293C1", + "k% c #7498C1", + "l% c #789FC4", + "m% c #79A1C3", + "n% c #79A1C4", + "o% c #7BA2C4", + "p% c #7CA4C5", + "q% c #7CA4C4", + "r% c #16496F", + "s% c #7DA7C5", + "t% c #7FAAC6", + "u% c #80ABC7", + "v% c #80ACC7", + "w% c #82AFC9", + "x% c #84B1C9", + "y% c #85B2CA", + "z% c #87B5CC", + "A% c #88B6CC", + "B% c #BDBDBE", + "C% c #C1C2C2", + "D% c #AAABAB", + "E% c #AAAAAA", + "F% c #ABAAAB", + "G% c #ABACAB", + "H% c #ACACAB", + "I% c #7192C0", + "J% c #7292C0", + "K% c #7598C1", + "L% c #7599C1", + "M% c #759AC1", + "N% c #769AC2", + "O% c #779CC2", + "P% c #779DC2", + "Q% c #789DC2", + "R% c #78A0C3", + "S% c #7CA3C4", + "T% c #7AA2C2", + "U% c #7CA5C4", + "V% c #7DA5C4", + "W% c #7DA6C5", + "X% c #7EA8C5", + "Y% c #82ADC8", + "Z% c #83B0C9", + "`% c #85B3CA", + " & c #86B5CB", + ".& c #87B6CC", + "+& c #BCBDBC", + "@& c #C2C1C2", + "#& c #C2C2C3", + "$& c #AAA9AA", + "%& c #AAABAA", + "&& c #ABAAAA", + "*& c #7091BF", + "=& c #7092BF", + "-& c #7191C0", + ";& c #7192BF", + ">& c #7092C0", + ",& c #7295C0", + "'& c #7497C1", + ")& c #759AC2", + "!& c #769CC2", + "~& c #789FC3", + "{& c #79A0C3", + "]& c #79A2C4", + "^& c #7AA4C3", + "/& c #7BA4C4", + "(& c #7DA8C5", + "_& c #7EA9C6", + ":& c #80AAC6", + "<& c #81ADC7", + "[& c #82ADC7", + "}& c #82AEC8", + "|& c #88B7CC", + "1& c #A9A9A9", + "2& c #A9AAAA", + "3& c #A9A9AA", + "4& c #A9AAA9", + "5& c #7090BE", + "6& c #7091BE", + "7& c #7092BE", + "8& c #7191BF", + "9& c #7397C1", + "0& c #7499C1", + "a& c #7AA1C3", + "b& c #7AA2C3", + "c& c #79A2C2", + "d& c #7AA3C3", + "e& c #7BA5C4", + "f& c #80ABC6", + "g& c #81ACC7", + "h& c #81AEC8", + "i& c #82AFC8", + "j& c #83B1CA", + "k& c #85B3CB", + "l& c #85B4CA", + "m& c #87B6CB", + "n& c #88B8CC", + "o& c #A8A8A8", + "p& c #6F90BE", + "q& c #6F91BE", + "r& c #7192BE", + "s& c #7193BF", + "t& c #769BC1", + "u& c #779EC3", + "v& c #789FC2", + "w& c #79A1C2", + "x& c #7AA3C2", + "y& c #7BA4C3", + "z& c #7CA6C5", + "A& c #7DA7C4", + "B& c #7EA7C5", + "C& c #7EA9C5", + "D& c #7EAAC6", + "E& c #7FACC6", + "F& c #81AEC7", + "G& c #82AFC7", + "H& c #83B1C9", + "I& c #84B2C9", + "J& c #84B3C9", + "K& c #86B4CA", + "L& c #89B7CC", + "M& c #89B8CD", + "N& c #A8A8A7", + "O& c #6F90BD", + "P& c #6E90BD", + "Q& c #6E90BE", + "R& c #7293BF", + "S& c #7396C0", + "T& c #7397C0", + "U& c #7498C0", + "V& c #759BC1", + "W& c #769CC1", + "X& c #779EC2", + "Y& c #789EC2", + "Z& c #78A0C1", + "`& c #78A1C2", + " * c #7BA6C3", + ".* c #7BA6C4", + "+* c #7CA6C4", + "@* c #7FABC6", + "#* c #82AEC7", + "$* c #83AFC8", + "%* c #83B0C8", + "&* c #88B7CB", + "** c #89B9CC", + "=* c #89BACD", + "-* c #6E8FBD", + ";* c #6F91BD", + ">* c #7093BF", + ",* c #7194BF", + "'* c #7294BF", + ")* c #7395C0", + "!* c #7398C0", + "~* c #779FC1", + "{* c #77A0C1", + "]* c #78A1C1", + "^* c #7AA4C2", + "/* c #7CA7C4", + "(* c #7DA8C4", + "_* c #7DA9C5", + ":* c #7FAAC5", + "<* c #80ACC6", + "[* c #80ADC7", + "}* c #84B1C8", + "|* c #88B8CB", + "1* c #89BACC", + "2* c #BEBDBE", + "3* c #12285A", + "4* c #768CBE", + "5* c #768DBE", + "6* c #6E91BD", + "7* c #7193BE", + "8* c #7295BF", + "9* c #7396BF", + "0* c #7398BF", + "a* c #7499C0", + "b* c #749AC1", + "c* c #779DC1", + "d* c #789FC1", + "e* c #779EC0", + "f* c #769EC0", + "g* c #769FC0", + "h* c #77A0C0", + "i* c #79A2C1", + "j* c #79A3C2", + "k* c #7BA4C2", + "l* c #7CA7C3", + "m* c #7EAAC5", + "n* c #80ADC6", + "o* c #82B0C7", + "p* c #85B2C9", + "q* c #85B3C9", + "r* c #85B4C9", + "s* c #86B5CA", + "t* c #87B6CA", + "u* c #88B9CC", + "v* c #8AB9CC", + "w* c #8ABACC", + "x* c #8BBBCC", + "y* c #758BBE", + "z* c #758CBE", + "A* c #768CBF", + "B* c #6E91BE", + "C* c #7093BE", + "D* c #7397BF", + "E* c #7497BF", + "F* c #749AC0", + "G* c #759AC0", + "H* c #769BC0", + "I* c #769CC0", + "J* c #779EC1", + "K* c #769DC0", + "L* c #759DBF", + "M* c #769DBE", + "N* c #77A1C0", + "O* c #7AA5C2", + "P* c #7DA7C3", + "Q* c #7EA9C4", + "R* c #7EAAC4", + "S* c #7FABC5", + "T* c #81ADC6", + "U* c #81AFC7", + "V* c #82B0C8", + "W* c #83B1C8", + "X* c #84B2C8", + "Y* c #86B6CB", + "Z* c #87B7CA", + "`* c #87B7CB", + " = c #84AFCB", + ".= c #143F5A", + "+= c #12275A", + "@= c #758BBD", + "#= c #768BBE", + "$= c #6E8FBC", + "%= c #6E8EBD", + "&= c #7296BF", + "*= c #7297BF", + "== c #779CC1", + "-= c #749BBE", + ";= c #749CBF", + ">= c #759EBE", + ",= c #769FBF", + "'= c #76A0C0", + ")= c #779FC0", + "!= c #7BA5C3", + "~= c #7CA6C3", + "{= c #7CA8C4", + "]= c #7DA9C3", + "^= c #7FAAC4", + "/= c #81AFC6", + "(= c #82B1C7", + "_= c #85B5C9", + ":= c #86B6CA", + "<= c #82AECA", + "[= c #758ABD", + "}= c #748ABD", + "|= c #758CBD", + "1= c #6D8FBC", + "2= c #759CC1", + "3= c #769DC1", + "4= c #759BBF", + "5= c #739ABE", + "6= c #759DBE", + "7= c #769EBE", + "8= c #769EBF", + "9= c #779FBF", + "0= c #78A1C0", + "a= c #78A2C1", + "b= c #79A2C0", + "c= c #7AA3C1", + "d= c #7CA8C3", + "e= c #7DA9C4", + "f= c #82B0C6", + "g= c #83B2C8", + "h= c #84B3C8", + "i= c #143E5B", + "j= c #11265A", + "k= c #7489BC", + "l= c #748ABC", + "m= c #758ABC", + "n= c #6D8EBC", + "o= c #6E8EBC", + "p= c #6D8FBD", + "q= c #6F8FBD", + "r= c #7092BD", + "s= c #7294BE", + "t= c #7194BE", + "u= c #7295BE", + "v= c #7196BF", + "w= c #759BC0", + "x= c #749ABE", + "y= c #7399BC", + "z= c #729ABD", + "A= c #739ABD", + "B= c #749CBD", + "C= c #769DBF", + "D= c #779EBF", + "E= c #78A2C0", + "F= c #79A3C1", + "G= c #7AA4C1", + "H= c #7BA6C2", + "I= c #7CA9C4", + "J= c #7EABC4", + "K= c #7FACC4", + "L= c #80ADC5", + "M= c #80AEC6", + "N= c #81AEC6", + "O= c #83B1C7", + "P= c #7EA9C7", + "Q= c #7FAAC8", + "R= c #80AAC8", + "S= c #7388BC", + "T= c #7488BC", + "U= c #7389BC", + "V= c #7489BD", + "W= c #6E8EBB", + "X= c #6D8EBD", + "Y= c #7195BE", + "Z= c #7499BF", + "`= c #749ABF", + " - c #749BC0", + ".- c #7198BB", + "+- c #7298BC", + "@- c #7299BC", + "#- c #729ABC", + "$- c #739BBD", + "%- c #749BBD", + "&- c #749DBE", + "*- c #76A0BF", + "=- c #77A2C0", + "-- c #78A3C1", + ";- c #79A4C1", + ">- c #7CA8C2", + ",- c #7DAAC4", + "'- c #7FACC5", + ")- c #7DA7C6", + "!- c #7FA9C7", + "~- c #133E5A", + "{- c #7387BC", + "]- c #6F92BD", + "^- c #7094BE", + "/- c #7296BE", + "(- c #7399BD", + "_- c #0E3559", + ":- c #7096BB", + "<- c #7197BB", + "[- c #7199BB", + "}- c #739BBC", + "|- c #749CBE", + "1- c #749EBE", + "2- c #769FBE", + "3- c #77A0BF", + "4- c #77A1BF", + "5- c #78A3C0", + "6- c #79A4C0", + "7- c #7AA6C2", + "8- c #7BA7C2", + "9- c #7DA8C3", + "0- c #7EACC5", + "a- c #7CA5C5", + "b- c #10255A", + "c- c #7286BB", + "d- c #7287BC", + "e- c #6D8EBB", + "f- c #7093BD", + "g- c #7094BD", + "h- c #7195BF", + "i- c #7399BF", + "j- c #739ABF", + "k- c #7398BE", + "l- c #6F95BA", + "m- c #7096BA", + "n- c #7097BB", + "o- c #739ABC", + "p- c #739CBD", + "q- c #759EBF", + "r- c #78A2BF", + "s- c #7CA7C2", + "t- c #10245A", + "u- c #7185BB", + "v- c #7286BC", + "w- c #7387BB", + "x- c #7487BC", + "y- c #6E90BC", + "z- c #6F93BE", + "A- c #7196BE", + "B- c #7297BE", + "C- c #7298BF", + "D- c #7297BD", + "E- c #6E94BA", + "F- c #6F95B9", + "G- c #6F96BA", + "H- c #7097BA", + "I- c #729ABB", + "J- c #749DBD", + "K- c #77A0BE", + "L- c #78A4C0", + "M- c #7AA5C0", + "N- c #7CA7C5", + "O- c #7185BA", + "P- c #7286BA", + "Q- c #7285BB", + "R- c #7386BB", + "S- c #7288BC", + "T- c #7589BD", + "U- c #6E91BC", + "V- c #6F91BC", + "W- c #6E92BC", + "X- c #6F93BD", + "Y- c #7194BD", + "Z- c #7195BD", + "`- c #7298BE", + " ; c #7297BC", + ".; c #6D93B8", + "+; c #6E94B8", + "@; c #6E95B9", + "#; c #7096B9", + "$; c #739CBC", + "%; c #76A0BE", + "&; c #78A1BF", + "*; c #79A1C1", + "=; c #79A4C2", + "-; c #7BA3C3", + ";; c #7084BA", + ">; c #7184BB", + ",; c #7085BB", + "'; c #7186BB", + "); c #7287BB", + "!; c #7388BB", + "~; c #6C8EBB", + "{; c #6D8FBB", + "]; c #6F92BC", + "^; c #7095BD", + "/; c #7196BD", + "(; c #7195BC", + "_; c #0E3359", + ":; c #6C92B7", + "<; c #6D94B8", + "[; c #6F96B9", + "}; c #6F97BA", + "|; c #7299BB", + "1; c #729BBB", + "2; c #749DBC", + "3; c #759EBD", + "4; c #759FBE", + "5; c #10235A", + "6; c #7083BA", + "7; c #7084BB", + "8; c #7085BA", + "9; c #7093BC", + "0; c #7095BC", + "a; c #6C91B7", + "b; c #6E95B8", + "c; c #7198BA", + "d; c #739BBB", + "e; c #78A2C2", + "f; c #0F225A", + "g; c #6F82B9", + "h; c #7083B9", + "i; c #6F83B9", + "j; c #6F83BA", + "k; c #7184BA", + "l; c #6C8DBB", + "m; c #6C8FBB", + "n; c #6D90BB", + "o; c #6E91BB", + "p; c #6F93BC", + "q; c #7094BC", + "r; c #6F94BB", + "s; c #0D3259", + "t; c #6A8FB6", + "u; c #6B91B7", + "v; c #6E93B8", + "w; c #7098BA", + "x; c #7099BA", + "y; c #7199BA", + "z; c #729BBC", + "A; c #6E81B9", + "B; c #6E82B9", + "C; c #6E90BB", + "D; c #6E93BA", + "E; c #698EB6", + "F; c #6A8EB6", + "G; c #6A90B6", + "H; c #6B90B6", + "I; c #6B92B7", + "J; c #6D93B7", + "K; c #6E96B8", + "L; c #6F97B9", + "M; c #7098BB", + "N; c #78A0C0", + "O; c #6E80B8", + "P; c #6E81B8", + "Q; c #6F81B8", + "R; c #6F81B9", + "S; c #6F82B8", + "T; c #6F92BB", + "U; c #6E92BA", + "V; c #0D3159", + "W; c #688DB4", + "X; c #698EB5", + "Y; c #698FB5", + "Z; c #6A90B7", + "`; c #6C93B7", + " > c #518FC8", + ".> c #6F96B8", + "+> c #123A5A", + "@> c #0F215A", + "#> c #6D80B8", + "$> c #6D81B8", + "%> c #6C8FBA", + "&> c #6E90BA", + "*> c #6E92BB", + "=> c #6E93BC", + "-> c #0C3159", + ";> c #678CB4", + ">> c #678DB4", + ",> c #688EB4", + "'> c #698EB4", + ")> c #6A90B5", + "!> c #6B91B6", + "~> c #6D94B7", + "{> c #6D95B8", + "]> c #6E96B9", + "^> c #0E2159", + "/> c #6C7FB8", + "(> c #6D7FB7", + "_> c #6D7FB8", + ":> c #507FC9", + "<> c #6D8FBA", + "[> c #6D91BB", + "}> c #6D91B9", + "|> c #0C3059", + "1> c #678AB3", + "2> c #678BB3", + "3> c #678DB3", + "4> c #6B91B5", + "5> c #6B92B5", + "6> c #6C92B6", + "7> c #6B92B6", + "8> c #6C93B6", + "9> c #0E2059", + "0> c #6C7EB7", + "a> c #6D7EB7", + "b> c #6E80B7", + "c> c #6E82B8", + "d> c #7084B9", + "e> c #6F84BA", + "f> c #6C90B9", + "g> c #668AB2", + "h> c #698FB4", + "i> c #6A90B4", + "j> c #719ABB", + "k> c #749BBC", + "l> c #6B7EB7", + "m> c #6B7DB6", + "n> c #6C7DB7", + "o> c #6C7FB7", + "p> c #6D80B7", + "q> c #6F84B9", + "r> c #7186BA", + "s> c #6C8EB9", + "t> c #6589B1", + "u> c #678CB2", + "v> c #678DB2", + "w> c #688EB3", + "x> c #6A8FB5", + "y> c #6A91B5", + "z> c #6C92B5", + "A> c #6C94B7", + "B> c #6D95B7", + "C> c #759DBD", + "D> c #0E1F5A", + "E> c #6A7CB6", + "F> c #6A7DB6", + "G> c #6C7EB6", + "H> c #7082B9", + "I> c #7285BA", + "J> c #7085B9", + "K> c #0E335A", + "L> c #658BB1", + "M> c #668BB1", + "N> c #668CB1", + "O> c #678CB1", + "P> c #688DB3", + "Q> c #688FB3", + "R> c #698FB3", + "S> c #6990B4", + "T> c #7097B9", + "U> c #7197BA", + "V> c #739CBE", + "W> c #0E1F59", + "X> c #6A7BB6", + "Y> c #6B7CB6", + "Z> c #6C7DB6", + "`> c #6B7DB7", + " , c #6F82B6", + "., c #648AB0", + "+, c #658AB1", + "@, c #658BB0", + "#, c #668CB2", + "$, c #688FB4", + "%, c #6B90B5", + "&, c #0D1E59", + "*, c #697BB5", + "=, c #6A7CB7", + "-, c #6B7EB6", + ";, c #6C7EB8", + ">, c #6E82B7", + ",, c #6389B0", + "', c #6489B0", + "), c #658AB0", + "!, c #668AB1", + "~, c #688DB2", + "{, c #6990B5", + "], c #697AB5", + "^, c #697BB6", + "/, c #6A7BB5", + "(, c #6D7EB8", + "_, c #6D81B6", + ":, c #6388AE", + "<, c #6388AF", + "[, c #6389AF", + "}, c #6489AF", + "|, c #668BB0", + "1, c #6979B4", + "2, c #6879B5", + "3, c #6879B4", + "4, c #6979B5", + "5, c #6A7AB5", + "6, c #6B7CB7", + "7, c #6D80B5", + "8, c #6287AE", + "9, c #6288AE", + "0, c #0D1D59", + "a, c #6878B4", + "b, c #6778B4", + "c, c #6C7EB5", + "d, c #6186AC", + "e, c #6186AD", + "f, c #6286AE", + "g, c #668DB1", + "h, c #678EB3", + "i, c #0D1C59", + "j, c #6777B3", + "k, c #6777B4", + "l, c #697AB4", + "m, c #6A7CB5", + "n, c #6E81B7", + "o, c #6084AC", + "p, c #6185AC", + "q, c #6086AD", + "r, c #6187AE", + "s, c #6387AE", + "t, c #0C1C59", + "u, c #6676B3", + "v, c #6776B3", + "w, c #6877B4", + "x, c #687AB5", + "y, c #697CB6", + "z, c #6A7DB7", + "A, c #6B7DB5", + "B, c #5F83AC", + "C, c #6083AC", + "D, c #6185AD", + "E, c #6288AD", + "F, c #668BB2", + "G, c #6A91B4", + "H, c #6675B3", + "I, c #6575B3", + "J, c #6677B3", + "K, c #6677B4", + "L, c #6A7DB4", + "M, c #5E82AB", + "N, c #5F83AB", + "O, c #5F84AC", + "P, c #6085AD", + "Q, c #6085AC", + "R, c #10365A", + "S, c #0C1B59", + "T, c #6575B2", + "U, c #6675B2", + "V, c #6676B2", + "W, c #6676B4", + "X, c #6776B4", + "Y, c #687AB4", + "Z, c #5D81AA", + "`, c #5D81AB", + " ' c #5D82AA", + ".' c #5E83AB", + "+' c #6083AB", + "@' c #6286AD", + "#' c #648AB1", + "$' c #6473B3", + "%' c #6474B2", + "&' c #697CB3", + "*' c #5D80A9", + "=' c #5E82AA", + "-' c #5F84AB", + ";' c #6287AD", + ">' c #6389AE", + ",' c #0B1A59", + "'' c #6473B2", + ")' c #6574B2", + "!' c #6574B3", + "~' c #6778B3", + "{' c #6779B4", + "]' c #687BB2", + "^' c #5B7FA9", + "/' c #5B80A9", + "(' c #5C80A9", + "_' c #5D81A9", + ":' c #5E81AA", + "<' c #6184AC", + "[' c #638AB0", + "}' c #678DB1", + "|' c #0B1A58", + "1' c #6372B1", + "2' c #6472B2", + "3' c #6472B1", + "4' c #6473B1", + "5' c #6573B2", + "6' c #6576B3", + "7' c #6878B3", + "8' c #687AB3", + "9' c #5B7EA7", + "0' c #5B7FA8", + "a' c #5B80A8", + "b' c #5C81AA", + "c' c #5F82AB", + "d' c #668DB2", + "e' c #11268E", + "f' c #11268D", + "g' c #0B1958", + "h' c #6373B2", + "i' c #6877B3", + "j' c #6879B2", + "k' c #0C2F59", + "l' c #5A7DA7", + "m' c #5A7EA7", + "n' c #5B7FA7", + "o' c #5B7EA8", + "p' c #5C7FA8", + "q' c #5F83AA", + "r' c #6084AB", + "s' c #6589B0", + "t' c #0C196C", + "u' c #152064", + "v' c #11258D", + "w' c #6371B1", + "x' c #6271B1", + "y' c #6372B2", + "z' c #6778B1", + "A' c #0C2E59", + "B' c #597CA6", + "C' c #5A7CA6", + "D' c #597DA6", + "E' c #5D80AA", + "F' c #5E83AA", + "G' c #0E355B", + "H' c #0C1A6F", + "I' c #131E62", + "J' c #414C90", + "K' c #10258E", + "L' c #6271B0", + "M' c #6272B1", + "N' c #6373B1", + "O' c #6677B1", + "P' c #0B2E59", + "Q' c #577BA5", + "R' c #587BA6", + "S' c #587CA6", + "T' c #5A7EA8", + "U' c #5D82AB", + "V' c #6289AE", + "W' c #1A5FA3", + "X' c #0D1C75", + "Y' c #131E61", + "Z' c #404B8E", + "`' c #475296", + " ) c #10258D", + ".) c #6270B0", + "+) c #6272B0", + "@) c #6576B2", + "#) c #6576B1", + "$) c #577AA4", + "%) c #577BA4", + "&) c #587BA5", + "*) c #5C81A9", + "=) c #648AAF", + "-) c #0E345B", + ";) c #0D1D79", + ">) c #101B5F", + ",) c #3C478B", + "') c #11258E", + ")) c #6371B0", + "!) c #6575B1", + "~) c #0B2E58", + "{) c #5679A3", + "]) c #5779A4", + "^) c #567AA4", + "/) c #577AA5", + "() c #577BA6", + "_) c #597BA6", + ":) c #175797", + "<) c #0E1F82", + "[) c #101B5E", + "}) c #384487", + "|) c #0B1858", + "1) c #6170B0", + "2) c #6575B0", + "3) c #5578A2", + "4) c #5678A3", + "5) c #5679A4", + "6) c #5A7DA6", + "7) c #102394", + "8) c #111C60", + "9) c #141F63", + "0) c #293578", + "a) c #0A1859", + "b) c #616FAF", + "c) c #616FB0", + "d) c #6270AF", + "e) c #6372B0", + "f) c #6474AF", + "g) c #0B2D58", + "h) c #5576A2", + "i) c #5577A2", + "j) c #5577A3", + "k) c #5578A4", + "l) c #5578A3", + "m) c #587CA5", + "n) c #597DA7", + "o) c #5D82A9", + "p) c #6187AD", + "q) c #154F8D", + "r) c #1227A5", + "s) c #0D185C", + "t) c #1B266A", + "u) c #313C80", + "v) c #445093", + "w) c #10248D", + "x) c #6170AF", + "y) c #6474B1", + "z) c #6373AF", + "A) c #5375A1", + "B) c #5476A2", + "C) c #587AA4", + "D) c #5C7FA9", + "E) c #6084AD", + "F) c #102393", + "G) c #0C196A", + "H) c #0E1A5D", + "I) c #242F73", + "J) c #3A4589", + "K) c #626FAF", + "L) c #626FB0", + "M) c #6475B2", + "N) c #6272AE", + "O) c #0A2C59", + "P) c #5275A1", + "Q) c #5376A2", + "R) c #5477A2", + "S) c #144A84", + "T) c #0E1E7F", + "U) c #121D61", + "V) c #2B3679", + "W) c #0A1858", + "X) c #6370B0", + "Y) c #6271AF", + "Z) c #0A2C58", + "`) c #5173A0", + " ! c #5274A1", + ".! c #5274A0", + "+! c #0D1B74", + "@! c #10248E", + "#! c #6171AE", + "$! c #51729F", + "%! c #51739F", + "&! c #5273A0", + "*! c #5476A1", + "=! c #5576A3", + "-! c #114379", + ";! c #102291", + ">! c #0C196B", + ",! c #1F2A6E", + "'! c #364185", + ")! c #465195", + "!! c #10238D", + "~! c #616EAF", + "{! c #616FAD", + "]! c #0A2B59", + "^! c #50729E", + "/! c #50729F", + "(! c #5375A0", + "_! c #134C8D", + ":! c #0E1E81", + "~ c #323D81", + ",~ c #0A2D5D", + "'~ c #1354AE", + ")~ c #10228F", + "!~ c #212C70", + "~~ c #374286", + "{~ c #0F228B", + "]~ c #1251A7", + "^~ c #283377", + "/~ c #3E4A8D", + "(~ c #0F4085", + "_~ c #0B2F62", + ":~ c #1328A8", + "<~ c #0D1C77", + "[~ c #303B7F", + "}~ c #104289", + "|~ c #0B3063", + "1~ c #112497", + "2~ c #1C276A", + "3~ c #0C175B", + "4~ c #0F438A", + "5~ c #0B3266", + "6~ c #0F2088", + "7~ c #0C3367", + "8~ c #365885", + "9~ c #0B3369", + "0~ c #0E1D7C", + "a~ c #0B2F60", + "b~ c #0C366E", + " ", + " ", + " ", + " ", + " ", + " . . ", + " . . . . . . . ", + " . . . . + @ # $ % . . . . ", + " . . . . & * + @ = - % ; > , . . . . ", + " . . . . ' ) ! * + @ ~ { ] % ^ , / ( _ . . . ", + " . . . . : < [ } | * + 1 = $ 2 ; > , / 3 4 5 6 . . . . ", + " . . . . 7 8 9 0 a } | * + b c d 2 % > , / e f g h i j k . . . . ", + " . . . . l m n 9 o p q } | * r s t # u % v w x y z A B i C D E F G . . . ", + " . . . . H I J K L M 9 < q ' | N O P t # Q % R S T / U V W X Y D Z ` ...+.. . . . ", + " . . . . @.#.H I $.%.L M 9 < q } } N r + @ # Q &.R S *.=.f V W X -.;.k ` ...+.+.>.,.. . . . ", + " . . . . '.'.'.#.H ).!.~.n {.].< 0 ' } | ^.b @ # Q ] /.(., / f 4 5 B i D k _. ...:.<.[.,.}.|.1.. . . . ", + " . . . . '.'.'.'.'.2.H 3.J %.m 7 9 < p } ) 4.5.+ @ ~ Q Q 6.> , / 3 4 7.X 8.9.k 0. ...a.b.<.c.d.|.1.e.f.g.. . . ", + " . . . . . '.'.'.'.'.'.'.h.i.j.$.$.m 7 k.< l.a m.| * + @ c Q Q % > , / f f n.B i j k _.o.p.q.+.r.c.s.|.t.u.v.w.x.y.. . . . ", + " . . . . . '.'.'.'.'.'.'.'.z.A.B.I $.m 7 9 ].C.q D.| * + P t # Q 6.> (.T f E.F.6 i j G.0.H.I...+.<.c.d.J.K.L.M.N.x.y.O.P.Q.. . . . ", + " R.. . '.'.'.'.'.'.'.'.'.'.'.S.A.3.I $.m n k.T.U.q V.W.X.+ + t # Q % /.S Y./ z F.W i -.Z.k _.`.a.+.<.r.s. +|.L.M.N.g..+++O.@+#+$+%+. . . ", + " . . . . . '.'.'.'.'.'.'.'.'.&+i.H I $.K n 8 < < q } *+* ^.=+@ { Q ] -+, , ;+_ V W B 8.>+,+_.G ..+.'+c.d.d.t.)+!+M.x.x.~+{+Q.#+$+]+^+/+. . . . ", + " . . =.f . . . . . '.'.'.'.'.'.2.A.H (+$._+:+<+].< q } | N ^.s [+# Q }+6.> *./ f V 5 |+C D 0._. ...q.1+2+3+4+|.1.!+N.5+y.6+O.Q.#+$+7+8+/+/+/+/+. . . . ", + " . . / / y e . . . . . '.'.'.'.&+#.H I 9+0+m a+9 b+l.} m.X.5.+ @ = $ % > c+Y./ f U W X d+k k _. ...e+f+g+c.d.J.)+h+i+j+x.6+k+@+l+m+n+o+/+/+/+/+/+/+/+. . . . ", + " . . S , *.x T / / 3 . . . . . '.'.#.p+q+!.~.m 7 9 < 0 ' } r+* P @ # { s+% w , / e V 5 B -.j k _. .t+e+1+2+3+d.|.K.u.u+N.x..+O.v+w+x+y+z+/+/+/+/+/+/+/+/+/+/+. . . ", + " . . ; > > ^ , A+/ / e y ( . . . . . i.).B+$.C+7 9 : l.a } | * + D+t d Q % > , / f E+5 6 d+j k _.o.p.F+<.r.c.d.J.)+h+!+G+x.H+O.@+@+$+y+%+/+/+/+/+/+/+/+/+/+/+/+/+. . . . ", + " . . 2 % % /.-+> ^ S , Y.I+/ =.e . . . . . I $.C+L 9 J+K+a } & 4.+ P c d Q v L+S / f f g |+i j k ,+H.t+:.+.<.c.s.M+N+O+i+N.x..+~+@+#+P+]+%+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+. . . . ", + " . . # $ Q 2 s+6./.> > , , , , / / ;+y . . . . . 7 a+< U.Q+} | N R+P S+# u % > , / ( f V W i -.Z._.T+I...+.U+c.V+W+t.O+!+N.x.y.++X+@+#+$+%+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+/+. . . . ", + " . . @ t # Y+Y+Q Q &.% v v > c+c+S , , / =.( f . . . . . < q Z+) X.^.D+c Q Q % /., Y./ 4 V W i d+k Z T+`.q.+.<.r.d.}.`+)+!+N.x. @.+k+@+#+x+%+z+/+/+/+/+/+/+/+/+/+/+/+/+/+. . . . f f . ", + " . . + D+@ c # # $ Q Q Q }+% % /./.S S , *.T / ;+;+f . . . . . m.4.5.b @ # Q % R > , e f V W i 8.j k _.G ..+.'+<.c.4+`+)+h+v.w.y..@O.@+#+x+n++@/+/+/+/+/+/+/+/+/+/+/+. . . . f f f f f . ", + " . . . ^.+ + P b @ c t # - - u u &.% /.R c+c+S , A+/ / y f . . . . . 5.+ @ # Q ] /.L+A+=.f V W |+@@9.k _. .t++.b.g+c.W+|.1.!+u+j+#@~+O.@+l+#+$@8+/+/+/+/+/+/+/+/+/+. . . . f f f f f f f f . ", + " . . | N * * + + =+=+D+@ S+# %@%@- Q 2 % 6.v /.> , , , / T y f f . . . . . # Q % % > , / f E+V B -.9.k _.o.p.F+f+r.c.d.|.&@O+u+N.x..+++@+*@#+]+%+/+/+/+/+/+/+/+. . . =@f f f f f f f f f f -@. ", + " . . . W.D.| | 4.* 5.r + P b @ S+# # Y+- Q Q }+% ; -+> w w S , I+/ / 3 f . . . . . ; > , A+f V g ;@i j k _.>@`...+.r.c.d.|.&@,@'@G+x..+O.)@@+x+$+z+/+/+/+/+/+. . . T / ( y f f f f f f f f f f . . ", + " . . . a } V.} W.| r+4.* ^.* + D+@ @ @ # # - Q Q ] 2 ; /.-+> w (., A+Y./ f f . . . . . , / / U V X @@j k Z .t+a.+.<.c.d.|.K.O+!+G+x.y.!@P.Q.~@$+8+/+/+/+. . . ; > w ^ , T / 3 f f f f f f f f f . . ", + " . {@. . . . Z+} ) D.m.| r+* * 5.r + D+@ S+c # # - Q Q s+% % -+> c+(., , / / / / f . . . . . f g B i j k _._.`.q.+.<.c.]@ +1.O+!+N.x..+!@)@^@#+$+%+%+. . . # - Q % % % > L+w Y./ / / f f f f f f f . . ", + " . /@(@_@:@. . . . [ } } W.| N ! * * R++ + @ @ c c # # # Q u 2 % % ; > L+, , *./ / =.;+f . . . . . i j 9.E >@G ..+.'+c.<@4+&@)+!+N.G+.+O.O.l+#+@+. . . O s @ c c $ Q Q 2 % % > c+, I+x ;+f f f f f f . ", + " . [@/@}@/@/@/@. . . . q } } W.V.! ! N * + O + b b [+t c # $ Q u 2 ] % v R > > ^ *.A+I+/ e f f . . . . 9.E _. ...+.'+[.V+}.|.)+!+v.x..+6+{+.+. . . *+X.r+* r + s @ S+c { - Q s+% > > (., *./ f f f f f . ", + " . |@|@|@1@}@2@/@}@/@. . . . Q+[ } W.| N & * * R++ D+=+@ S+~ # # %@Q Q ] % R -+> ^ , w , , / =.;+f . . . . . ...3@<.4@3+}.|.)+!+u+w.x.)+. . . 0 q } [ V.| & 4.+ R++ b @ # # Q Q &.% 6.> > , A+x ( f f . ", + " . 5@5@6@|@7@|@|@8@}@}@2@/@. . . . ' } ) | | X.| * * ^.+ P 1 @ @ ~ # d Y+Q Q % % v > v w , , *.T / =.f f . . . . . 9@2+,.d.|.t.!+!+b.. . . <+9 o b+p 0 q Z+} ) | N * O + s @ t = d - Q % % -+> ^ , *./ . ", + " . 0@5@a@a@b@c@6@7@|@|@[@8@|@8@. . . . . } ) W.W.N & r+* * r + s 1 @ # # # { - Q u % % ; ; > c+, , , I+/ ( f f . . . . . d.M+t.j . . . $.0+m :+7 M 9 9 < U.q Z+} ) *+& 4.* O + @ @ c # { - }+% % R ^ , . ", + " . d@e@f@f@g@5@5@h@b@5@h@|@b@|@|@|@|@. . . . Z+} } | | & X.r+5.i@+ s D+@ [+t # # Q Q 2 &.% % /.R > c+, , T T / y f . . . . . . . . H 3.I !.$.%.~.C+7 {.a+T.: C.< q q } D.| r+* ^.+ =+1 @ c # - Q s+% v . ", + " . j@k@d@d@d@d@g@f@e@d@l@5@5@a@b@6@c@6@|@|@. . . . [ } } m.| | r+* * + + =+D+@ ~ ~ # m@n@n@Q &.% % v > c+(., , Y./ / =.f . . . '.h.#.#.o@H I I J $.K m C+7 M M ].< U.p q ' D.m.| ! * O + @ @ c @ d d 2 . ", + " . p@q@q@r@r@r@j@s@d@d@f@e@5@l@0@5@5@b@b@c@7@7@7@. . . . } V.V.) | & * * * + s t@u@v@v@w@m@n@x@y@u % v % > > (., , *.x / Y.. . z@A@B@'.2.#.#.p+j.I !.$.C@_+:+C+<+8 9 o < U.0 D@} W.m.| r+* O + s @ t # . ", + " . E@E@F@F@G@q@q@H@H@I@d@H@d@d@d@d@5@f@5@5@5@5@5@c@h@. . . . [ Z+) ) m.| 4.J@K@L@M@N@O@v@w@m@P@x@Q@R@S@] % 6.6.> > w , , . . T@U@V@W@X@Y@X@h.2.#.#.H B.I !.$.$._+Z@7 7 9 T.o < l.q q } } | | X.^.r D+=+. ", + " . `@E@E@E@E@F@G@ #p@q@q@q@q@d@k@d@H@d@d@g@f@g@d@5@0@5@5@6@. . . . Z+} .#+#@###$#L@%#M@O@O@&#P@P@n@n@*#=#S@&.}+% 6.-+> > . . -#T@;#U@>#z@,#X@Y@'#@.#.)#!#H I I I $.K m 7 7 7 9 9 T.< q q } } D.r+4.* 5.. ", + " . ~#~#~#{#~#E@E@E@]#G@^#^# #p@q@q@q@j@k@j@k@d@d@d@d@0@0@e@l@0@5@/#(#_#:#<#.#[#}#K@K@L@M@|#O@#2#3#4#4#x@R@5#6#% }+v . . 7#8#9#0#a#U@T@U@U@,#b#X@c#'.#.#.)#H 3.I l $.$.m m 7 7 M 9 9 < 0 q D@} *+| | . ", + " . d#e#f#~#~#~#g#h#{#{#E@i#E@E@q@F@p@]#q@q@q@q@q@j@d@k@d@d@d@j#k#l#m#n#o#:#:#p#+#}#q#$#$#$#M@M@u@v@1#r#s#3#t#u#v#5#w#x#. . y#z#A#B#C#D#a#E#F#G#V@z@H#X@I#'.@.#.#.H H B.I $.$.0+K :+7 M M : : < q q ' } . ", + " . J#K#K#K#K#L#~#~#~#~#~#~#{#{#i#E@E@^#]#G@]#q@q@^#q@I@H@M#M#N#O#k#k#l#P#Q#_#R#:#S#[#[#J@$#$#T#T#u@U#1#1#P@3#t#t#u#V#W#X#Y#Z#`# $y#z#7#7#D#D#-#.$U@U@+$z@@$H#'#'.2.2.#.p+j.I I l $.%.m m 7 7 9 ].< C.q . ", + " . #$J#K#$$$$%$K#K#L#K#L#f#~#f#~#~#`@`@E@E@E@E@E@E@q@&$*$=$=$-$-$;$O#>$>$,$,$Q#:#:#S#S#'$q#J@$#$#T#)$!$U#1#1#s#~$t#t#{$W#]$^$^$/$($`#_$y#:$7#9#D#<$a#E#U@+$[$b#X@X@A@'.2.#.p+H H B.!.!.~._+m }$7 a+9 ].. ", + " . =@|$#$#$#$1$2$K##$%$K#K#L#e#f#e#~#L#~#~#~#{#3$4$5$6$7$7$8$&$*$-$-$9$9$>$0$0$P#P#Q#S#S#'$'$'$a$b$T#c$!$!$#2#3#d$e$f$g$]$^$^$h$/$i$`#j$k$y#7#7#l$<$m$E#;#U@+$z@z@H#'.'.@.#.#.i.H q+I J $.K K :+C+7 . ", + " . n$o$p$=@o$q$#$q$#$#$#$J##$$$%$$$K#K#e#e#r$s$s$t$4$5$5$u$v$7$w$w$w$-$x$9$>$>$0$y$P#z$A$B$'$'$'$C$b$T#D$D$!$E$#F$F$G$H$I$J$K$^$L$Y#h$($($`#`#y#y#M$7#C#D#E#E#N$U@>#z@b#X@'#'.z.#.#.p+H j.!.O$K 0+m . ", + " . P$P$n$=@=@=@=@p$p$o$#$#$#$#$#$Q$K#Q$R$R$S$T$r$s$t$t$U$5$6$V$6$w$w$W$x$-$X$;$>$0$y$y$z$z$Y$Z$`$'$ % %.%T#T#!$u@+%@%#%$%%%&%*%=%J$K$-%;%>%>%($,%'%`#`#y#z#7#)%D#0#E#;#N$U@z@,#@$X@Y@'.S.#.o@H I j.I J . ", + " . !%!%~%P${%!%n$!%=@=@=@=@=@p$#$]%^%/%/%/%(%S$T$_%:%s$<%t$5$5$5$6$u$7$w$w$-$X$X$>$[%>$y$y$Y$Y$A$`$}%C$ %.%.%|%1%+%+%2%3%4%$%%%*%5%I$J$K$^$;%>%6%7%,%8%9%0%k$:$7#8#8#D#a%E#.$U@[$z@z@X@Y@Y@S.@.#.A.H q+. ", + " . b%b%c%b%d%d%!%!%!%e%f%e%n$g%g%g%^%h%h%i%j%/%R$R$T$_%:%s$k%U$U$4$6$u$V$w$7$w$x$X$X$l%l%0$m%n%z$A$o%`$p%q%.%.%|%r%+%s%2%2%3%t%u%v%*%5%J$]$w%L$x%y%6%7%,%'%z%A%`#y#B%7#l$l$D#E#E#T@[$C%z@H#X@A@I#z.#.A.. ", + " . D%E%F%F%b%b%G%b%~%~%H%I%I%I%J%J%J%g%I%I%g%]%(%R$_%R$T$T$K%k%K%U$L%M%N%u$w$O%P%Q%X$X$X$[%R%0$n%n%z$Y$Z$Z$S%q%T%|%U%V%W%s%X%3%t%4%u%v%*%Y%J$J$Z%;%;%y%y%`%8% &9%.&`#+&y#7#7#B#D#0#E#E#U@U@@&#&W@X@B@&+. ", + " . $&E%E%E%%&E%&&b%b%*&=&-&;&I%;&I%>&I%I%I%I%g%h%]%/%,&_%_%'&'&k%k%L%U$M%)&N%u$!&O%x$x$W$X$~&~&{&{&0$]&z$Y$Z$Z$T%.%^&/&U%W%s%(&2%_&3%:&u%v%<&[&}&K$K$;%>%y%y%,%8%9%9%z%|&`#y#:$7#7#C#m$E#E#.$U@U@z@@$X@. ", + " . 1&$&E%2&3&4&5&6&6&*&7&6&=&=&*&=&>&-&8&-&I%I%J%g%h%]%,&(%R$_%9&9&'&k%0&L%)&)&u$v$O%!&W$P%W$X$~&~&[%a&z$Y$b&o%c&.%d&d&e&/&U%W%s%X%2%3%t%f&f&g&<&<&h&i&Z%Z%j&y%y%k&l& &m&.&|&n&0%y#z#A#)%D#<$E#;#T@>#@&. ", + " . o&1&1&1&p&p&q&q&p&6&6&6&6&6&*&*&r&8&7&=&8&8&I%;&s&g%]%]%]%,&,&_%9&'&:%K%L%L%U$t&)&!&!&!&W$P%u&v&~&[%{&{&a&Y$w& %T%T%x&y&y&U%z&A&A&B&C&D&D&E&v%v%v%F&G&i&Z%H&x%I&J&K&8%9%m&.&|&L&M& $y#M$7#8#D#m$a%U@. ", + " . N&o&O&O&P&Q&q&q&p&6&q&q&6&6&5&6&6&6&6&=&7&*&*&=&;&;&g%R&^%^%,&,&S&T&T&U&U&k%L%L%M%N%V&W&O%!&X&u&v&Y&v&{&m%m%Z&C$Z&`&c&x&x&y&y& *.*+*s%2%C&D&t%@*f&v%<&#*G&$*%*H&x%y%`%l&8%9%m&A%&*n&**=*y#y#7#7#9#m$. ", + " . -*-*P&O&P&P&P&P&O&p&;*Q&p&p&p&q&q&5&6&q&6&6&6&6&*&=&=&>*s&s&,*'*,&)*S&T&T&!*k%k%L%M%M%V&t&!&O%P%P%X&Y&v&v&{&~*'$~*{*]*]*c&x&x&^*^& *+*/*(*_*D&t%:*E&<*[*F&#*G&$*%*}*I&I&`%K& &9%m&&*|*n&**1* $y#2*2*. ", + " 3*4*5*-*-*-*-*O&-*P&O&P&6*P&P&Q&p&p&q&p&6&5&q&6&6&6&q&6&*&7*7*>*s&,*8*8*9*S&T&U&0*U&a*b*M%M%V&W&W&c*c*X&X&Y&d*e*'$f*g*h*{*]*i*j*x&x&k* * *l*(*(*_*C&m*@*f&n*[*F&#*G&o*%*}*p*q*r*K&s*t*m&&*|*u*v*w*x*k$. ", + " 3*y*z*4*4*A*-*-*-*-*-*-*P&P&P&O&P&p&p&P&P&;*B*p&p&q&q&q&6&6&7&=&C*7*,*8*8*8*9*T&D*E*!*a*a*F*G*H*V&I*W&W&c*J*~*K*'$L*M*f*g*h*N*]*i*c&x&^*y&O* *l*P*(*Q*R*m*S*E&<*T*F&U*G&V*W*X*X*q*r*l&s*Y*Z*`*|***** =.= ", + " +=y*@=@=#=4*4*4*5*$=%=-*-*-*-*O&O&P&-*P&P&Q&Q&P&q&p&;*q&q&q&7&q&7&C*s&,*,*'*8*9*&=*=D*!*U&a*F*G*M%V&t&W&W&==c*I*S#-=;=L*>=,='=)=h*]*i*j*j*^*O*!=~=/*{=]=Q*^=S*S*<*<*T*F&/=o*(=W*X*X*J&r*_=s*:=`*I$<=-%.= ", + " +=[=}=}=[=y*@=y*z*|=z*4*1=1=-*$=-*%=-*-*-*P&P&-*P&P&P&Q&p&q&q&p&q&7&7&C*7*,*,*8*8*D*&=D*!*!*a*a*a*F*G*V&2=W&3=4=:#5=-=-=6=7=>=8=9=h*0=a=b=c=^*O*O*!=l*d={=e=R*R*R*S*E&n*F&U*U*f=o*W*g=X*h=r*G$G$&%H$I$i= ", + " j=k=l=m=l=}=}=}=}=[=@=#=@=4*#=n=1=$=o=-*1=p=-*-*P&q=-*q=-*P&O&O&;*q&6&r=C*7*7*s=t=u=&=v=9*D*0*0*a*a*F*w=w=w=2=x=:#y=z=A=B=B=6=8=C=D='=h*N*E=F=F=G=^*H=H=l*d={=I=e=R*J=K=L=L=M=N=U*o*O=P=4%Q=R=R=G$*%H${$ ", + " j=S=T=k=U=k=V=k=k=}=m=[=[=@=@=y*y*@=n=W=1=X=X=$=-*-*p=-*-*-*q=-*-*O&;*;*7&7&7&C*t=t=Y=v=&=&=*=D*D*0*a*Z=G*`= -5=_#.-+-@-#-$-%-B=&-6=7=,=*-N*=-E=----;-O*O* *l*>-d=]=,-J='-'-L=n*N=)-B&X%X%_&_&!-Q=R=R=~- ", + " j={-S={-S=S=T=S=T=k=k=V=k=V=l=[=[=[=y*y*y*n=n=o=o=n=$=p=1=%=%=$=-*-*P&O&;*;*]-r=r&C*^-t=t=/-&=/-0*0*0*0*Z=`=F*(-_-:-<-.-[-#-A=}-$-|-&-1-2-*-3-4-0=E=5-6-;-f$7-8-l*d=9-]=,-J=0-U%a-z&W%W%s%2%2%2%_&3%4%F$ ", + " b-c-c-c-d-{-d-{-S=S=S=S=T=T=k=k=V=k=V=}=[=[=y*@=n=o=e-n=1=o=1=$=p=%=-*-*P&O&;*r=]-7&f-g-t=t=Y=h-&=D**=0*0*i-j-k-(#l-m-n-.-[-@-#-o-$-p-B=&-q-2-2-3-4-r-E=5-;-G=f$H=s-8-d=x&x&y&y&q%U%U%z&W%s%s%X%2%_&2%F$ ", + " t-c-u-c-c-c-v-d-{-w-{-w-S=x-S=S=S=U=k=l=k=k=V=}=}=[=e-e-e-W=e-e-o=o=n=$=$=-*y-O&;*]-]-z-C*g-^-Y=Y=A-&=B-B-C-i-D-n#E-F-l-G-H-.-.-@-I-}-}-B=J-1->=2-3-K-4-r-5-L-6-M-f$]*]*i*c&j*x&^*^*y&e&q%z&z&N-A&s%B&+% ", + " t-O-u-u-u-u-P-Q-c-c-c-v-c-R-{-S-{-S=S=T=S=k=S=k=k=T-}=m=}=e-e-e-e-e-n=1=n=$=$=y-U-6*V-W-X-f-f-g-Y-Z-A-/-B-B-`- ;/#.;+;@;l-#;H-H-.-[-I-I-}-$;p-J->=>=2-%;4-&;r-,=3-,={*Z&]**;a=i*c&=;x&-;y&!=/&U%a-+*s%+% ", + " t-;;>;,;;;O-u-u-';Q-u-Q-Q-P-c-d-);d-);w-!;S=S=U=T=T=k=T=k=V=}=l=e-~;e-e-e-n=$={;y-$=y-U-V-];]-f-f-Y-^;Z-/;/;/;(;_;:;.;.;<;@;l-[;};n-.-|;I-1;}-$;2;J-3;4;%;6=6=6=8=8=,=3-3-h*]*a=a=i*c&j*x&x&^&!=y&U%+*+% ", + " 5;6;;;;;;;;;;;7;8;O-u-O-O-';';';';Q-c-c-);{-);w-{-{-S=k=S=U=T=k=V=k=m=e-e-~;e-e-{;1={;U-U-];V-];9;9;g-Y-^;^;/;0;_;a;a;:;.;.;b;@;[;G-H-c;[-|;I-d;$;$;J-o-}-B=B=|-&-6=8=8=,=9=3-h*0=]*`&e;a=c&x&d&^&^&y&|% ", + " f;g;g;h;h;i;j;j;;;;;8;>;k;O-u-u-O-c-u-u-';c-c-c-);c-d-w-w-S=S=S=S=T=U=k=k=V=l;l;~;m;e-1=n;o;V-U-];p;9;g-q;g-0;r;s;t;u;u;:;:;.;v;+;b;[;};w;w;x;y;[-|;|;I-o-z;}-$-%-B=&-6=6=8=8=,=*-h*h*0=]*]*i*j*j*j*x&|% ", + " f;A;B;g;g;g;g;g;h;j;6;6;;;k;;;;;O-;;O-k;u-u-c-Q-';';';c-v-);c-w-);d-S=S=U=S=S=T=S=l;~;m;{;{;C;y-y-V-];9;p;p;g-D;s;E;F;G;H;I;:;:;J;<;<;K;[;L;L;H-H-M;y;[-|;I-I-}-}-$-%-p-B=6=6=C=7=8=,=)=h*N;0=]*]*i*c&|% ", + " f;O;P;Q;R;P;Q;S;g;g;g;g;g;i;j;j;;;;;;;;;7;k;O-O-u-u-u-P-';P-u-c-c-);d-w-S={-S=!;S=S=U=k=~;{;{;n;y-o;U-T;p;p;p;U;V;W;X;Y;Y;G;Z;u;:;`;J; >b;b;.>[;};H-n-n-c;[-[-I-#-#-o-$-$-p-|-&-6=6=q-8=8=9=9=h*h*0=]*+> ", + " @>O;#>O;$>#>O;P;P;P;P;S;g;g;g;g;i;h;j;6;6;6;;;;;;;,;>;k;u-u-u-u-';u-';c-c-c-);{-);{-{-S-S=S=U=%>{;&>&>o;*>W-=>U;->;>>>,>'>Y;)>)>!>`;J;~>~>{>{>K;@;]>[;G-H-M;w;y;|;[-@-I-d;z;$-p-B=B=|-6=6=M*8=9=9=h*h*.% ", + " ^>/>(>_>(>_>_>O;O;O;$>O;A;A;P;P;S;R;g;g;i;i;i;6;6;;;;;;;;;k;k;u-O-u-O-u-Q-u-c-c-';c-c-);w-d-S=S-S-:><>n;[>[>o;}>|>1>2>3>W;'>'>)>4>5>6>7>8>J;~>~>{>{>b;K;[;[;H-H-.-c;y;[-[-#-#-}-}-p-$-B=|-&-6=>=8=,=,=.% ", + " 9>0>0>0>a>a>(>/>_>_>#>b>O;O;P;$>P;P;P;Q;g;S;c>g;g;h;i;d>j;6;e>;;;;;;k;u-;;O-u-O-Q-Q-';c-';c-);););{-S-S=n;n;[>f>|>g>g>2>'>h>h>h>h>i>)>!>7>7>8>`;`;~>~>b;b;K;.>[;[;m-w;w;c;.-[-j>I-#-z;}-k>B=B=B=&->=>=.% ", + " 9>l>m>n>0>0>0>0>a>o>(>(>_>_>p>#>p>O;O;P;P;Q;P;Q;g;g;g;g;i;g;i;h;e>j;q>;;;;;;8;7;8;>;u-O-u-u-O-';r>c-c-););w-);s>|>t>u>v>3>w>,>,>'>h>x>)>i>y>5>z>7>`;`;A>~>B>{>K;b;[;L;};H-<-w;c;[-|;#-I-#-}-}-$-B=B=C> % ", + " D>E>F>m>m>m>G>0>0>n>0>0>0>o>_>o>(>_>_>#>#>#>O;#>P;P;P;A;P;B;g;B;g;i;H>i;i;6;;;h;;;;;8;7;O-O-O-u-u-Q-I>';Q-c-c-J>K>L>M>N>O>u>v>w>P>w>Q>R>S>h>)>)>4>!>7>6>`;`;J;~>b;{>b;.>K;[;T>H-U>c;c;[-|;@-#-#-$-}-V> % ", + " W>X>E>E>m>Y>m>Y>Z>`>n>0>0>0>l>0>0>0>(>0>(>/>(>_>_>#>#>O;P;P;P;P;A;B;A;R;g;g;g;j;i;i;i;;;;;;;;;;;8;k;8;O-u-O-u- ,K>.,+,@,M>M>#,u>v>3>P>,>Q>$,$,h>)>i>%,4>6>7>6>`;J;~>~>+;b;]>]>[;L;H-w;w;y;.-[-|;#-#-o-'$ ", + " &,X>X>*,X>X>X>X>E>E>=,m>`>m>`>l>-,l>n>0>0>0>;,;,a>o>(>_>_>O;P;#>#>P;O;P;c>B;P;c>B;g;i;i;i;6;;;e>6;;;7;;;,;O-O->,_;,,',.,),!,L>N>N>#,v>v>~,w>w>w>h>h>{,i>y>4>4>7>6>:;`;J;~>{>{>b;]>.>[;L;w;w;c;[-.-[-#-'$ ", + " &,],],],],^,*,],/,X>X>E>E>E>Y>m>m>m>`>n>`>l>G>l>0>0>0>(,;,o>(>_>(>#>O;p>#>#>P;P;P;c>A;S;g;g;g;g;i;j;i;;;;;6;;;_,s;:,<,[,},.,),+,|,L>M>N>#,v>v>P>w>w>$,h>h>S>)>)>4>7>7>6>`;A>~>{>b;b;b;]>.>[;L;w;H-c;[-'$ ", + " &,1,2,3,4,2,],],],5,^,^,X>X>E>E>E>F>6,E>Y>`>`>l>`>`>`>n>l>0>o>a>_>(>_>_>_>#>p>O;O;P;$>P;P;P;g;c>g;c>g;g;i;q>i;7,s;8,8,9,:,[,[,',),.,),M>N>N>N>v>v>v>w>w>,>Q>$,Y;i>)>y>!>5>6>:;`;`;~>{>{>b;K;[;[;};H-U>'$ ", + " 0,a,a,b,a,3,3,2,3,4,],],],*,^,],^,X>X>E>E>E>E>E>6,`>m>m>`>Z>G>`>l>0>0>0>a>_>(>p>(>#>#>#>$>P;#>P;P;P;P;P;B;g;i;c,s;d,e,f,8,:,<,:,[,[,',',),@,M>N>M>#,g,v>h,P>w>'>$,h>S>)>y>y>4>6>7>`;`;~>B>b;b;b;]>[;L;S# ", + " i,j,k,k,b,j,b,a,3,3,3,2,l,3,],l,],],*,/,/,X>m,E>X>Y>Y>=,F>F>F>m>-,-,l>n>`>0>0>0>o>o>o>p>(>#>p>#>#>b>O;P;n,P;c>c,V;o,p,q,e,r,r,s,9,9,<,,,},.,.,+,L>M>M>N>O>v>v>3>w>Q>'>h>h>{,)>y>4>4>6>6>`;`;~>~>b;b;b;S# ", + " t,u,u,j,v,k,k,j,k,a,w,a,b,a,a,3,1,4,x,],l,],],/,X>X>^,y,E>Y>=,=,m>z,`>`>m>l>n>n>l>0>G>0>0>o>(>/>_>#>#>#>O;$>$>A,V;B,C,o,p,D,e,e,r,8,E,9,<,[,},',.,.,!,M>M>F,O>O>~,3>P>w>$,Q>h>S>Y;G,y>4>7>6>8>`;J;~>~>:# ", + " t,H,I,u,u,J,u,j,j,K,k,j,j,k,k,b,b,a,a,3,1,4,4,],4,],],/,/,^,X>/,*,E>E>E>E>`>m>`>`>`>`>m>0>-,0>0>0>0>(>/>_>/>p>L,|>M,N,N,C,O,P,Q,D,e,f,e,8,9,9,<,[,',.,),),|,M>N>N>u>u>v>P>w>w>,>$,h>S>)>y>4>4>7>:;8>`;R, ", + " S,T,H,H,I,U,V,V,u,v,W,u,X,j,k,k,b,b,b,b,a,a,a,3,3,3,Y,x,x,],],],],],X>X>E>E>E>E>=,F>`>`>z,`>m>`>0>G>l>0>0>0>0>L,|>Z,`, '.'N,N,+'o,P,P,e,e,@'8,9,8,:,<,[,,,#'),),M>M>F,N>u>v>3>w>,>,>h>h>h>S>i>y>4>4>6>:# ", + " S,$'%'%'T,T,I,U,I,V,U,H,u,u,J,J,u,v,v,j,j,k,b,b,a,a,b,3,3,1,l,3,],l,x,*,],*,*,/,m,X>m,E>F>Y>`>z,m>m>`>`>m>-,G>&'|>*'Z,Z,Z,=' 'M,N,B,-'o,o,d,D,e,;'8,8,9,>'[,,,',),),+,M>M>N>N>v>v>h,w>$,h>h>h>{,)>)>%,:# ", + " ,''''''''')')')'!')'I,T,T,I,H,u,u,u,u,v,W,v,j,j,j,j,k,~'~'{'a,3,3,3,2,x,4,],],],],/,*,y,/,X>m,E>z,E>F>F>Y>`>`>]'|>^'/'('*'Z,_':'M,M,M,N,o,o,<'P,D,D,e,8,s,9,:,<,[,['.,.,),M>@,M>#,O>}'v>3>w>w>h>h>h>S>_# ", + " |'1'2'3'4'''''''5'''%'T,)'T,T,I,H,u,I,6'u,u,u,v,u,u,X,v,j,j,j,7'b,a,a,b,3,3,3,Y,l,],Y,],*,*,*,*,*,X>X>E>E>E>Y>8'|>9'9'0'a'('('b'*'Z,='M,N,c'B,o,o,Q,P,Q,q,e,8,8,9,<,<,[,.,.,),),M>M>F,N>d'u>h,w>w>,>$,o# ", + " e'f'g'1'1'1'2'h'4'''4'''''''%'%'%'I,T,T,I,T,u,6'u,u,u,u,J,v,j,J,j,k,k,j,i'b,a,a,3,3,2,],4,x,],],],],^,/,/,*,X>j'k'l'l'm'n'o'p'/'('('*'_'Z,='M,q'.'-'r'o,Q,D,e,e,8,8,8,9,<,[,',',s'),L>M>M>N>O>v>3>3>w>/# ", + " t'u'v'v'e'w'x'w'1'y'1'3'3'4'4'''''5'%''')')'T,T,T,T,I,u,u,u,u,u,v,J,K,j,v,k,k,b,b,a,a,b,3,3,3,3,1,l,l,],*,*,],z'A'B'C'D'l'l'9'n'0'^'('('E'*'_'='='='F'N,O,o,P,P,P,D,e,f,8,9,:,[,[,,,.,),L>@,M>N>O>u>u>G' ", + " H'I'J'K'K'v'g'L'L'w'w'M'1'1'y'''3'N'2'''%'%'%')'%'T,T,T,T,I,T,I,u,H,u,u,u,u,j,j,k,~'b,b,~'7'3,7'3,3,3,2,1,Y,O'P'Q'R'S'B'B'l'l'o'o'T'0'p'('*'E'_' 'U'='.'N,N,O,o,D,e,D,e,f,8,8,:,V'[,[,.,',),@,|,M>/#W' ", + " X'Y'Z'`'`' ) ) )g'L'.)L'+)1'w'1'1'3'1'2'''''''''%'%'%'!')'T,)'I,T,H,@)u,H,u,u,u,J,j,j,j,k,k,b,b,a,a,b,a,3,#)P'$)%)&)R'R'S'B'D'l'l'9'9'0'0'p'('*)Z,Z, 'U'='.'N,N,r'P,D,P,D,@'e,8,s,9,<,[,=)',),@,-) ", + " ;)>),)`'`'`'`'') )g'.).).)L'))w'w'))w'1'1'4'1'3'4'N'''''%'%')'%'T,T,T,T,I,T,V,H,u,u,u,u,K,v,J,J,k,~'b,~'!)~){)])^)/)/)()R'_)S'B'l'l'm'9'n'0'('('('b'Z,Z,=' 'M,N,N,C,o,o,p,e,e,e,8,8,9,:,<,[,_;:) ", + " <)[)})`'`'`'`'`' ) ) )|)1).).)L'L'L'L'L'w'))1'1'1'3'2'3'h'h'''%'%')')'T,!'T,T,T,T,6'u,u,H,u,u,u,j,J,j,2)P'3)4){)5)5)$)$)Q'Q'S'S'B'D'6)l'T'o'o'0'0'('('*)Z,Z,M,M,.'N,-'o,o,o,P,d,e,;'8,8,:,K> ", + " 7)8)9)0)J'`'`'`'`'`' ) )a)b)c)d).).)d).)L'.)e)1'))x'1'1'1'4'''''''''%'%')'%'!')')'I,I,U,U,V,u,I,u,u,f)g)h)i)j)4)k)l)5)])$)&)&)m)S'B'D'n)6)l'9'n'o'0'p'('E'_'o)Z,M,.'F'N,r'o,P,o,e,D,p)s;q) ", + " r)X's)t)u)v)`'`'`'`'K'w)K'a)b)b)x)1).).).).).)L'w'))))1'1'1'3'1'N'1'4'''y)''%')')'T,T,T,T,6'I,V,z)g)A)A)B)h)i)i)l){){)$)$)/)C)()R'S'B'B'C'l'm'9'o'0'a'D)('_'Z,_'M,='F'N,N,r'o,P,E)s; ", + " F)G)H)I)J)`'`'`'`'`'w) )w)b)b)b)c)K)L)d).).)d).)L'))))w'e)e)1'1'y'2'''4'4'%''')'%'M)T,T,T,N)O)P)A)A)Q)B)B)R)j)j){)5)5)5)$)$)Q'&)S'S'B'D'l'l'9'0'0'p'p'('('*'Z,:'M,F'M,N,-'V;S) ", + " T)U)I'V)J'`'`'`'`'w)w)w)W)c)c)b)c)c)c)L)b)d).).).)X)L'+)w'e)e)1'1'1'h'2'4'''''%')'%'Y)Z)`) !.!P)A)A)A)B)i)j)4)4)4)4)5)$)$)/)Q'&)S'S'B'D'l'm'9'0'0'p'a'('*'_'Z,Z,:'M,V; ", + " r)+!s)t)u)v)`'`'`'`'w)w)@!W)b)b)b)c)b)c)b)L)K).).)d)d)L'L'L'w'w'1'e)1'1'1'3'4'''#!Z)$!$!%!&!.! ! !P)A)*!B)=!i)l)l)4)5)5)$)$)Q'R'S'S'B'6)l'l'l'9'n'0'D)('*)E'_'|>-! ", + " ;!>!s),!'!)!`'`'`'`'!!w)W)b)~!b)b)b)c)b)b)b)c)b)K).).)L'.).)L'))))e)+)1'1'{!]!^!/!$!$!%!%!&!.! !P)(!Q)B)B)h)j)l){)5)^)$)$)Q'&)R'S'S'B'D'6)m'm'9'9'p'|>|>_! ", + " :!)[!}!`'`'`'`'!!!!!!|!~!~!~!c)b)b)c)c)b)b)c)K)x)L).)1).)X)L'L'))1!2!3!3!4!^!/!/!$!%!5!&!.!.! !A)A)B)h)i)i)l)4)5)5)$)$)%)R'&)R'S'B'n)l'k'6!7! ", + " 8!9![)0!a!b!`'`'`'`'!!!!!!|!~!~!b)~!c)c)b)b)b)c)b)c)c)L)d).).).)c!2!d!e!3!f!4!4!g!/!%!`)`)&!.!.!P)A)h!B)B)i)i!4)4){)5)])$)$)%)&)S'k'j!k! ", + " l!H's)m!n!o!`'`'`'`'!!!!|!~!~!~!~!p!b)b)c)c)b)b)b)b)b)b)K)q!2!r!r!s!e!e!3!3!4!4!/!/!`)%!`)`).!P)t!A)Q)B)u!i)j)l)l)4)5)5)P'v! ", + " w!x![)y!z!`'`'`'`'!!!!!!A!~!~!~!~!~!p!~!b)b)c)b)b)c)q!2!B!B!B!B!r!C!e!e!3!f!D!4!/!$!%!`)E!.!.!P)A)F!B)B)G!R)P'P'H! ", + " I!>)J!K!L!`'`'`'`'!!!!|!~!~!~!~!~!~!~!b)~!b)c)M!2!B!B!B!B!B!r!r!N!C!e!3!O!3!4!^!/!/!%!P!`).!.!t!(!Q!g)R! ", + " S!T!s)U!V!o!`'`'`'!!!!!!|!W!~!~!W!~!~!~!~!X!2!B!B!B!B!B!B!B!r!B!r!Y!e!Z!e!`!D!4!^!$!$!%!5!Z)O) ~ ", + " .~+~@~I)#~`'`'`'`'!!!!A!|!W!~!W!W!W!X!2!B!B!B!B!B!B!B!B!B!B!r!r!r!r!e!Z!3!D!D!g!Z)O)$~ ", + " %~8)u'&~L!`'`'`'`'!!!!|!W!~!W!X!2!B!B!B!B!B!B!B!B!B!B!B!B!B!B!r!r!d!3!2!*~=~ ", + " -~T!s);~>~v)`'`'`'!!!!!!A!X!2!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!B!2!,~'~ ", + " )~t)s)!~~~)!`'`'`'!!{~2!B!B!B!B!B!B!B!B!B!B!B!B!B!B!2!,~]~ ", + " :!U)U)^~/~`'`'`'(~2!B!B!B!B!B!B!B!B!B!B!B!2!_~ ", + " :~<~@~+~[~b!`'}~2!B!B!B!B!B!B!B!B!2!|~ ", + " 1~2~3~,!'!4~2!B!B!B!B!B!2!5~ ", + " 6~x!@~7~2!B!8~2!9~ ", + " 0~a~2!b~ ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " "}; + """ + +def tankWeight(obj, angles=Vector(0.0,0.0,0.0), cor=Vector(0.0,0.0,0.0)): + """ Compute tank fluid weight and their center of gravity. + @param obj Tank object. + @param angles Tank angles, Roll, Pitch and Yaw. + @param cor Center or rotation. + @return Weight and center of gravity. None if errors detected + """ + # Test if is a tank instance + props = obj.PropertiesList + try: + props.index("IsShipTank") + except ValueError: + return None + if not obj.IsShipTank: + return None + # Get object solids + Solids = obj.Shape.Solids + W = [0.0, 0.0, 0.0, 0.0] + for s in Solids: + # Get fluid volume + bbox = s.BoundBox + z0 = bbox.ZMin + z1 = bbox.ZMax + dz = obj.Level/100.0 * (z1-z0) + z = z0 + dz + dx = bbox.XMax-bbox.XMin + dy = bbox.YMax-bbox.YMin + box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) + fluid = s.common(box) + vol = fluid.Volume + W[0] = W[0] + vol*obj.Density + # Compute fluid solid in rotated position (non linear rotation + # are ussually computed as Roll -> Pitch -> Yaw). + s.rotate(cor, Vector(1.0,0.0,0.0), angles.x) + s.rotate(cor, Vector(0.0,1.0,0.0), angles.y) + s.rotate(cor, Vector(0.0,0.0,1.0), angles.z) + bbox = s.BoundBox + z0 = bbox.ZMin + z1 = bbox.ZMax + dx = bbox.XMax-bbox.XMin + dy = bbox.YMax-bbox.YMin + Error = 0.01*vol + z = 0.0 + v = 0.0 + while(abs(vol - v) > Error): + z = z + (vol - v) / (dx*dy) + dz = z - z0 + box = Part.makeBox(3.0*(dx), 3.0*(dy), (z1-z0)+dz, Vector(bbox.XMin-dx, bbox.YMin-dy, bbox.ZMin-(z1-z0))) + fluid = s.common(box) + v = fluid.Volume + if(abs(vol - v) / (dx*dy) <= 0.000001): + break + # Add fluid moments + for f in fluid.Solids: + cog = f.CenterOfMass + W[1] = W[1] + f.Volume*obj.Density*cog.x + W[2] = W[2] + f.Volume*obj.Density*cog.y + W[3] = W[3] + f.Volume*obj.Density*cog.z + return [W[0], W[1]/W[0], W[2]/W[0], W[3]/W[0]] diff --git a/src/Mod/Ship/shipCreateShip/TaskPanel.py b/src/Mod/Ship/shipCreateShip/TaskPanel.py index bec74302ad..cbb5319c84 100644 --- a/src/Mod/Ship/shipCreateShip/TaskPanel.py +++ b/src/Mod/Ship/shipCreateShip/TaskPanel.py @@ -49,6 +49,7 @@ class TaskPanel: obj.Draft = self.form.draft.value() # Discretize it ship.discretize(self.form.nSections.value(), self.form.nPoints.value()) + App.ActiveDocument.recompute() return True def reject(self): diff --git a/src/Mod/Ship/shipHydrostatics/Tools.py b/src/Mod/Ship/shipHydrostatics/Tools.py index a2b1f2c65f..2c0e5aa36b 100644 --- a/src/Mod/Ship/shipHydrostatics/Tools.py +++ b/src/Mod/Ship/shipHydrostatics/Tools.py @@ -116,7 +116,7 @@ def Displacement(ship, draft, trim): @param ship Selected ship instance @param draft Draft. @param trim Trim in degrees. - @return [areas,disp,xcb]: \n + @return [areas,disp,xcb,Cb]: \n areas : Area of each section \n disp: Ship displacement \n xcb: X bouyance center coordinate @@ -439,9 +439,9 @@ def KBT(ship, draft, trim, roll=0.0): @param draft Draft. @param trim Trim in degrees. @param roll Roll angle in degrees. - @return [KBTx, KBTy]: \n - KBTy : TRansversal KB y coordinate \n - KBTz : TRansversal KB z coordinate + @return [KBTy, KBTz]: \n + KBTy : Transversal KB y coordinate \n + KBTz : Transversal KB z coordinate """ angle = math.radians(trim) rAngle = math.radians(roll) diff --git a/src/Mod/Ship/shipLoadExample/TaskPanel.ui b/src/Mod/Ship/shipLoadExample/TaskPanel.ui index 77d7441895..3c875d905a 100644 --- a/src/Mod/Ship/shipLoadExample/TaskPanel.ui +++ b/src/Mod/Ship/shipLoadExample/TaskPanel.ui @@ -76,7 +76,7 @@ - Serie 60 from Iowa University + Series 60 from Iowa University @@ -86,7 +86,7 @@ - Serie 60 (Katamaran) + Series 60 (Katamaran) diff --git a/src/Mod/Ship/tankCreateTank/TaskPanel.py b/src/Mod/Ship/tankCreateTank/TaskPanel.py new file mode 100644 index 0000000000..4eddbd03e7 --- /dev/null +++ b/src/Mod/Ship/tankCreateTank/TaskPanel.py @@ -0,0 +1,167 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# Module +from TankInstance import * +from shipUtils import Paths, Translator + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/tankCreateTank/TaskPanel.ui" + + def accept(self): + # Create new ship instance + obj = App.ActiveDocument.addObject("Part::FeaturePython","Tank") + ShipTank(obj, self.solid, self.form.level.value(), self.form.dens.value()) + if not obj.IsShipTank: + msg = Translator.translate("Tank has not been created.\n") + App.Console.PrintError(msg) + ViewProviderShipTank(obj.ViewObject) + App.ActiveDocument.recompute() + return True + + def reject(self): + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.level = form.findChild(QtGui.QDoubleSpinBox, "Level") + form.dens = form.findChild(QtGui.QDoubleSpinBox, "Density") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + # Connect Signals and Slots + QtCore.QObject.connect(form.level, QtCore.SIGNAL("valueChanged(double)"), self.onLevel) + QtCore.QObject.connect(form.dens , QtCore.SIGNAL("valueChanged(double)"), self.onDens) + + 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 initValues(self): + """ Get selected geometry. + @return False if sucessfully find valid geometry. + """ + self.solid = None + solids = [] + selObjs = Gui.Selection.getSelection() + if not selObjs: + msg = Translator.translate("Tank objects can only be created on top of structure geometry (no object selected).\n") + App.Console.PrintError(msg) + msg = Translator.translate("Please create a tank geometry before using this tool.\n") + App.Console.PrintError(msg) + return True + for i in range(0, len(selObjs)): + solid = selObjs[i] + if solid.isDerivedFrom('Part::Feature'): + # Get shape + shape = solid.Shape + if not shape: + continue + solid = shape + if not solid.isDerivedFrom('Part::TopoShape'): + return None + # Get shells + shells = solid.Shells + if not shells: + continue + # Build solids + for s in shells: + solids.append(Part.Solid(s)) + if not solids: + msg = Translator.translate("Ship objects can only be created on top of structure geometry (no solids can't be computed).\n") + App.Console.PrintError(msg) + msg = Translator.translate("Please create or download a tank geometry before using this tool\n") + App.Console.PrintError(msg) + return True + self.solid = Part.CompSolid(solids) + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("Create a new tank")) + name = Translator.translate("Filling level") + " (%)" + self.form.findChild(QtGui.QLabel, "LevelLabel").setText(name) + name = '\n' + name = name + Translator.translate("Density") + name = name + '(kg/m3)' + self.form.findChild(QtGui.QLabel, "DensityLabel").setText(name) + + def onLevel(self, value): + """ Method called when tank filling level has been modified. + @param value Changed value. + """ + pass + + def onDens(self, value): + """ Method called when fluid density has been modified. + @param value Changed value. + """ + pass + +def createTask(): + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/tankCreateTank/TaskPanel.ui b/src/Mod/Ship/tankCreateTank/TaskPanel.ui new file mode 100644 index 0000000000..635af00900 --- /dev/null +++ b/src/Mod/Ship/tankCreateTank/TaskPanel.ui @@ -0,0 +1,141 @@ + + + TaskPanel + + + + 0 + 0 + 260 + 180 + + + + Create new ship tank + + + + + + + + + 240 + 160 + + + + Fluid + + + false + + + + + 0 + 20 + 241 + 141 + + + + + 6 + + + QLayout::SetDefaultConstraint + + + + + QLayout::SetDefaultConstraint + + + 10 + + + 0 + + + 10 + + + 0 + + + + + Filling level (%) + + + + + + + 1 + + + 100.000000000000000 + + + 1.000000000000000 + + + + + + + + + 10 + + + 0 + + + 10 + + + 0 + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Density (kg/m<span style=" vertical-align:super;">3</span>)</p></body></html> + + + + + + + 1 + + + 1000000.000000000000000 + + + 10.000000000000000 + + + 998.000000000000000 + + + + + + + + + + + + + + + + diff --git a/src/Mod/Ship/tankCreateTank/__init__.py b/src/Mod/Ship/tankCreateTank/__init__.py new file mode 100644 index 0000000000..cbfb57d75d --- /dev/null +++ b/src/Mod/Ship/tankCreateTank/__init__.py @@ -0,0 +1,36 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD +import FreeCADGui + +# Qt libraries +from PyQt4 import QtGui,QtCore + +# Main object +import TaskPanel + +def load(): + """ Loads the tool """ + TaskPanel.createTask() diff --git a/src/Mod/Ship/tankGZ/Plot.py b/src/Mod/Ship/tankGZ/Plot.py new file mode 100644 index 0000000000..1ce11d344a --- /dev/null +++ b/src/Mod/Ship/tankGZ/Plot.py @@ -0,0 +1,186 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +import os +# FreeCAD modules +import FreeCAD,FreeCADGui +from FreeCAD import Part, Base +from FreeCAD import Image, ImageGui +# FreeCADShip modules +from shipUtils import Paths, Translator + +header = """ ################################################################# + + ##### #### ### #### ##### # # ### #### + # # # # # # # # # # # # + # ## #### #### # # # # # # # # # # # + #### # # # # # # # ##### # # ## ## ##### # #### + # # #### #### # # # # # # # # # # + # # # # # # # # # # # # # # + # # #### #### ### # # #### ##### # # ### # + + ################################################################# +""" + +class Plot(object): + def __init__(self, x, y, disp, draft, trim): + """ Constructor. performs plot and show it (Using pyxplot). + @param x Roll angles [deg]. + @param y GZ value [m]. + @param disp Ship displacement [tons]. + @param draft Ship draft [m]. + @param trim Ship trim angle [deg]. + """ + if self.createDirectory(): + return + if self.saveData(x,y): + return + if self.saveLayout(x,y, disp, draft, trim): + return + if self.execute(): + return + ImageGui.open(self.path + 'gz.png') + + def createDirectory(self): + """ Create needed folder to write data and scripts. + @return True if error happens. + """ + self.path = FreeCAD.ConfigGet("UserAppData") + "ShipOutput/" + if not os.path.exists(self.path): + os.makedirs(self.path) + if not os.path.exists(self.path): + msg = Translator.translate("Can't create '" + self.path + "' folder.\n") + FreeCAD.Console.PrintError(msg) + return False + + def saveData(self,x,y): + """ Write data file. + @param x Roll angles. + @param y GZ value. + @return True if error happens. + """ + # Open the file + filename = self.path + 'gz.dat' + try: + Output = open(filename, "w") + except IOError: + msg = Translator.translate("Can't write '" + filename + "' file.\n") + FreeCAD.Console.PrintError(msg) + return True + # Print header + Output.write(header) + Output.write(" #\n") + Output.write(" # File automatically exported by FreeCAD-Ship\n") + Output.write(" # This file contains transversal GZ stability parameter, filled with following columns:\n") + Output.write(" # 1: Roll angles [deg]\n") + Output.write(" # 2: GZ [m]\n") + Output.write(" #\n") + Output.write(" #################################################################\n") + # Print data + if len(x) < 2: + msg = Translator.translate("Not enough data to plot.\n") + FreeCAD.Console.PrintError(msg) + return True + for i in range(0, len(x)): + string = "%f %f\n" % (x[i], y[i]) + Output.write(string) + # Close file + Output.close() + self.dataFile = filename + msg = Translator.translate("Data saved at '" + self.dataFile + "'.\n") + FreeCAD.Console.PrintMessage(msg) + return False + + def saveLayout(self, x, y, disp, draft, trim): + """ Prints the data output. + @param x Roll angles. + @param y GZ value. + @param disp Ship displacement. + @param draft Ship draft. + @param trim Ship trim angle. + @return True if error happens. + """ + filename = self.path + 'gz.pyxplot' + # Open the file + try: + Output = open(filename, "w") + except IOError: + msg = Translator.translate("Can't write '" + filename + "' file.\n") + FreeCAD.Console.PrintError(msg) + return True + # Write header + Output.write(header) + Output.write(" #\n") + Output.write(" # File automatically exported by FreeCAD-Ship\n") + Output.write(" # This file contains a script to plot transversal GZ stability parameter.\n") + Output.write(" # To use it execute:\n") + Output.write(" #\n") + Output.write(" # pyxplot %s\n" % (filename)) + Output.write(" #\n") + Output.write(" #################################################################\n") + # Write general options for hydrostatics + Output.write("set numeric display latex\n") + Output.write("set output '%s'\n" % (self.path + 'gz.eps')) + Output.write("set nokey\n") + Output.write("set grid\n") + Output.write("# X axis\n") + Output.write("set xlabel '$roll$ / degrees'\n") + Output.write("set xtic\n") + Output.write("# Y axis\n") + Output.write("set ylabel '$GZ$ / m'\n") + Output.write("set ytic\n") + Output.write("# Line styles\n") + Output.write("set style 1 line linetype 1 linewidth 2 colour rgb (0):(0):(0)\n") + # Additional data + Output.write("# Additional data\n") + Output.write("set label (1) '$\\Delta = %g \\mathrm{tons}$' %f,%f\n" % (disp, x[0] + 0.65*(x[-1] - x[0]), min(y) + 0.95*(max(y)-min(y)))) + Output.write("set label (2) '$T = %g \\mathrm{m}$' %f,%f\n" % (draft, x[0] + 0.65*(x[-1] - x[0]), min(y) + 0.85*(max(y)-min(y)))) + Output.write("set label (3) '$Trim = %g^\\circ$' %f,%f\n" % (trim, x[0] + 0.65*(x[-1] - x[0]), min(y) + 0.75*(max(y)-min(y)))) + # Write plot call + Output.write("# Plot\n") + Output.write("plot '%s' using 1:2 title 'GZ' axes x1y1 with lines style 1\n" % (self.dataFile)) + # Close file + self.layoutFile = filename + Output.close() + return False + + def execute(self): + """ Calls pyxplot in order to plot an save an image. + @return True if error happens. + """ + filename = self.path + 'gz' + comm = "pyxplot %s" % (self.layoutFile) + if os.system(comm): + msg = Translator.translate("Can't execute pyxplot. Maybe is not installed?\n") + FreeCAD.Console.PrintError(msg) + msg = Translator.translate("Plot will not generated\n") + FreeCAD.Console.PrintError(msg) + return True + comm = "gs -r300 -dEPSCrop -dTextAlphaBits=4 -sDEVICE=png16m -sOutputFile=%s.png -dBATCH -dNOPAUSE %s.eps" % (filename,filename) + if os.system(comm): + msg = Translator.translate("Can't execute ghostscript. Maybe is not installed?\n") + FreeCAD.Console.PrintError(msg) + msg = Translator.translate("Generated image will not converted to png\n") + FreeCAD.Console.PrintError(msg) + return True + return False diff --git a/src/Mod/Ship/tankGZ/TaskPanel.py b/src/Mod/Ship/tankGZ/TaskPanel.py new file mode 100644 index 0000000000..5fefccafb9 --- /dev/null +++ b/src/Mod/Ship/tankGZ/TaskPanel.py @@ -0,0 +1,369 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +import math +# FreeCAD modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# Module +from Plot import * +from Instance import * +from TankInstance import * +from shipUtils import Paths, Translator +from shipHydrostatics import Tools as Hydrostatics + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/tankGZ/TaskPanel.ui" + self.ship = None + self.tanks = {} + + def accept(self): + if not self.ship: + return False + # Get general data + disp = self.computeDisplacement() + draft = self.computeDraft(disp[0], self.form.trim.value()) + trim = self.form.trim.value() + # Get roll angles + roll0 = self.form.roll0.value() + roll1 = self.form.roll1.value() + nRoll = self.form.nRoll.value() + dRoll = (roll1 - roll0) / (nRoll - 1) + roll = [] + GZ = [] + for i in range(0, nRoll): + roll.append(i*dRoll) + GZ.append(self.computeGZ(draft[0], trim, roll[-1])) + Plot(roll, GZ, disp[0]/1000.0, draft[0], trim) + return True + + def reject(self): + if not self.ship: + return False + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.tanks = form.findChild(QtGui.QListWidget, "Tanks") + form.disp = form.findChild(QtGui.QLabel, "DisplacementLabel") + form.draft = form.findChild(QtGui.QLabel, "DraftLabel") + form.trim = form.findChild(QtGui.QDoubleSpinBox, "Trim") + form.autoTrim = form.findChild(QtGui.QPushButton, "TrimAutoCompute") + form.roll0 = form.findChild(QtGui.QDoubleSpinBox, "StartAngle") + form.roll1 = form.findChild(QtGui.QDoubleSpinBox, "EndAngle") + form.nRoll = form.findChild(QtGui.QSpinBox, "NAngle") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + self.onTanksSelection() + # Connect Signals and Slots + QtCore.QObject.connect(form.tanks,QtCore.SIGNAL("itemSelectionChanged()"),self.onTanksSelection) + QtCore.QObject.connect(form.trim,QtCore.SIGNAL("valueChanged(double)"),self.onTrim) + QtCore.QObject.connect(form.autoTrim,QtCore.SIGNAL("pressed()"),self.onAutoTrim) + QtCore.QObject.connect(form.roll0,QtCore.SIGNAL("valueChanged(double)"),self.onRoll) + QtCore.QObject.connect(form.roll1,QtCore.SIGNAL("valueChanged(double)"),self.onRoll) + QtCore.QObject.connect(form.nRoll,QtCore.SIGNAL("valueChanged(int)"),self.onRoll) + return False + + 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 initValues(self): + """ Get selected geometry. + @return False if sucessfully values initialized. + """ + # Get selected objects + selObjs = FreeCADGui.Selection.getSelection() + if not selObjs: + msg = Translator.translate("Ship instance must be selected (no object selected)\n") + App.Console.PrintError(msg) + return True + for i in range(0,len(selObjs)): + obj = selObjs[i] + # Test if is a ship instance + props = obj.PropertiesList + try: + props.index("IsShip") + except ValueError: + continue + if obj.IsShip: + # Test if another ship already selected + if self.ship: + msg = Translator.translate("More than one ship selected (extra ship will be neglected)\n") + App.Console.PrintWarning(msg) + break + self.ship = obj + # Test if any valid ship was selected + if not self.ship: + msg = Translator.translate("Ship instance must be selected (no valid ship found at selected objects)\n") + App.Console.PrintError(msg) + return True + props = self.ship.PropertiesList + try: + props.index("WeightNames") + except: + msg = Translator.translate("Ship weights has not been set. You need to set weights before use this tool.\n") + App.Console.PrintError(msg) + return True + # Setup available tanks list + objs = App.ActiveDocument.Objects + iconPath = Paths.iconsPath() + "/Tank.xpm" + icon = QtGui.QIcon(QtGui.QPixmap(iconPath)) + for obj in objs: + # Try to get valid tank property + props = obj.PropertiesList + try: + props.index("IsShipTank") + except ValueError: + continue + if not obj.IsShipTank: + continue + # Add tank to list + name = obj.Name + label = obj.Label + tag = label + ' (' + name + ')' + self.tanks[tag] = name + # self.tanks.append([name, tag]) + item = QtGui.QListWidgetItem(tag) + item.setIcon(icon) + self.form.tanks.addItem(item) + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("GZ curve computation")) + self.form.findChild(QtGui.QGroupBox, "LoadConditionGroup").setTitle(Translator.translate("Loading condition.")) + self.form.findChild(QtGui.QGroupBox, "AnglesGroup").setTitle(Translator.translate("Roll angles.")) + self.form.findChild(QtGui.QLabel, "TrimLabel").setText(Translator.translate("Trim") + " [deg]") + self.form.findChild(QtGui.QLabel, "StartAngleLabel").setText(Translator.translate("Start") + " [deg]") + self.form.findChild(QtGui.QLabel, "EndAngleLabel").setText(Translator.translate("Start") + " [deg]") + self.form.findChild(QtGui.QLabel, "NAngleLabel").setText(Translator.translate("Number of points")) + + def onTanksSelection(self): + """ Called when tanks are selected or deselected. + """ + # Set displacement label + disp = self.computeDisplacement() + self.form.disp.setText(Translator.translate("Displacement") + ' = %g [kg]' % (disp[0])) + # Set draft label + draft = self.computeDraft(disp[0], self.form.trim.value()) + self.form.draft.setText(Translator.translate("Draft") + ' = %g [m]' % (draft[0])) + + def onTrim(self, trim): + """ Called when trim angle value is changed. + @param trim Selected trim angle. + """ + self.onTanksSelection() + + def onAutoTrim(self): + """ Called when trim angle must be auto computed. + """ + # Start at null trim angle + trim = 0.0 + # Get center of gravity + disp = self.computeDisplacement(trim) + G = [disp[1], disp[2], disp[3]] + disp = disp[0] + # Get bouyancy center + draft = self.computeDraft(disp) + xcb = draft[1] + draft = draft[0] + KBT = Hydrostatics.KBT(self.ship, draft, trim) + B = [xcb, KBT[0], KBT[1]] + # Get stability initial condition + BG = [G[0]-B[0], G[1]-B[1], G[2]-B[2]] + x = BG[0]*math.cos(math.radians(trim)) - BG[2]*math.sin(math.radians(trim)) + y = BG[1] + z = BG[0]*math.sin(math.radians(trim)) + BG[2]*math.cos(math.radians(trim)) + var = math.degrees(math.atan2(x,z)) + # Iterate looking stability point + dVar = math.copysign(0.0033, var) + while True: + if (dVar*math.copysign(dVar, var) < 0.0): + break + trim = trim - math.copysign(dVar, var) + # Get center of gravity + disp = self.computeDisplacement(trim) + G = [disp[1], disp[2], disp[3]] + disp = disp[0] + # Get bouyancy center + draft = self.computeDraft(disp, trim) + xcb = draft[1] + draft = draft[0] + KBT = Hydrostatics.KBT(self.ship, draft, trim) + B = [xcb, KBT[0], KBT[1]] + # Get stability initial condition + BG = [G[0]-B[0], G[1]-B[1], G[2]-B[2]] + x = BG[0]*math.cos(math.radians(trim)) - BG[2]*math.sin(math.radians(trim)) + y = BG[1] + z = BG[0]*math.sin(math.radians(trim)) + BG[2]*math.cos(math.radians(trim)) + var = math.degrees(math.atan2(x,z)) + self.form.trim.setValue(trim) + + def onRoll(self, value): + """ Called when roll angles options are modified. + @param value Dummy changed value. + """ + roll0 = self.form.roll0.value() + self.form.roll1.setMinimum(roll0) + roll1 = self.form.roll1.value() + self.form.roll0.setMaximum(roll1) + + def getTanks(self): + """ Get the selected tanks objects list. + @return Selected tanks list. + """ + items = self.form.tanks.selectedItems() + tanks = [] + for item in items: + tag = str(item.text()) + name = self.tanks[tag] + t = App.ActiveDocument.getObject(name) + if not t: + continue + tanks.append(t) + return tanks + + def computeDisplacement(self, trim=0.0, roll=0.0): + """ Computes ship displacement. + @param trim Trim angle [degrees]. + @return Ship displacement and center of gravity. None if errors + detected. + @note Returned center of gravity is refered to ship attached + axis coordinates. + """ + if not self.ship: + return None + # Get ship structure weights + W = [0.0, 0.0, 0.0, 0.0] + sWeights = weights(self.ship) + for w in sWeights: + W[0] = W[0] + w[1] + W[1] = W[1] + w[1]*w[2][0] + W[2] = W[2] + w[1]*w[2][1] + W[3] = W[3] + w[1]*w[2][2] + # Get selected tanks weights + tanks = self.getTanks() + for t in tanks: + w = tankWeight(t, App.Base.Vector(roll,-trim,0.0)) + # Unrotate center of gravity + x = w[1]*math.cos(math.radians(-trim)) - w[3]*math.sin(math.radians(-trim)) + y = w[2] + z = w[1]*math.sin(math.radians(-trim)) + w[3]*math.cos(math.radians(-trim)) + w[1] = x + w[2] = y*math.cos(math.radians(-roll)) - z*math.sin(math.radians(-roll)) + w[3] = y*math.sin(math.radians(-roll)) + z*math.cos(math.radians(-roll)) + W[0] = W[0] + w[0] + W[1] = W[1] + w[0]*w[1] + W[2] = W[2] + w[0]*w[2] + W[3] = W[3] + w[0]*w[3] + return [W[0], W[1]/W[0], W[2]/W[0], W[3]/W[0]] + + def computeDraft(self, disp, trim=0.0): + """ Computes ship draft. + @param disp Ship displacement. + @param trim Trim angle [degrees]. + @return Ship draft, and longitudinal bouyance center position. None if errors detected. + """ + if not self.ship: + return None + # Initial condition + dens = 1025 + bbox = self.ship.Shape.BoundBox + draft = bbox.ZMin + dx = bbox.XMax - bbox.XMin + dy = bbox.YMax - bbox.YMin + w = 0.0 + xcb = 0.0 + while(abs(disp - w)/disp > 0.01): + draft = draft + (disp - w) / (dens*dx*dy) + ww = Hydrostatics.Displacement(self.ship, draft, trim) + w = 1000.0*ww[1] + xcb = ww[2] + return [draft,xcb] + + def computeGZ(self, draft, trim, roll): + """ Compute GZ value. + @param draft Ship draft. + @param trim Ship trim angle [degrees]. + @param roll Ship roll angle [degrees]. + @return GZ value [m]. + """ + # Get center of gravity (x coordinate not relevant) + disp = self.computeDisplacement(trim, roll) + G = [disp[2], disp[3]] + disp = disp[0] + # Get bouyancy center (x coordinate not relevant) + KBT = Hydrostatics.KBT(self.ship, draft, trim, roll) + B = [KBT[0], KBT[1]] + # GZ computation + BG = [G[0] - B[0], G[1] - B[1]] + y = BG[0]*math.cos(math.radians(-roll)) - BG[1]*math.sin(math.radians(-roll)) + z = BG[0]*math.sin(math.radians(-roll)) + BG[1]*math.cos(math.radians(-roll)) + return -y + +def createTask(): + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/tankGZ/TaskPanel.ui b/src/Mod/Ship/tankGZ/TaskPanel.ui new file mode 100644 index 0000000000..ce59e5d2b5 --- /dev/null +++ b/src/Mod/Ship/tankGZ/TaskPanel.ui @@ -0,0 +1,213 @@ + + + TaskPanel + + + + 0 + 0 + 256 + 408 + + + + + 256 + 408 + + + + GZ curve computation + + + + + + + 0 + 6 + + + + + 0 + 0 + + + + Loading condition + + + + + 0 + 20 + 231 + 231 + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::MultiSelection + + + + + + + Displacement = 0 [kg] + + + + + + + Draft = 0 [m] + + + + + + + + + + 3 + 0 + + + + Trim [deg] + + + + + + + + 3 + 0 + + + + -45.000000000000000 + + + 45.000000000000000 + + + 0.100000000000000 + + + + + + + + 1 + 0 + + + + Auto + + + + + + + + + + + + + + 0 + 3 + + + + Roll angles + + + + + 0 + 20 + 231 + 101 + + + + + QLayout::SetMinimumSize + + + + + Start [deg] + + + + + + + End [deg] + + + + + + + Number of points + + + + + + + 0.000000000000000 + + + 90.000000000000000 + + + + + + + 89.000000000000000 + + + 45.000000000000000 + + + + + + + 2 + + + 10000 + + + 46 + + + + + + + + + + + + diff --git a/src/Mod/Ship/tankGZ/__init__.py b/src/Mod/Ship/tankGZ/__init__.py new file mode 100644 index 0000000000..cbfb57d75d --- /dev/null +++ b/src/Mod/Ship/tankGZ/__init__.py @@ -0,0 +1,36 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD +import FreeCADGui + +# Qt libraries +from PyQt4 import QtGui,QtCore + +# Main object +import TaskPanel + +def load(): + """ Loads the tool """ + TaskPanel.createTask() diff --git a/src/Mod/Ship/tankWeights/Preview.py b/src/Mod/Ship/tankWeights/Preview.py new file mode 100644 index 0000000000..571155bb9d --- /dev/null +++ b/src/Mod/Ship/tankWeights/Preview.py @@ -0,0 +1,106 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD,FreeCADGui +from FreeCAD import Base +from FreeCAD import Part +# FreeCADShip modules +from shipUtils import Paths, Translator + +class Preview(object): + def __init__(self): + """ Constructor. + """ + self.objects = [] + + def reinit(self): + """ Reinitializate drawer. + """ + self.clean() + + def update(self, names, pos): + """ Update the 3D view printing annotations. + @param names Weight names. + @param pos Weight positions (FreeCAD::Base::Vector). + """ + # Destroy all previous entities + self.clean() + for i in range(0, len(names)): + # Draw gravity line + line = Part.makeLine((pos[i].x,pos[i].y,pos[i].z),(pos[i].x,pos[i].y,pos[i].z - 9.81)) + Part.show(line) + objs = FreeCAD.ActiveDocument.Objects + self.objects.append(objs[-1]) + objs[-1].Label = names[i] + 'Line' + # Draw circles + circle = Part.makeCircle(0.5, pos[i], Base.Vector(1.0,0.0,0.0)) + Part.show(circle) + objs = FreeCAD.ActiveDocument.Objects + self.objects.append(objs[-1]) + objs[-1].Label = names[i] + 'CircleX' + circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0,1.0,0.0)) + Part.show(circle) + objs = FreeCAD.ActiveDocument.Objects + self.objects.append(objs[-1]) + objs[-1].Label = names[i] + 'CircleY' + circle = Part.makeCircle(0.5, pos[i], Base.Vector(0.0,0.0,1.0)) + Part.show(circle) + objs = FreeCAD.ActiveDocument.Objects + self.objects.append(objs[-1]) + objs[-1].Label = names[i] + 'CircleZ' + # Draw annotation + self.objects.append(DrawText(names[i] + 'Text', names[i], Base.Vector(pos[i].x+1.0,pos[i].y,pos[i].z))) + + def clean(self): + """ Erase all annotations from screen. + """ + for i in range(0,len(self.objects)): + if not FreeCAD.ActiveDocument.getObject(self.objects[i].Name): + continue + FreeCAD.ActiveDocument.removeObject(self.objects[i].Name) + self.objects = [] + +def DrawText(name, string, position, displayMode="Screen", angle=0.0, justification="Left", colour=(0.00,0.00,0.00), size=12): + """ Draws a text in a desired position. + @param name Name of the object + @param string Text to draw (recommended format u'') + @param position Point to draw the text + @param angle Counter clockwise rotation of text + @param justification Alignement of the text ("Left", "Right" or "Center") + @param colour Colour of the text + @param size Font size + @return FreeCAD annotation object + """ + # Create the object + text = FreeCAD.ActiveDocument.addObject("App::Annotation",name) + # Set the text + text.LabelText = [string, u''] + # Set the options + text.Position = position + FreeCADGui.ActiveDocument.getObject(text.Name).Rotation = angle + FreeCADGui.ActiveDocument.getObject(text.Name).Justification = justification + FreeCADGui.ActiveDocument.getObject(text.Name).FontSize = size + FreeCADGui.ActiveDocument.getObject(text.Name).TextColor = colour + FreeCADGui.ActiveDocument.getObject(text.Name).DisplayMode = displayMode + return FreeCAD.ActiveDocument.getObject(text.Name) diff --git a/src/Mod/Ship/tankWeights/TaskPanel.py b/src/Mod/Ship/tankWeights/TaskPanel.py new file mode 100644 index 0000000000..a01f7c73c2 --- /dev/null +++ b/src/Mod/Ship/tankWeights/TaskPanel.py @@ -0,0 +1,246 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD as App +import FreeCADGui as Gui +# Qt library +from PyQt4 import QtGui,QtCore +# Module +import Preview +from Instance import * +from shipUtils import Paths, Translator + +class TaskPanel: + def __init__(self): + self.ui = Paths.modulePath() + "/tankWeights/TaskPanel.ui" + self.ship = None + self.preview = Preview.Preview() + + def accept(self): + self.preview.clean() + if not self.ship: + return False + # Setup lists + name = [] + mass = [] + pos = [] + for i in range(0,self.form.weights.rowCount() - 1): + item = self.form.weights.item(i,0) + name.append(item.text().__str__()) + item = self.form.weights.item(i,1) + mass.append(item.text().toFloat()[0]) + vec = [] + item = self.form.weights.item(i,2) + vec.append(item.text().toFloat()[0]) + item = self.form.weights.item(i,3) + vec.append(item.text().toFloat()[0]) + item = self.form.weights.item(i,4) + vec.append(item.text().toFloat()[0]) + pos.append(App.Base.Vector(vec[0],vec[1],vec[2])) + # Send to ship + self.ship.WeightNames = name[:] + self.ship.WeightMass = mass[:] + self.ship.WeightPos = pos[:] + return True + + def reject(self): + self.preview.clean() + if not self.ship: + return False + return True + + def clicked(self, index): + pass + + def open(self): + pass + + def needsFullSpace(self): + return True + + def isAllowedAlterSelection(self): + return False + + def isAllowedAlterView(self): + return True + + def isAllowedAlterDocument(self): + return False + + def helpRequested(self): + pass + + def setupUi(self): + mw = self.getMainWindow() + form = mw.findChild(QtGui.QWidget, "TaskPanel") + form.weights = form.findChild(QtGui.QTableWidget, "Weights") + self.form = form + # Initial values + if self.initValues(): + return True + self.retranslateUi() + # Connect Signals and Slots + QtCore.QObject.connect(form.weights,QtCore.SIGNAL("cellChanged(int,int)"),self.onTableItem); + # Update screen + name = [] + pos = [] + for i in range(0,self.form.weights.rowCount() - 1): + item = self.form.weights.item(i,0) + name.append(item.text().__str__()) + vec = [] + item = self.form.weights.item(i,2) + vec.append(item.text().toFloat()[0]) + item = self.form.weights.item(i,3) + vec.append(item.text().toFloat()[0]) + item = self.form.weights.item(i,4) + vec.append(item.text().toFloat()[0]) + pos.append(App.Base.Vector(vec[0],vec[1],vec[2])) + self.preview.update(name, pos) + + 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 initValues(self): + """ Get selected geometry. + @return False if sucessfully values initialized. + """ + # Get selected objects + selObjs = FreeCADGui.Selection.getSelection() + if not selObjs: + msg = Translator.translate("Ship instance must be selected (no object selected)\n") + App.Console.PrintError(msg) + return True + for i in range(0,len(selObjs)): + obj = selObjs[i] + # Test if is a ship instance + props = obj.PropertiesList + try: + props.index("IsShip") + except ValueError: + continue + if obj.IsShip: + # Test if another ship already selected + if self.ship: + msg = Translator.translate("More than one ship selected (extra ship will be neglected)\n") + App.Console.PrintWarning(msg) + break + self.ship = obj + # Test if any valid ship was selected + if not self.ship: + msg = Translator.translate("Ship instance must be selected (no valid ship found at selected objects)\n") + App.Console.PrintError(msg) + return True + # Get weights + w = weights(self.ship) + # Set the items + self.form.weights.setRowCount(len(w)+1) + for i in range(0,len(w)): + item = QtGui.QTableWidgetItem(w[i][0]) + self.form.weights.setItem(i,0,item) + string = '%g' % (w[i][1]) + item = QtGui.QTableWidgetItem(string) + self.form.weights.setItem(i,1,item) + string = '%g' % (w[i][2].x) + item = QtGui.QTableWidgetItem(string) + self.form.weights.setItem(i,2,item) + string = '%g' % (w[i][2].y) + item = QtGui.QTableWidgetItem(string) + self.form.weights.setItem(i,3,item) + string = '%g' % (w[i][2].z) + item = QtGui.QTableWidgetItem(string) + self.form.weights.setItem(i,4,item) + msg = Translator.translate("Ready to work\n") + App.Console.PrintMessage(msg) + return False + + def retranslateUi(self): + """ Set user interface locale strings. + """ + self.form.setWindowTitle(Translator.translate("Set weights")) + labels = [] + labels.append(Translator.translate("Name")) + labels.append(Translator.translate("Mass") + " [kg]") + labels.append(QtCore.QString("g.x [m]")) + labels.append(QtCore.QString("g.y [m]")) + labels.append(QtCore.QString("g.z [m]")) + self.form.weights.setHorizontalHeaderLabels(labels) + + def onTableItem(self, row, column): + """ Function called when an item of table is changed. + @param row Changed item row + @param column Changed item column + """ + item = self.form.weights.item(row,column) + # Row deletion + if column == 0: + if not item.text(): + self.form.weights.removeRow(row) + # Ensure that exist one empty item at the end + nRow = self.form.weights.rowCount() + last = self.form.weights.item(nRow-1,0) + if last: + if(last.text() != ''): + self.form.weights.setRowCount(nRow+1) + # Fields must be numbers + for i in range(0,self.form.weights.rowCount()-1): # Avoid last row + for j in range(1,self.form.weights.columnCount()): # Avoid name column + item = self.form.weights.item(i,j) + if not item: + item = QtGui.QTableWidgetItem('0.0') + self.form.weights.setItem(i,j,item) + continue + (number,flag) = item.text().toFloat() + if not flag: + item.setText('0.0') + # Update screen annotations + name = [] + pos = [] + for i in range(0,self.form.weights.rowCount() - 1): + item = self.form.weights.item(i,0) + name.append(item.text().__str__()) + vec = [] + item = self.form.weights.item(i,2) + vec.append(item.text().toFloat()[0]) + item = self.form.weights.item(i,3) + vec.append(item.text().toFloat()[0]) + item = self.form.weights.item(i,4) + vec.append(item.text().toFloat()[0]) + pos.append(App.Base.Vector(vec[0],vec[1],vec[2])) + self.preview.update(name, pos) + +def createTask(): + panel = TaskPanel() + Gui.Control.showDialog(panel) + if panel.setupUi(): + Gui.Control.closeDialog(panel) + return None + return panel diff --git a/src/Mod/Ship/tankWeights/TaskPanel.ui b/src/Mod/Ship/tankWeights/TaskPanel.ui new file mode 100644 index 0000000000..23dc4ff1bb --- /dev/null +++ b/src/Mod/Ship/tankWeights/TaskPanel.ui @@ -0,0 +1,97 @@ + + + TaskPanel + + + + 0 + 0 + 260 + 256 + + + + Set wieghts + + + + + + true + + + 1 + + + 5 + + + false + + + 20 + + + false + + + false + + + + + Name + + + + + Mass [kg] + + + + + g.x [m] + + + + + g.y [m] + + + + + g.z [m] + + + + + Lightweight + + + + + 0.0 + + + + + 0.0 + + + + + 0.0 + + + + + 0.0 + + + + + + + + + diff --git a/src/Mod/Ship/tankWeights/__init__.py b/src/Mod/Ship/tankWeights/__init__.py new file mode 100644 index 0000000000..cbfb57d75d --- /dev/null +++ b/src/Mod/Ship/tankWeights/__init__.py @@ -0,0 +1,36 @@ +#*************************************************************************** +#* * +#* Copyright (c) 2011, 2012 * +#* Jose Luis Cercos Pita * +#* * +#* 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 * +#* * +#*************************************************************************** + +# FreeCAD modules +import FreeCAD +import FreeCADGui + +# Qt libraries +from PyQt4 import QtGui,QtCore + +# Main object +import TaskPanel + +def load(): + """ Loads the tool """ + TaskPanel.createTask() diff --git a/src/Mod/Sketcher/App/ConstraintPyImp.cpp b/src/Mod/Sketcher/App/ConstraintPyImp.cpp index b04d6ab7cf..7dad2b7594 100644 --- a/src/Mod/Sketcher/App/ConstraintPyImp.cpp +++ b/src/Mod/Sketcher/App/ConstraintPyImp.cpp @@ -138,15 +138,20 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) if (PyInt_Check(index_or_value)) { FirstPos = any_index; SecondIndex = PyInt_AsLong(index_or_value); - if (strcmp("Tangent", ConstraintType) == 0) { - this->getConstraintPtr()->Type = Tangent; - this->getConstraintPtr()->First = FirstIndex; - this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos; - this->getConstraintPtr()->Second = SecondIndex; - return 0; + bool valid = false; + if (strcmp("Perpendicular", ConstraintType) == 0) { + this->getConstraintPtr()->Type = Perpendicular; + valid = true; } - if (strcmp("PointOnObject", ConstraintType) == 0) { + else if (strcmp("Tangent", ConstraintType) == 0) { + this->getConstraintPtr()->Type = Tangent; + valid = true; + } + else if (strcmp("PointOnObject", ConstraintType) == 0) { this->getConstraintPtr()->Type = PointOnObject; + valid = true; + } + if (valid) { this->getConstraintPtr()->First = FirstIndex; this->getConstraintPtr()->FirstPos = (Sketcher::PointPos) FirstPos; this->getConstraintPtr()->Second = SecondIndex; @@ -212,6 +217,10 @@ int ConstraintPy::PyInit(PyObject* args, PyObject* /*kwd*/) this->getConstraintPtr()->Type = Vertical; valid = true; } + else if (strcmp("Perpendicular", ConstraintType) == 0) { + this->getConstraintPtr()->Type = Perpendicular; + valid = true; + } else if (strcmp("Tangent", ConstraintType) == 0) { this->getConstraintPtr()->Type = Tangent; valid = true; diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 35f6bdb64c..1898955f3e 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -96,8 +96,9 @@ void Sketch::clear(void) Conflicting.clear(); } -int Sketch::setUpSketch(const std::vector &GeoList, const std::vector &ConstraintList, - bool withDiagnose, int extGeoCount) +int Sketch::setUpSketch(const std::vector &GeoList, + const std::vector &ConstraintList, + int extGeoCount) { clear(); @@ -119,13 +120,11 @@ int Sketch::setUpSketch(const std::vector &GeoList, const std: addConstraints(ConstraintList); GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); - GCSsys.initSolution(Parameters); - - if (withDiagnose) - return diagnose(); - else - return 0; + GCSsys.declareUnknowns(Parameters); + GCSsys.initSolution(); + GCSsys.getConflicting(Conflicting); + GCSsys.getRedundant(Redundant); + return GCSsys.dofsNumber(); } const char* nameByType(Sketch::GeoType type) @@ -474,7 +473,16 @@ int Sketch::addConstraint(const Constraint *constraint) rtn = addParallelConstraint(constraint->First,constraint->Second); break; case Perpendicular: - rtn = addPerpendicularConstraint(constraint->First,constraint->Second); + if (constraint->SecondPos != none) // perpendicularity at common point + rtn = addPerpendicularConstraint(constraint->First,constraint->FirstPos, + constraint->Second,constraint->SecondPos); + else if (constraint->Second != Constraint::GeoUndef) { + if (constraint->FirstPos != none) // "First" is a connecting point + rtn = addPerpendicularConstraint(constraint->First,constraint->FirstPos, + constraint->Second); + else // simple perpendicularity + rtn = addPerpendicularConstraint(constraint->First,constraint->Second); + } break; case Tangent: if (constraint->SecondPos != none) // tangency at common point @@ -735,10 +743,7 @@ int Sketch::addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2, GCS::Point &p1 = Points[pointId1]; GCS::Point &p2 = Points[pointId2]; int tag = ++ConstraintsCounter; - // trick: we do not tag coincidence constraints in order to exclude - // them from the diagnosing of conflicts - //GCSsys.addConstraintP2PCoincident(p1, p2, tag); - GCSsys.addConstraintP2PCoincident(p1, p2); + GCSsys.addConstraintP2PCoincident(p1, p2, tag); return ConstraintsCounter; } return -1; @@ -760,8 +765,13 @@ int Sketch::addParallelConstraint(int geoId1, int geoId2) return ConstraintsCounter; } +// simple perpendicularity constraint int Sketch::addPerpendicularConstraint(int geoId1, int geoId2) { + // accepts the following combinations: + // 1) Line1, Line2/Circle2/Arc2 + // 2) Circle1, Line2 (converted to case #1) + // 3) Arc1, Line2 (converted to case #1) geoId1 = checkGeoId(geoId1); geoId2 = checkGeoId(geoId2); @@ -778,17 +788,12 @@ int Sketch::addPerpendicularConstraint(int geoId1, int geoId2) } if (Geoms[geoId1].type == Line) { - GCS::Line &l = Lines[Geoms[geoId1].index]; - if (Geoms[geoId2].type == Arc) { - GCS::Arc &a = Arcs[Geoms[geoId2].index]; - //GCSsys.addConstraintPerpendicular(l, a); - Base::Console().Warning("Perpendicular constraints between lines and arcs are not implemented yet.\n"); - return -1; - } else if (Geoms[geoId2].type == Circle) { - GCS::Circle &c = Circles[Geoms[geoId2].index]; - //GCSsys.addConstraintPerpendicular(l, c); - Base::Console().Warning("Perpendicular constraints between lines and circles are not implemented yet.\n"); - return -1; + GCS::Line &l1 = Lines[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Arc || Geoms[geoId2].type == Circle) { + GCS::Point &p2 = Points[Geoms[geoId2].midPointId]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnLine(p2, l1, tag); + return ConstraintsCounter; } } @@ -797,15 +802,182 @@ int Sketch::addPerpendicularConstraint(int geoId1, int geoId2) return -1; } +// perpendicularity at specific point constraint +int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2) +{ + // accepts the following combinations: + // 1) Line1, start/end, Line2/Circle2/Arc2 + // 2) Arc1, start/end, Line2/Circle2/Arc2 + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + int pointId1 = getPointId(geoId1, pos1); + + if (pointId1 < 0 || pointId1 >= int(Points.size())) + return addPerpendicularConstraint(geoId1, geoId2); + + GCS::Point &p1 = Points[pointId1]; + if (Geoms[geoId1].type == Line) { + GCS::Line &l1 = Lines[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Line) { + GCS::Line &l2 = Lines[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnLine(p1, l2, tag); + GCSsys.addConstraintPerpendicular(l1, l2, tag); + return ConstraintsCounter; + } + else if (Geoms[geoId2].type == Arc) { + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + GCS::Point &p2 = Points[Geoms[geoId2].midPointId]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnArc(p1, a2, tag); + GCSsys.addConstraintPointOnLine(p2, l1, tag); + return ConstraintsCounter; + } + else if (Geoms[geoId2].type == Circle) { + GCS::Circle &c2 = Circles[Geoms[geoId2].index]; + GCS::Point &p2 = Points[Geoms[geoId2].midPointId]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnCircle(p1, c2, tag); + GCSsys.addConstraintPointOnLine(p2, l1, tag); + return ConstraintsCounter; + } + } + else if (Geoms[geoId1].type == Arc) { + GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Line) { + GCS::Line &l2 = Lines[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnLine(p1, l2, tag); + GCSsys.addConstraintPointOnLine(a1.center, l2, tag); + return ConstraintsCounter; + } + else if (Geoms[geoId2].type == Arc || Geoms[geoId2].type == Circle) { + int tag = ++ConstraintsCounter; + GCS::Point ¢er = Points[Geoms[geoId2].midPointId]; + double *radius; + if (Geoms[geoId2].type == Arc) { + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + radius = a2.rad; + } + else { + GCS::Circle &c2 = Circles[Geoms[geoId2].index]; + radius = c2.rad; + } + if (pos1 == start) + GCSsys.addConstraintPerpendicularCircle2Arc(center, radius, a1, tag); + else if (pos1 == end) + GCSsys.addConstraintPerpendicularArc2Circle(a1, center, radius, tag); + return ConstraintsCounter; + } + } + return -1; +} + +// perpendicularity at common point constraint +int Sketch::addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2) +{ + // accepts the following combinations: + // 1) Line1, start/end, Line2/Arc2, start/end + // 2) Arc1, start/end, Line2, start/end (converted to case #1) + // 3) Arc1, start/end, Arc2, start/end + geoId1 = checkGeoId(geoId1); + geoId2 = checkGeoId(geoId2); + + int pointId1 = getPointId(geoId1, pos1); + int pointId2 = getPointId(geoId2, pos2); + + if (pointId1 < 0 || pointId1 >= int(Points.size()) || + pointId2 < 0 || pointId2 >= int(Points.size())) + return -1; + + GCS::Point &p1 = Points[pointId1]; + GCS::Point &p2 = Points[pointId2]; + if (Geoms[geoId2].type == Line) { + if (Geoms[geoId1].type == Line) { + GCS::Line &l1 = Lines[Geoms[geoId1].index]; + GCS::Line &l2 = Lines[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintP2PCoincident(p1, p2, tag); + GCSsys.addConstraintPerpendicular(l1, l2, tag); + return ConstraintsCounter; + } + else { + std::swap(geoId1, geoId2); + std::swap(pos1, pos2); + std::swap(pointId1, pointId2); + p1 = Points[pointId1]; + p2 = Points[pointId2]; + } + } + + if (Geoms[geoId1].type == Line) { + GCS::Line &l1 = Lines[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Arc) { + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + if (pos2 == start) { + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPerpendicularLine2Arc(l1.p2, l1.p1, a2, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPerpendicularLine2Arc(l1.p1, l1.p2, a2, tag); + return ConstraintsCounter; + } + } + else if (pos2 == end) { + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPerpendicularArc2Line(a2, l1.p1, l1.p2, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPerpendicularArc2Line(a2, l1.p2, l1.p1, tag); + return ConstraintsCounter; + } + } + else + return -1; + } + } + else if (Geoms[geoId1].type == Arc) { + GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Arc) { + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + if (pos1 == start && (pos2 == start || pos2 == end)) { + int tag = ++ConstraintsCounter; + if (pos2 == start) + GCSsys.addConstraintPerpendicularArc2Arc(a1, true, a2, false, tag); + else // if (pos2 == end) + GCSsys.addConstraintPerpendicularArc2Arc(a1, true, a2, true, tag); + // GCSsys.addConstraintTangentArc2Arc(a2, false, a1, false, tag); + return ConstraintsCounter; + } + else if (pos1 == end && (pos2 == start || pos2 == end)) { + int tag = ++ConstraintsCounter; + if (pos2 == start) + GCSsys.addConstraintPerpendicularArc2Arc(a1, false, a2, false, tag); + else // if (pos2 == end) + GCSsys.addConstraintPerpendicularArc2Arc(a1, false, a2, true, tag); + return ConstraintsCounter; + } + } + } + return -1; +} + // simple tangency constraint int Sketch::addTangentConstraint(int geoId1, int geoId2) { // accepts the following combinations: // 1) Line1, Line2/Circle2/Arc2 // 2) Circle1, Line2 (converted to case #1) - // Circle1, Circle2/Arc2 (not implemented yet) + // Circle1, Circle2/Arc2 // 3) Arc1, Line2 (converted to case #1) - // Arc1, Circle2/Arc2 (not implemented yet) + // Arc1, Circle2/Arc2 geoId1 = checkGeoId(geoId1); geoId2 = checkGeoId(geoId2); @@ -836,8 +1008,33 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2) GCSsys.addConstraintTangent(l, c, tag); return ConstraintsCounter; } - } else - Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n"); + } else if (Geoms[geoId1].type == Circle) { + GCS::Circle &c = Circles[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Circle) { + GCS::Circle &c2 = Circles[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(c, c2, tag); + return ConstraintsCounter; + } else if (Geoms[geoId2].type == Arc) { + GCS::Arc &a = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(c, a, tag); + return ConstraintsCounter; + } + } else if (Geoms[geoId1].type == Arc) { + GCS::Arc &a = Arcs[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Circle) { + GCS::Circle &c = Circles[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(c, a, tag); + return ConstraintsCounter; + } else if (Geoms[geoId2].type == Arc) { + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(a, a2, tag); + return ConstraintsCounter; + } + } return -1; } @@ -846,12 +1043,8 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2) int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) { // accepts the following combinations: - // 1) Line1, start/end/mid, Line2 - // 2) Line1, start/end/mid, Circle2 - // 3) Line1, start/end/mid, Arc2 - // 4) Arc1, start/end, Line2 - // 5) Arc1, start/end, Circle2 (not implemented yet) - // 6) Arc1, start/end, Arc2 (not implemented yet) + // 1) Line1, start/end, Line2/Circle2/Arc2 + // 2) Arc1, start/end, Line2/Circle2/Arc2 geoId1 = checkGeoId(geoId1); geoId2 = checkGeoId(geoId2); @@ -895,16 +1088,24 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) return ConstraintsCounter; } else if (Geoms[geoId2].type == Arc) { - //GCS::Arcs &a2 = Arcs[Geoms[geoId2].index]; - //GCSsys.addConstraintPointOnArc(p1, a2); - //GCSsys.addConstraintTangent(a1, a2); - Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n"); + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnArc(p1, a2, tag); + GCSsys.addConstraintTangent(a1, a2, tag); + return ConstraintsCounter; } else if (Geoms[geoId2].type == Circle) { - //GCS::Circle &c2 = Circles[Geoms[geoId2].index]; - //GCSsys.addConstraintPointOnCircle(p1, c2); - //GCSsys.addConstraintTangent(a1, c2); - Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n"); + GCS::Circle &c2 = Circles[Geoms[geoId2].index]; + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentCircle2Arc(c2, a1, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentArc2Circle(a1, c2, tag); + return ConstraintsCounter; + } } } return -1; @@ -914,10 +1115,9 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2) { // accepts the following combinations: - // 1) Line1, start/end/mid, Line2, start/end/mid - // 2) Line1, start/end/mid, Arc2, start/end - // 3) Arc1, start/end, Line2, start/end/mid (converted to case #2) - // 4) Arc1, start/end, Arc2, start/end (not implemented yet) + // 1) Line1, start/end, Line2/Arc2, start/end + // 2) Arc1, start/end, Line2, start/end (converted to case #1) + // 3) Arc1, start/end, Arc2, start/end geoId1 = checkGeoId(geoId1); geoId2 = checkGeoId(geoId2); @@ -950,14 +1150,7 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos if (Geoms[geoId1].type == Line) { GCS::Line &l1 = Lines[Geoms[geoId1].index]; - if (Geoms[geoId2].type == Line) { - GCS::Line &l2 = Lines[Geoms[geoId2].index]; - int tag = ++ConstraintsCounter; - GCSsys.addConstraintP2PCoincident(p1, p2, tag); - GCSsys.addConstraintParallel(l1, l2, tag); - return ConstraintsCounter; - } - else if (Geoms[geoId2].type == Arc) { + if (Geoms[geoId2].type == Arc) { GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; if (pos2 == start) { if (pos1 == start) { @@ -970,12 +1163,6 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos GCSsys.addConstraintTangentLine2Arc(l1.p1, l1.p2, a2, tag); return ConstraintsCounter; } - else if (pos1 == mid) { - int tag = ++ConstraintsCounter; - GCSsys.addConstraintP2PCoincident(p1, p2, tag); - GCSsys.addConstraintTangent(l1, a2, tag); - return ConstraintsCounter; - } } else if (pos2 == end) { if (pos1 == start) { @@ -988,24 +1175,32 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos GCSsys.addConstraintTangentArc2Line(a2, l1.p2, l1.p1, tag); return ConstraintsCounter; } - else if (pos1 == mid) { - int tag = ++ConstraintsCounter; - GCSsys.addConstraintP2PCoincident(p1, p2, tag); - GCSsys.addConstraintTangent(l1, a2, tag); - return ConstraintsCounter; - } } else return -1; } } else if (Geoms[geoId1].type == Arc) { - //GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; + GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; if (Geoms[geoId2].type == Arc) { - //GCS::Arcs &a2 = Arcs[Geoms[geoId2].index]; - //GCSsys.addConstraintPointOnArc(p1, a2); - //GCSsys.addConstraintTangent(a1, a2); - Base::Console().Warning("Tangency constraints between arcs are not implemented yet.\n"); + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + if (pos1 == start && (pos2 == start || pos2 == end)) { + int tag = ++ConstraintsCounter; + if (pos2 == start) + GCSsys.addConstraintTangentArc2Arc(a1, true, a2, false, tag); + else // if (pos2 == end) + GCSsys.addConstraintTangentArc2Arc(a1, true, a2, true, tag); + // GCSsys.addConstraintTangentArc2Arc(a2, false, a1, false, tag); + return ConstraintsCounter; + } + else if (pos1 == end && (pos2 == start || pos2 == end)) { + int tag = ++ConstraintsCounter; + if (pos2 == start) + GCSsys.addConstraintTangentArc2Arc(a1, false, a2, false, tag); + else // if (pos2 == end) + GCSsys.addConstraintTangentArc2Arc(a1, false, a2, true, tag); + return ConstraintsCounter; + } } } return -1; @@ -1364,13 +1559,13 @@ bool Sketch::updateGeometry() // solving ========================================================== -int Sketch::solve() +int Sketch::solve(void) { Base::TimeInfo start_time; if (!isInitMove) { // make sure we are in single subsystem mode GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); + isFine = true; } int ret; @@ -1381,44 +1576,45 @@ int Sketch::solve() case 0: // solving with the default DogLeg solver // (or with SQP if we are in moving mode) solvername = isInitMove ? "SQP" : "DogLeg"; - ret = GCSsys.solve(true, GCS::DogLeg); + ret = GCSsys.solve(isFine, GCS::DogLeg); break; case 1: // solving with the LevenbergMarquardt solver solvername = "LevenbergMarquardt"; - ret = GCSsys.solve(true, GCS::LevenbergMarquardt); + ret = GCSsys.solve(isFine, GCS::LevenbergMarquardt); break; case 2: // solving with the BFGS solver solvername = "BFGS"; - ret = GCSsys.solve(true, GCS::BFGS); + ret = GCSsys.solve(isFine, GCS::BFGS); break; case 3: // last resort: augment the system with a second subsystem and use the SQP solver solvername = "SQP(augmented system)"; - GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); InitParameters.resize(Parameters.size()); int i=0; for (std::vector::iterator it = Parameters.begin(); it != Parameters.end(); ++it, i++) { InitParameters[i] = **it; - GCSsys.addConstraintEqual(*it, &InitParameters[i], -2); + GCSsys.addConstraintEqual(*it, &InitParameters[i], -1); } - GCSsys.initSolution(Parameters); - ret = GCSsys.solve(true); + GCSsys.initSolution(); + ret = GCSsys.solve(isFine); break; } - // if successfully solved try write the parameters back + // if successfully solved try to write the parameters back if (ret == GCS::Success) { GCSsys.applySolution(); valid_solution = updateGeometry(); - if (!valid_solution) + if (!valid_solution) { + GCSsys.undoSolution(); + updateGeometry(); Base::Console().Warning("Invalid solution from %s solver.\n", solvername.c_str()); + } } else { valid_solution = false; //Base::Console().Log("NotSolved "); } if (soltype == 3) // cleanup temporary constraints of the augmented system - GCSsys.clearByTag(-2); + GCSsys.clearByTag(-1); if (valid_solution) { if (soltype == 1) @@ -1437,23 +1633,19 @@ int Sketch::solve() } } // soltype - if (!valid_solution) { // undo any changes - GCSsys.undoSolution(); - updateGeometry(); - } - Base::TimeInfo end_time; //Base::Console().Log("T:%s\n",Base::TimeInfo::diffTime(start_time,end_time).c_str()); SolveTime = Base::TimeInfo::diffTimeF(start_time,end_time); return ret; } -int Sketch::initMove(int geoId, PointPos pos) +int Sketch::initMove(int geoId, PointPos pos, bool fine) { + isFine = fine; + geoId = checkGeoId(geoId); GCSsys.clearByTag(-1); - GCSsys.clearByTag(-2); // don't try to move sketches that contain conflicting constraints if (hasConflicts()) { @@ -1558,7 +1750,7 @@ int Sketch::initMove(int geoId, PointPos pos) } InitParameters = MoveParameters; - GCSsys.initSolution(Parameters); + GCSsys.initSolution(); isInitMove = true; return 0; } @@ -1636,18 +1828,6 @@ Base::Vector3d Sketch::getPoint(int geoId, PointPos pos) return Base::Vector3d(); } -int Sketch::diagnose(void) -{ - Conflicting.clear(); - if (GCSsys.isInit()) { - int dofs = GCSsys.diagnose(Parameters, Conflicting); - return dofs; - } - else { - return -1; - } -} - TopoShape Sketch::toShape(void) const diff --git a/src/Mod/Sketcher/App/Sketch.h b/src/Mod/Sketcher/App/Sketch.h index 8746ff226d..3ea95bc4fd 100644 --- a/src/Mod/Sketcher/App/Sketch.h +++ b/src/Mod/Sketcher/App/Sketch.h @@ -53,9 +53,21 @@ public: int solve(void); /// delete all geometry and constraints, leave an empty sketch void clear(void); - /// set the sketch up with geoms and constraints + /** set the sketch up with geoms and constraints + * + * returns the degree of freedom of a sketch and calculates a list of + * conflicting constraints + * + * 0 degrees of freedom correspond to a fully constrained sketch + * -1 degrees of freedom correspond to an over-constrained sketch + * positive degrees of freedom correspond to an under-constrained sketch + * + * an over-constrained sketch will always contain conflicting constraints + * a fully constrained or under-constrained sketch may contain conflicting + * constraints or may not + */ int setUpSketch(const std::vector &GeoList, const std::vector &ConstraintList, - bool withDiagnose=true, int extGeoCount=0); + int extGeoCount=0); /// return the actual geometry of the sketch a TopoShape Part::TopoShape toShape(void) const; /// add unspecified geometry @@ -71,20 +83,10 @@ public: /// retrieves a point Base::Vector3d getPoint(int geoId, PointPos pos); - /** returns the degree of freedom of a sketch and calculates a list of - * conflicting constraints - * - * 0 degrees of freedom correspond to a fully constrained sketch - * -1 degrees of freedom correspond to an over-constrained sketch - * positive degrees of freedom correspond to an under-constrained sketch - * - * an over-constrained sketch will always contain conflicting constraints - * a fully constrained or under-constrained sketch may contain conflicting - * constraints or may not - */ - int diagnose(void); - bool hasConflicts(void) const { return (Conflicting.size() > 0); }; - const std::vector &getConflicting(void) const { return Conflicting; }; + bool hasConflicts(void) const { return (Conflicting.size() > 0); } + const std::vector &getConflicting(void) const { return Conflicting; } + bool hasRedundancies(void) const { return (Redundant.size() > 0); } + const std::vector &getRedundant(void) const { return Redundant; } /** set the datum of a distance or angle constraint to a certain value and solve * This can cause the solving to fail! @@ -94,14 +96,14 @@ public: /** initializes a point (or curve) drag by setting the current * sketch status as a reference */ - int initMove(int geoIndex, PointPos pos); + int initMove(int geoId, PointPos pos, bool fine=true); /** move this point (or curve) to a new location and solve. * This will introduce some additional weak constraints expressing * a condition for satisfying the new point location! * The relative flag permits moving relatively to the current position */ - int movePoint(int geoIndex, PointPos pos, Base::Vector3d toPoint, bool relative=false); + int movePoint(int geoId, PointPos pos, Base::Vector3d toPoint, bool relative=false); /// add dedicated geometry //@{ @@ -127,8 +129,8 @@ public: /// add one constraint to the sketch int addConstraint(const Constraint *constraint); /// add a fixed coordinate constraint to a point - int addCoordinateXConstraint(int geoIndex, PointPos pos, double value); - int addCoordinateYConstraint(int geoIndex, PointPos pos, double value); + int addCoordinateXConstraint(int geoId, PointPos pos, double value); + int addCoordinateYConstraint(int geoId, PointPos pos, double value); /// add a horizontal distance constraint to two points or line ends int addDistanceXConstraint(int geoId, double value); int addDistanceXConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value); @@ -136,34 +138,36 @@ public: int addDistanceYConstraint(int geoId, double value); int addDistanceYConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value); /// add a horizontal constraint to a geometry - int addHorizontalConstraint(int geoIndex); - int addHorizontalConstraint(int geoIndex1, PointPos pos1, int geoIndex2, PointPos pos2); + int addHorizontalConstraint(int geoId); + int addHorizontalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2); /// add a vertical constraint to a geometry - int addVerticalConstraint(int geoIndex); - int addVerticalConstraint(int geoIndex1, PointPos pos1, int geoIndex2, PointPos pos2); + int addVerticalConstraint(int geoId); + int addVerticalConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2); /// add a coincident constraint to two points of two geometries - int addPointCoincidentConstraint(int geoIndex1, PointPos pos1, int geoIndex2, PointPos pos2); + int addPointCoincidentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2); /// add a length or distance constraint - int addDistanceConstraint(int geoIndex1, double value); - int addDistanceConstraint(int geoIndex1, int geoIndex2, double value); - int addDistanceConstraint(int geoIndex1, PointPos pos1, int geoIndex2, double value); - int addDistanceConstraint(int geoIndex1, PointPos pos1, int geoIndex2, PointPos pos2, double value); + int addDistanceConstraint(int geoId1, double value); + int addDistanceConstraint(int geoId1, int geoId2, double value); + int addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, double value); + int addDistanceConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value); /// add a parallel constraint between two lines - int addParallelConstraint(int geoIndex1, int geoIndex2); + int addParallelConstraint(int geoId1, int geoId2); /// add a perpendicular constraint between two lines - int addPerpendicularConstraint(int geoIndex1, int geoIndex2); + int addPerpendicularConstraint(int geoId1, int geoId2); + int addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2); + int addPerpendicularConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2); /// add a tangency constraint between two geometries - int addTangentConstraint(int geoIndex1, int geoIndex2); - int addTangentConstraint(int geoIndex1, PointPos pos1, int geoIndex2); - int addTangentConstraint(int geoIndex1, PointPos pos1, int geoIndex2, PointPos pos2); + int addTangentConstraint(int geoId1, int geoId2); + int addTangentConstraint(int geoId1, PointPos pos1, int geoId2); + int addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2); /// add a radius constraint on a circle or an arc - int addRadiusConstraint(int geoIndex, double value); + int addRadiusConstraint(int geoId, double value); /// add an angle constraint on a line or between two lines - int addAngleConstraint(int geoIndex, double value); - int addAngleConstraint(int geoIndex1, int geoIndex2, double value); - int addAngleConstraint(int geoIndex1, PointPos pos1, int geoIndex2, PointPos pos2, double value); + int addAngleConstraint(int geoId, double value); + int addAngleConstraint(int geoId1, int geoId2, double value); + int addAngleConstraint(int geoId1, PointPos pos1, int geoId2, PointPos pos2, double value); /// add an equal length or radius constraints between two lines or between circles and arcs - int addEqualConstraint(int geoIndex1, int geoIndex2); + int addEqualConstraint(int geoId1, int geoId2); /// add a point on line constraint int addPointOnObjectConstraint(int geoId1, PointPos pos1, int geoId2); /// add a symmetric constraint between two points with respect to a line @@ -199,6 +203,7 @@ protected: GCS::System GCSsys; int ConstraintsCounter; std::vector Conflicting; + std::vector Redundant; // solving parameters std::vector Parameters; // with memory allocation @@ -210,6 +215,7 @@ protected: std::vector Circles; bool isInitMove; + bool isFine; private: /// retrieves the index of a point diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 95aa455a77..c09cd69639 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -97,7 +97,7 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) rebuildExternalGeometry(); Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); if (dofs < 0) { // over-constrained sketch std::string msg="Over-constrained sketch\n"; appendConflictMsg(sketch.getConflicting(), msg); @@ -108,6 +108,11 @@ App::DocumentObjectExecReturn *SketchObject::execute(void) appendConflictMsg(sketch.getConflicting(), msg); return new App::DocumentObjectExecReturn(msg.c_str(),this); } + if (sketch.hasRedundancies()) { // redundant constraints + std::string msg="Sketch with redundant constraints\n"; + appendRedundantMsg(sketch.getRedundant(), msg); + return new App::DocumentObjectExecReturn(msg.c_str(),this); + } // solve the sketch if (sketch.solve() != 0) @@ -128,7 +133,7 @@ int SketchObject::hasConflicts(void) const // set up a sketch (including dofs counting and diagnosing of conflicts) Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); if (dofs < 0) // over-constrained sketch return -2; if (sketch.hasConflicts()) // conflicting constraints @@ -166,7 +171,7 @@ int SketchObject::setDatum(int ConstrId, double Datum) // set up a sketch (including dofs counting and diagnosing of conflicts) Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); int err=0; if (dofs < 0) // over-constrained sketch err = -3; @@ -192,7 +197,7 @@ int SketchObject::movePoint(int GeoId, PointPos PosId, const Base::Vector3d& toP { Sketch sketch; int dofs = sketch.setUpSketch(getCompleteGeometry(), Constraints.getValues(), - true, getExternalGeometryCount()); + getExternalGeometryCount()); if (dofs < 0) // over-constrained sketch return -1; if (sketch.hasConflicts()) // conflicting constraints @@ -1388,10 +1393,32 @@ void SketchObject::appendConflictMsg(const std::vector &conflicting, std::s if (msg.length() > 0) ss << msg; if (conflicting.size() > 0) { - ss << "Please remove at least one of the constraints (" << conflicting[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"; + 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(); } diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index 83802d83a3..cf865d4053 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -136,6 +136,8 @@ public: /// generates a warning message about constraint conflicts and appends it to the given message static void appendConflictMsg(const std::vector &conflicting, std::string &msg); + /// generates a warning message about redundant constraints and appends it to the given message + static void appendRedundantMsg(const std::vector &redundant, std::string &msg); // from base class virtual PyObject *getPyObject(void); diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.cpp b/src/Mod/Sketcher/App/freegcs/Constraints.cpp index b893bb70ee..76b42f8d73 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/freegcs/Constraints.cpp @@ -771,4 +771,64 @@ double ConstraintMidpointOnLine::grad(double *param) return scale * deriv; } +// TangentCircumf +ConstraintTangentCircumf::ConstraintTangentCircumf(Point &p1, Point &p2, + double *rad1, double *rad2, bool internal_) +{ + internal = internal_; + pvec.push_back(p1.x); + pvec.push_back(p1.y); + pvec.push_back(p2.x); + pvec.push_back(p2.y); + pvec.push_back(rad1); + pvec.push_back(rad2); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintTangentCircumf::getTypeId() +{ + return TangentCircumf; +} + +void ConstraintTangentCircumf::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintTangentCircumf::error() +{ + double dx = (*c1x() - *c2x()); + double dy = (*c1y() - *c2y()); + if (internal) + return scale * (sqrt(dx*dx + dy*dy) - std::abs(*r1() - *r2())); + else + return scale * (sqrt(dx*dx + dy*dy) - (*r1() + *r2())); +} + +double ConstraintTangentCircumf::grad(double *param) +{ + double deriv=0.; + if (param == c1x() || param == c1y() || + param == c2x() || param == c2y()|| + param == r1() || param == r2()) { + double dx = (*c1x() - *c2x()); + double dy = (*c1y() - *c2y()); + double d = sqrt(dx*dx + dy*dy); + if (param == c1x()) deriv += dx/d; + if (param == c1y()) deriv += dy/d; + if (param == c2x()) deriv += -dx/d; + if (param == c2y()) deriv += -dy/d; + if (internal) { + if (param == r1()) deriv += (*r1() > *r2()) ? -1 : 1; + if (param == r2()) deriv += (*r1() > *r2()) ? 1 : -1; + } + else { + if (param == r1()) deriv += -1; + if (param == r2()) deriv += -1; + } + } + return scale * deriv; +} + } //namespace GCS diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.h b/src/Mod/Sketcher/App/freegcs/Constraints.h index 40018a9e8b..17abd3106e 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.h +++ b/src/Mod/Sketcher/App/freegcs/Constraints.h @@ -44,7 +44,8 @@ namespace GCS Parallel = 7, Perpendicular = 8, L2LAngle = 9, - MidpointOnLine = 10 + MidpointOnLine = 10, + TangentCircumf = 11 }; class Constraint @@ -262,6 +263,26 @@ namespace GCS virtual double grad(double *); }; + // TangentCircumf + class ConstraintTangentCircumf : public Constraint + { + private: + inline double* c1x() { return pvec[0]; } + inline double* c1y() { return pvec[1]; } + inline double* c2x() { return pvec[2]; } + inline double* c2y() { return pvec[3]; } + inline double* r1() { return pvec[4]; } + inline double* r2() { return pvec[5]; } + bool internal; + public: + ConstraintTangentCircumf(Point &p1, Point &p2, + double *rd1, double *rd2, bool internal_=false); + 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/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index 069e181626..ffab4c579f 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -27,32 +27,34 @@ #include "qp_eq.h" #include +#include +#include + namespace GCS { +typedef boost::adjacency_list Graph; + /////////////////////////////////////// // Solver /////////////////////////////////////// // System System::System() -: clist(0), +: plist(0), clist(0), c2p(), p2c(), - subsys0(0), - subsys1(0), - subsys2(0), - reference(), - init(false) + subSystems(0), subSystemsAux(0), + reference(0), + hasUnknowns(false), hasDiagnosis(false), isInit(false) { } System::System(std::vector clist_) -: c2p(), p2c(), - subsys0(0), - subsys1(0), - subsys2(0), - reference(), - init(false) +: plist(0), + c2p(), p2c(), + subSystems(0), subSystemsAux(0), + reference(0), + hasUnknowns(false), hasDiagnosis(false), isInit(false) { // create own (shallow) copy of constraints for (std::vector::iterator constr=clist_.begin(); @@ -124,7 +126,16 @@ System::~System() void System::clear() { - clearReference(); + plist.clear(); + pIndex.clear(); + hasUnknowns = false; + hasDiagnosis = false; + + redundant.clear(); + conflictingTags.clear(); + redundantTags.clear(); + + reference.clear(); clearSubSystems(); free(clist); c2p.clear(); @@ -147,7 +158,9 @@ void System::clearByTag(int tagId) int System::addConstraint(Constraint *constr) { - clearReference(); + isInit = false; + if (constr->getTag() >= 0) // negatively tagged constraints have no impact + hasDiagnosis = false; // on the diagnosis clist.push_back(constr); VEC_pD constr_params = constr->params(); @@ -162,12 +175,15 @@ int System::addConstraint(Constraint *constr) void System::removeConstraint(Constraint *constr) { - clearReference(); - clearSubSystems(); - std::vector::iterator it; it = std::find(clist.begin(), clist.end(), constr); + if (it == clist.end()) + return; + clist.erase(it); + if (constr->getTag() >= 0) + hasDiagnosis = false; + clearSubSystems(); VEC_pD constr_params = c2p[constr]; for (VEC_pD::const_iterator param=constr_params.begin(); @@ -208,9 +224,9 @@ int System::addConstraintP2PDistance(Point &p1, Point &p2, double *distance, int } int System::addConstraintP2PAngle(Point &p1, Point &p2, double *angle, - double incr_angle, int tagId) + double incrAngle, int tagId) { - Constraint *constr = new ConstraintP2PAngle(p1, p2, angle, incr_angle); + Constraint *constr = new ConstraintP2PAngle(p1, p2, angle, incrAngle); constr->setTag(tagId); return addConstraint(constr); } @@ -286,6 +302,14 @@ int System::addConstraintMidpointOnLine(Point &l1p1, Point &l1p2, return addConstraint(constr); } +int System::addConstraintTangentCircumf(Point &p1, Point &p2, double *rad1, double *rad2, + bool internal, int tagId) +{ + Constraint *constr = new ConstraintTangentCircumf(p1, p2, rad1, rad2, internal); + constr->setTag(tagId); + return addConstraint(constr); +} + // derived constraints int System::addConstraintP2PCoincident(Point &p1, Point &p2, int tagId) @@ -342,6 +366,67 @@ int System::addConstraintPointOnArc(Point &p, Arc &a, int tagId) return addConstraintP2PDistance(p, a.center, a.rad, tagId); } +int System::addConstraintPerpendicularLine2Arc(Point &p1, Point &p2, Arc &a, + int tagId) +{ + addConstraintP2PCoincident(p2, a.start, tagId); + double dx = *(p2.x) - *(p1.x); + double dy = *(p2.y) - *(p1.y); + if (dx * cos(*(a.startAngle)) + dy * sin(*(a.startAngle)) > 0) + return addConstraintP2PAngle(p1, p2, a.startAngle, 0, tagId); + else + return addConstraintP2PAngle(p1, p2, a.startAngle, M_PI, tagId); +} + +int System::addConstraintPerpendicularArc2Line(Arc &a, Point &p1, Point &p2, + int tagId) +{ + addConstraintP2PCoincident(p1, a.end, tagId); + double dx = *(p2.x) - *(p1.x); + double dy = *(p2.y) - *(p1.y); + if (dx * cos(*(a.endAngle)) + dy * sin(*(a.endAngle)) > 0) + return addConstraintP2PAngle(p1, p2, a.endAngle, 0, tagId); + else + return addConstraintP2PAngle(p1, p2, a.endAngle, M_PI, tagId); +} + +int System::addConstraintPerpendicularCircle2Arc(Point ¢er, double *radius, + Arc &a, int tagId) +{ + addConstraintP2PDistance(a.start, center, radius, tagId); + double incrAngle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2; + double tangAngle = *a.startAngle + incrAngle; + double dx = *(a.start.x) - *(center.x); + double dy = *(a.start.y) - *(center.y); + if (dx * cos(tangAngle) + dy * sin(tangAngle) > 0) + return addConstraintP2PAngle(center, a.start, a.startAngle, incrAngle, tagId); + else + return addConstraintP2PAngle(center, a.start, a.startAngle, -incrAngle, tagId); +} + +int System::addConstraintPerpendicularArc2Circle(Arc &a, Point ¢er, + double *radius, int tagId) +{ + addConstraintP2PDistance(a.end, center, radius, tagId); + double incrAngle = *(a.startAngle) < *(a.endAngle) ? -M_PI/2 : M_PI/2; + double tangAngle = *a.endAngle + incrAngle; + double dx = *(a.end.x) - *(center.x); + double dy = *(a.end.y) - *(center.y); + if (dx * cos(tangAngle) + dy * sin(tangAngle) > 0) + return addConstraintP2PAngle(center, a.end, a.endAngle, incrAngle, tagId); + else + return addConstraintP2PAngle(center, a.end, a.endAngle, -incrAngle, tagId); +} + +int System::addConstraintPerpendicularArc2Arc(Arc &a1, bool reverse1, + Arc &a2, bool reverse2, int tagId) +{ + Point &p1 = reverse1 ? a1.start : a1.end; + Point &p2 = reverse2 ? a2.end : a2.start; + addConstraintP2PCoincident(p1, p2, tagId); + return addConstraintPerpendicular(a1.center, p1, a2.center, p2, tagId); +} + int System::addConstraintTangent(Line &l, Circle &c, int tagId) { return addConstraintP2LDistance(c.center, l, c.rad, tagId); @@ -352,18 +437,82 @@ int System::addConstraintTangent(Line &l, Arc &a, int tagId) return addConstraintP2LDistance(a.center, l, a.rad, tagId); } +int System::addConstraintTangent(Circle &c1, Circle &c2, int tagId) +{ + double dx = *(c2.center.x) - *(c1.center.x); + double dy = *(c2.center.y) - *(c1.center.y); + double d = sqrt(dx*dx + dy*dy); + return addConstraintTangentCircumf(c1.center, c2.center, c1.rad, c2.rad, + (d < *c1.rad || d < *c2.rad), tagId); +} + +int System::addConstraintTangent(Arc &a1, Arc &a2, int tagId) +{ + double dx = *(a2.center.x) - *(a1.center.x); + double dy = *(a2.center.y) - *(a1.center.y); + double d = sqrt(dx*dx + dy*dy); + return addConstraintTangentCircumf(a1.center, a2.center, a1.rad, a2.rad, + (d < *a1.rad || d < *a2.rad), tagId); +} + +int System::addConstraintTangent(Circle &c, Arc &a, int tagId) +{ + double dx = *(a.center.x) - *(c.center.x); + double dy = *(a.center.y) - *(c.center.y); + double d = sqrt(dx*dx + dy*dy); + return addConstraintTangentCircumf(c.center, a.center, c.rad, a.rad, + (d < *c.rad || d < *a.rad), tagId); +} + int System::addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId) { addConstraintP2PCoincident(p2, a.start, tagId); - double incr_angle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2; - return addConstraintP2PAngle(p1, p2, a.startAngle, incr_angle, tagId); + double incrAngle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2; + return addConstraintP2PAngle(p1, p2, a.startAngle, incrAngle, tagId); } int System::addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId) { addConstraintP2PCoincident(p1, a.end, tagId); - double incr_angle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2; - return addConstraintP2PAngle(p1, p2, a.endAngle, incr_angle, tagId); + double incrAngle = *(a.startAngle) < *(a.endAngle) ? M_PI/2 : -M_PI/2; + return addConstraintP2PAngle(p1, p2, a.endAngle, incrAngle, tagId); +} + +int System::addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId) +{ + addConstraintPointOnCircle(a.start, c, tagId); + double dx = *(a.start.x) - *(c.center.x); + double dy = *(a.start.y) - *(c.center.y); + if (dx * cos(*(a.startAngle)) + dy * sin(*(a.startAngle)) > 0) + return addConstraintP2PAngle(c.center, a.start, a.startAngle, 0, tagId); + else + return addConstraintP2PAngle(c.center, a.start, a.startAngle, M_PI, tagId); +} + +int System::addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId) +{ + addConstraintPointOnCircle(a.end, c, tagId); + double dx = *(a.end.x) - *(c.center.x); + double dy = *(a.end.y) - *(c.center.y); + if (dx * cos(*(a.endAngle)) + dy * sin(*(a.endAngle)) > 0) + return addConstraintP2PAngle(c.center, a.end, a.endAngle, 0, tagId); + else + return addConstraintP2PAngle(c.center, a.end, a.endAngle, M_PI, tagId); +} + +int System::addConstraintTangentArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, + int tagId) +{ + Point &p1 = reverse1 ? a1.start : a1.end; + Point &p2 = reverse2 ? a2.end : a2.start; + addConstraintP2PCoincident(p1, p2, tagId); + + double *angle1 = reverse1 ? a1.startAngle : a1.endAngle; + double *angle2 = reverse2 ? a2.endAngle : a2.startAngle; + if (cos(*angle1) * cos(*angle2) + sin(*angle1) * sin(*angle2) > 0) + return addConstraintEqual(angle1, angle2, tagId); + else + return addConstraintP2PAngle(p2, a2.center, angle1, 0, tagId); } int System::addConstraintCircleRadius(Circle &c, double *radius, int tagId) @@ -411,9 +560,20 @@ void System::rescaleConstraint(int id, double coeff) clist[id]->rescale(coeff); } - -void System::initSolution(VEC_pD ¶ms) +void System::declareUnknowns(VEC_pD ¶ms) { + plist = params; + pIndex.clear(); + for (int i=0; i < int(plist.size()); ++i) + pIndex[plist[i]] = i; + hasUnknowns = true; +} + +void System::initSolution() +{ + // - Stores the current parameters values in the vector "reference" + // - identifies any decoupled subsystems and partitions the original + // system into corresponding components // - Stores the current parameters in the vector "reference" // - Identifies the equality constraints tagged with ids >= 0 // and prepares a corresponding system reduction @@ -421,111 +581,176 @@ void System::initSolution(VEC_pD ¶ms) // 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; + isInit = false; + if (!hasUnknowns) + return; + + // storing reference configuration + setReference(); + + // diagnose conflicting or redundant constraints + if (!hasDiagnosis) { + diagnose(); + if (!hasDiagnosis) + return; + } + std::vector clistR; + if (redundant.size()) { + for (std::vector::const_iterator constr=clist.begin(); + constr != clist.end(); ++constr) + if (redundant.count(*constr) == 0) + clistR.push_back(*constr); + } + else + clistR = clist; + + // partitioning into decoupled components + Graph g; + for (int i=0; i < int(plist.size() + clistR.size()); i++) + boost::add_vertex(g); + + int cvtid = int(plist.size()); + for (std::vector::const_iterator constr=clistR.begin(); + constr != clistR.end(); ++constr, cvtid++) { + VEC_pD &cparams = c2p[*constr]; + for (VEC_pD::const_iterator param=cparams.begin(); + param != cparams.end(); ++param) { + MAP_pD_I::const_iterator it = pIndex.find(*param); + if (it != pIndex.end()) + boost::add_edge(cvtid, it->second, g); + } + } + + VEC_I components(boost::num_vertices(g)); + int componentsSize = boost::connected_components(g, &components[0]); // identification of equality constraints and parameter reduction - std::set eliminated; // constraints that will be eliminated through reduction - reductionmap.clear(); + std::set reducedConstrs; // constraints that will be eliminated through reduction + reductionmaps.clear(); // destroy any maps + reductionmaps.resize(componentsSize); // create empty maps to be filled in { - VEC_pD reduced_params=params; - MAP_pD_I params_index; - for (int i=0; i < int(params.size()); ++i) - params_index[params[i]] = i; + VEC_pD reducedParams=plist; - for (std::vector::const_iterator constr=clist.begin(); - constr != clist.end(); ++constr) { + for (std::vector::const_iterator constr=clistR.begin(); + constr != clistR.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; + it1 = pIndex.find((*constr)->params()[0]); + it2 = pIndex.find((*constr)->params()[1]); + if (it1 != pIndex.end() && it2 != pIndex.end()) { + reducedConstrs.insert(*constr); + double *p_kept = reducedParams[it1->second]; + double *p_replaced = reducedParams[it2->second]; + for (int i=0; i < int(plist.size()); ++i) + if (reducedParams[i] == p_replaced) + reducedParams[i] = p_kept; } } } - for (int i=0; i < int(params.size()); ++i) - if (params[i] != reduced_params[i]) - reductionmap[params[i]] = reduced_params[i]; + for (int i=0; i < int(plist.size()); ++i) + if (plist[i] != reducedParams[i]) { + int cid = components[i]; + reductionmaps[cid][plist[i]] = reducedParams[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); + clists.clear(); // destroy any lists + clists.resize(componentsSize); // create empty lists to be filled in + int i = int(plist.size()); + for (std::vector::const_iterator constr=clistR.begin(); + constr != clistR.end(); ++constr, i++) { + if (reducedConstrs.count(*constr) == 0) { + int cid = components[i]; + clists[cid].push_back(*constr); } } + plists.clear(); // destroy any lists + plists.resize(componentsSize); // create empty lists to be filled in + for (int i=0; i < int(plist.size()); ++i) { + int cid = components[i]; + plists[cid].push_back(plist[i]); + } + + // calculates subSystems and subSystemsAux from clists, plists and reductionmaps 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; + for (int cid=0; cid < clists.size(); cid++) { + std::vector clist0, clist1; + for (std::vector::const_iterator constr=clists[cid].begin(); + constr != clists[cid].end(); ++constr) { + if ((*constr)->getTag() >= 0) + clist0.push_back(*constr); + else // move or distance from reference constraints + clist1.push_back(*constr); + } + + subSystems.push_back(NULL); + subSystemsAux.push_back(NULL); + if (clist0.size() > 0) + subSystems[cid] = new SubSystem(clist0, plists[cid], reductionmaps[cid]); + if (clist1.size() > 0) + subSystemsAux[cid] = new SubSystem(clist1, plists[cid], reductionmaps[cid]); + } + + isInit = true; } -void System::clearReference() +void System::setReference() { - init = false; reference.clear(); + reference.reserve(plist.size()); + for (VEC_pD::const_iterator param=plist.begin(); + param != plist.end(); ++param) + reference.push_back(**param); } void System::resetToReference() { - for (MAP_pD_D::const_iterator it=reference.begin(); - it != reference.end(); ++it) - *(it->first) = it->second; + if (reference.size() == plist.size()) { + VEC_D::const_iterator ref=reference.begin(); + VEC_pD::iterator param=plist.begin(); + for (; ref != reference.end(); ++ref, ++param) + **param = *ref; + } } int System::solve(VEC_pD ¶ms, bool isFine, Algorithm alg) { - initSolution(params); + declareUnknowns(params); + initSolution(); 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; + if (!isInit) + return Failed; + + bool isReset = false; + // return success by default in order to permit coincidence constraints to be applied + // even if no other system has to be solved + int res = Success; + for (int cid=0; cid < int(subSystems.size()); cid++) { + if ((subSystems[cid] || subSystemsAux[cid]) && !isReset) { + resetToReference(); + isReset = true; } - else if (subsys1) - return solve(subsys0, subsys1, isFine); - else - return solve(subsys0, isFine, alg); + if (subSystems[cid] && subSystemsAux[cid]) + res = std::max(res, solve(subSystems[cid], subSystemsAux[cid], isFine)); + else if (subSystems[cid]) + res = std::max(res, solve(subSystems[cid], isFine, alg)); + else if (subSystemsAux[cid]) + res = std::max(res, solve(subSystemsAux[cid], isFine, alg)); } - else if (subsys1) { - resetToReference(); - if (subsys2) - return solve(subsys1, subsys2, isFine); - else - return solve(subsys1, isFine, alg); + if (res == Success) { + for (std::set::const_iterator constr=redundant.begin(); + constr != redundant.end(); constr++) + if ((*constr)->error() > XconvergenceFine) { + res = Converged; + return res; + } } - else - // return success in order to permit coincidence constraints to be applied - return Success; + return res; } int System::solve(SubSystem *subsys, bool isFine, Algorithm alg) @@ -569,13 +794,13 @@ int System::solve_BFGS(SubSystem *subsys, bool isFine) double convergence = isFine ? XconvergenceFine : XconvergenceRough; int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*err + 1e12; + double divergingLim = 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 + if (err > divergingLim || err != err) // check for diverging and NaN break; y = grad; @@ -633,7 +858,7 @@ int System::solve_LM(SubSystem* subsys) e*=-1; int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*e.squaredNorm() + 1e12; + double divergingLim = 1e6*e.squaredNorm() + 1e12; double eps=1e-10, eps1=1e-80; double tau=1e-3; @@ -647,7 +872,7 @@ int System::solve_LM(SubSystem* subsys) stop = 1; break; } - else if (err > diverging_lim || err != err) { // check for diverging and NaN + else if (err > divergingLim || err != err) { // check for diverging and NaN stop = 6; break; } @@ -777,7 +1002,7 @@ int System::solve_DL(SubSystem* subsys) double fx_inf = fx.lpNorm(); int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*err + 1e12; + double divergingLim = 1e6*err + 1e12; double delta=0.1; double alpha=0.; @@ -794,7 +1019,7 @@ int System::solve_DL(SubSystem* subsys) stop = 2; else if (iter >= maxIterNumber) stop = 4; - else if (err > diverging_lim || err != err) { // check for diverging and NaN + else if (err > divergingLim || err != err) { // check for diverging and NaN stop = 6; } else { @@ -905,7 +1130,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) int xsizeB = subsysB->pSize(); int csizeA = subsysA->cSize(); - VEC_pD plist(xsizeA+xsizeB); + VEC_pD plistAB(xsizeA+xsizeB); { VEC_pD plistA, plistB; subsysA->getParamList(plistA); @@ -916,10 +1141,10 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) VEC_pD::const_iterator it; it = std::set_union(plistA.begin(),plistA.end(), - plistB.begin(),plistB.end(),plist.begin()); - plist.resize(it-plist.begin()); + plistB.begin(),plistB.end(),plistAB.begin()); + plistAB.resize(it-plistAB.begin()); } - int xsize = plist.size(); + int xsize = plistAB.size(); Eigen::MatrixXd B = Eigen::MatrixXd::Identity(xsize, xsize); Eigen::MatrixXd JA(csizeA, xsize); @@ -937,17 +1162,17 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) 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->getParams(plistAB,x); + subsysA->getParams(plistAB,x); + subsysB->setParams(plistAB,x); // just to ensure that A and B are synchronized - subsysB->calcGrad(plist,grad); - subsysA->calcJacobi(plist,JA); + subsysB->calcGrad(plistAB,grad); + subsysA->calcJacobi(plistAB,JA); subsysA->calcResidual(resA); double convergence = isFine ? XconvergenceFine : XconvergenceRough; int maxIterNumber = MaxIterations * xsize; - double diverging_lim = 1e6*subsysA->error() + 1e12; + double divergingLim = 1e6*subsysA->error() + 1e12; double mu = 0; lambda.setZero(); @@ -967,7 +1192,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) double tau=0.5; double rho=0.5; double alpha=1; - alpha = std::min(alpha, subsysA->maxStep(plist,xdir)); + alpha = std::min(alpha, subsysA->maxStep(plistAB,xdir)); // Eq. 18.32 // double mu = lambda.lpNorm() + 0.01; @@ -985,8 +1210,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) double deriv = grad.dot(xdir) - mu * resA.lpNorm<1>(); x = x0 + alpha * xdir; - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); + subsysA->setParams(plistAB,x); + subsysB->setParams(plistAB,x); subsysA->calcResidual(resA); double f = subsysB->error() + mu * resA.lpNorm<1>(); @@ -998,8 +1223,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) // Eigen::ComputeThinV).solve(-resA); xdir1 = -Y*resA; x += xdir1; // = x0 + alpha * xdir + xdir1 - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); + subsysA->setParams(plistAB,x); + subsysB->setParams(plistAB,x); subsysA->calcResidual(resA); f = subsysB->error() + mu * resA.lpNorm<1>(); if (f < f0 + eta * alpha * deriv) @@ -1009,8 +1234,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) if (alpha < 1e-8) // let the linesearch fail alpha = 0.; x = x0 + alpha * xdir; - subsysA->setParams(plist,x); - subsysB->setParams(plist,x); + subsysA->setParams(plistAB,x); + subsysB->setParams(plistAB,x); subsysA->calcResidual(resA); f = subsysB->error() + mu * resA.lpNorm<1>(); if (alpha < 1e-8) // let the linesearch fail @@ -1023,8 +1248,8 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) y = grad - JA.transpose() * lambda; { - subsysB->calcGrad(plist,grad); - subsysA->calcJacobi(plist,JA); + subsysB->calcGrad(plistAB,grad); + subsysA->calcJacobi(plistAB,JA); subsysA->calcResidual(resA); } y = grad - JA.transpose() * lambda - y; // Eq. 18.13 @@ -1042,7 +1267,7 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) double err = subsysA->error(); if (h.norm() <= convergence && err <= smallF) break; - if (err > diverging_lim || err != err) // check for diverging and NaN + if (err > divergingLim || err != err) // check for diverging and NaN break; } @@ -1060,29 +1285,17 @@ int System::solve(SubSystem *subsysA, SubSystem *subsysB, bool isFine) } -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); + for (int cid=0; cid < int(subSystems.size()); cid++) { + if (subSystemsAux[cid]) + subSystemsAux[cid]->applySolution(); + if (subSystems[cid]) + subSystems[cid]->applySolution(); + for (MAP_pD_pD::const_iterator it=reductionmaps[cid].begin(); + it != reductionmaps[cid].end(); ++it) + *(it->first) = *(it->second); + } } void System::undoSolution() @@ -1090,92 +1303,201 @@ void System::undoSolution() resetToReference(); } -int System::diagnose(VEC_pD ¶ms, VEC_I &conflicting) +int System::diagnose() { // 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()); + // The vector "conflictingTags" will hold a group of conflicting constraints + + // Hint 1: Only constraints with tag >= 0 are taken into account + // Hint 2: Constraints tagged with 0 are treated as high priority + // constraints and they are excluded from the returned + // list of conflicting constraints. Therefore, this function + // will provide no feedback about possible conflicts between + // two high priority constraints. For this reason, tagging + // constraints with 0 should be used carefully. + hasDiagnosis = false; + if (!hasUnknowns) { + dofs = -1; + return dofs; + } + + redundant.clear(); + conflictingTags.clear(); + redundantTags.clear(); + Eigen::MatrixXd J(clist.size(), plist.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]); + for (int j=0; j < int(plist.size()); j++) + J(count-1,j) = (*constr)->grad(plist[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 paramsNum = qrJT.rows(); + int constrNum = qrJT.cols(); int rank = qrJT.rank(); Eigen::MatrixXd R; - if (constr_num >= params_num) + if (constrNum >= paramsNum) R = qrJT.matrixQR().triangularView(); else - R = qrJT.matrixQR().topRows(constr_num) + R = qrJT.matrixQR().topRows(constrNum) .triangularView(); - if (constr_num > rank) { // conflicting constraints + if (constrNum > rank) { // conflicting or redundant 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.block(row,i+1,1,constrNum-i-1) -= coef * R.block(i,i+1,1,constrNum-i-1); R(row,i) = 0; } } } - conflictingIndex.resize(constr_num-rank); - for (int j=rank; j < constr_num; j++) { + std::vector< std::vector > conflictGroups(constrNum-rank); + for (int j=rank; j < constrNum; 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); + if (fabs(R(row,j)) > 1e-10) { + int origCol = qrJT.colsPermutation().indices()[row]; + conflictGroups[j-rank].push_back(clist[origCol]); } } - int orig_col = qrJT.colsPermutation().indices()[j]; - conflictingIndex[j-rank].push_back(orig_col); + int origCol = qrJT.colsPermutation().indices()[j]; + conflictGroups[j-rank].push_back(clist[origCol]); } - 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]]); + // try to remove the conflicting constraints and solve the + // system in order to check if the removed constraints were + // just redundant but not really conflicting + std::set skipped; + SET_I satisfiedGroups; + while (1) { + std::map< Constraint *, SET_I > conflictingMap; + for (int i=0; i < conflictGroups.size(); i++) { + if (satisfiedGroups.count(i) == 0) { + for (int j=0; j < conflictGroups[i].size(); j++) { + Constraint *constr = conflictGroups[i][j]; + if (constr->getTag() != 0) // exclude constraints tagged with zero + conflictingMap[constr].insert(i); + } + } + } + if (conflictingMap.empty()) + break; + + int maxPopularity = 0; + Constraint *mostPopular = NULL; + for (std::map< Constraint *, SET_I >::const_iterator it=conflictingMap.begin(); + it != conflictingMap.end(); it++) { + if (it->second.size() > maxPopularity || + (it->second.size() == maxPopularity && mostPopular && + it->first->getTag() > mostPopular->getTag())) { + mostPopular = it->first; + maxPopularity = it->second.size(); + } + } + if (maxPopularity > 0) { + skipped.insert(mostPopular); + for (SET_I::const_iterator it=conflictingMap[mostPopular].begin(); + it != conflictingMap[mostPopular].end(); it++) + satisfiedGroups.insert(*it); } } - 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; + std::vector clistTmp; + clistTmp.reserve(clist.size()); + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) + if (skipped.count(*constr) == 0) + clistTmp.push_back(*constr); + + SubSystem *subSysTmp = new SubSystem(clistTmp, plist); + int res = solve(subSysTmp); + if (res == Success) { + subSysTmp->applySolution(); + for (std::set::const_iterator constr=skipped.begin(); + constr != skipped.end(); constr++) { + double err = (*constr)->error(); + if (err * err < XconvergenceFine) + redundant.insert(*constr); + } + resetToReference(); + + std::vector< std::vector > conflictGroupsOrig=conflictGroups; + conflictGroups.clear(); + for (int i=conflictGroupsOrig.size()-1; i >= 0; i--) { + bool isRedundant = false; + for (int j=0; j < conflictGroupsOrig[i].size(); j++) { + if (redundant.count(conflictGroupsOrig[i][j]) > 0) { + isRedundant = true; + break; + } + } + if (!isRedundant) + conflictGroups.push_back(conflictGroupsOrig[i]); + else + constrNum--; + } + } + delete subSysTmp; + + // simplified output of conflicting tags + SET_I conflictingTagsSet; + for (int i=0; i < conflictGroups.size(); i++) { + for (int j=0; j < conflictGroups[i].size(); j++) { + conflictingTagsSet.insert(conflictGroups[i][j]->getTag()); + } + } + conflictingTagsSet.erase(0); // exclude constraints tagged with zero + conflictingTags.resize(conflictingTagsSet.size()); + std::copy(conflictingTagsSet.begin(), conflictingTagsSet.end(), + conflictingTags.begin()); + + // output of redundant tags + SET_I redundantTagsSet; + for (std::set::iterator constr=redundant.begin(); + constr != redundant.end(); ++constr) + redundantTagsSet.insert((*constr)->getTag()); + // remove tags represented at least in one non-redundant constraint + for (std::vector::iterator constr=clist.begin(); + constr != clist.end(); ++constr) + if (redundant.count(*constr) == 0) + redundantTagsSet.erase((*constr)->getTag()); + redundantTags.resize(redundantTagsSet.size()); + std::copy(redundantTagsSet.begin(), redundantTagsSet.end(), + redundantTags.begin()); + + if (paramsNum == rank && constrNum > rank) { // over-constrained + hasDiagnosis = true; + dofs = paramsNum - constrNum; + return dofs; + } } - return params_num - rank; + hasDiagnosis = true; + dofs = paramsNum - rank; + return dofs; } - return params.size(); + hasDiagnosis = true; + dofs = plist.size(); + return dofs; } void System::clearSubSystems() { - init = false; - std::vector subsystems; - getSubSystems(subsystems); - free(subsystems); - subsys0 = NULL; - subsys1 = NULL; - subsys2 = NULL; + isInit = false; + free(subSystems); + free(subSystemsAux); + subSystems.clear(); + subSystemsAux.clear(); } double lineSearch(SubSystem *subsys, Eigen::VectorXd &xdir) diff --git a/src/Mod/Sketcher/App/freegcs/GCS.h b/src/Mod/Sketcher/App/freegcs/GCS.h index 9e809c6c23..f0d87906fb 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.h +++ b/src/Mod/Sketcher/App/freegcs/GCS.h @@ -49,23 +49,31 @@ namespace GCS // This is the main class. It holds all constraints and information // about partitioning into subsystems and solution strategies private: - std::vector clist; + VEC_pD plist; // list of the unknown parameters + MAP_pD_I pIndex; + 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 + std::vector subSystems, subSystemsAux; void clearSubSystems(); - MAP_pD_D reference; - void clearReference(); - void resetToReference(); + VEC_D reference; + void setReference(); // copies the current parameter values to reference + void resetToReference(); // reverts all parameter values to the stored reference - MAP_pD_pD reductionmap; // for simplification of equality constraints + std::vector< VEC_pD > plists; // partitioned plist except equality constraints + std::vector< std::vector > clists; // partitioned clist except equality constraints + std::vector< MAP_pD_pD > reductionmaps; // for simplification of equality constraints - bool init; + int dofs; + std::set redundant; + VEC_I conflictingTags, redundantTags; + + bool hasUnknowns; // if plist is filled with the unknown parameters + bool hasDiagnosis; // if dofs, conflictingTags, redundantTags are up to date + bool isInit; // if plists, clists, reductionmaps are up to date int solve_BFGS(SubSystem *subsys, bool isFine); int solve_LM(SubSystem *subsys); @@ -87,7 +95,7 @@ namespace GCS double *difference, int tagId=0); int addConstraintP2PDistance(Point &p1, Point &p2, double *distance, int tagId=0); int addConstraintP2PAngle(Point &p1, Point &p2, double *angle, - double incr_angle, int tagId=0); + double incrAngle, int tagId=0); int addConstraintP2PAngle(Point &p1, Point &p2, double *angle, int tagId=0); int addConstraintP2LDistance(Point &p, Line &l, double *distance, int tagId=0); int addConstraintPointOnLine(Point &p, Line &l, int tagId=0); @@ -101,6 +109,8 @@ namespace GCS int addConstraintMidpointOnLine(Line &l1, Line &l2, int tagId=0); int addConstraintMidpointOnLine(Point &l1p1, Point &l1p2, Point &l2p1, Point &l2p2, int tagId=0); + int addConstraintTangentCircumf(Point &p1, Point &p2, double *rd1, double *rd2, + bool internal=false, int tagId=0); // derived constraints int addConstraintP2PCoincident(Point &p1, Point &p2, int tagId=0); @@ -113,10 +123,27 @@ namespace GCS int addConstraintArcRules(Arc &a, int tagId=0); int addConstraintPointOnCircle(Point &p, Circle &c, int tagId=0); int addConstraintPointOnArc(Point &p, Arc &a, int tagId=0); + int addConstraintPerpendicularLine2Arc(Point &p1, Point &p2, Arc &a, + int tagId=0); + int addConstraintPerpendicularArc2Line(Arc &a, Point &p1, Point &p2, + int tagId=0); + int addConstraintPerpendicularCircle2Arc(Point ¢er, double *radius, Arc &a, + int tagId=0); + int addConstraintPerpendicularArc2Circle(Arc &a, Point ¢er, double *radius, + int tagId=0); + int addConstraintPerpendicularArc2Arc(Arc &a1, bool reverse1, + Arc &a2, bool reverse2, int tagId=0); int addConstraintTangent(Line &l, Circle &c, int tagId=0); int addConstraintTangent(Line &l, Arc &a, int tagId=0); + int addConstraintTangent(Circle &c1, Circle &c2, int tagId=0); + int addConstraintTangent(Arc &a1, Arc &a2, int tagId=0); + int addConstraintTangent(Circle &c, Arc &a, int tagId=0); int addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId=0); int addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId=0); + int addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId=0); + int addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId=0); + int addConstraintTangentArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, + int tagId=0); int addConstraintCircleRadius(Circle &c, double *radius, int tagId=0); int addConstraintArcRadius(Arc &a, double *radius, int tagId=0); int addConstraintEqualLength(Line &l1, Line &l2, double *length, int tagId=0); @@ -126,20 +153,23 @@ namespace GCS int addConstraintP2PSymmetric(Point &p1, Point &p2, Line &l, int tagId=0); void rescaleConstraint(int id, double coeff); - void initSolution(VEC_pD ¶ms); + void declareUnknowns(VEC_pD ¶ms); + void initSolution(); 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(); void undoSolution(); - bool isInit() const { return init; } - - int diagnose(VEC_pD ¶ms, VEC_I &conflicting); + int diagnose(); + int dofsNumber() { return hasDiagnosis ? dofs : -1; } + void getConflicting(VEC_I &conflictingOut) const + { conflictingOut = hasDiagnosis ? conflictingTags : VEC_I(0); } + void getRedundant(VEC_I &redundantOut) const + { redundantOut = hasDiagnosis ? redundantTags : VEC_I(0); } }; /////////////////////////////////////// diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 8ef99041fe..fd795eb939 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -1198,7 +1198,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) // only one sketch with its subelements are allowed to be selected if (selection.size() != 1) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select two lines from the sketch.")); + QObject::tr("Select two entities from the sketch.")); return; } @@ -1208,7 +1208,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) if (SubNames.size() != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select exactly two lines from the sketch.")); + QObject::tr("Select exactly two entities from the sketch.")); return; } @@ -1216,37 +1216,102 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) getIdsFromName(SubNames[0], GeoId1, VtId1); getIdsFromName(SubNames[1], GeoId2, VtId2); - if (checkBothExternal(GeoId1, GeoId2)) - return; - else if (GeoId1 == Constraint::GeoUndef || GeoId2 == Constraint::GeoUndef) { - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select exactly two lines from the sketch.")); + Sketcher::PointPos PosId1,PosId2; + if (VtId1 >= 0 && VtId2 >= 0) { // perpendicularity at common point + Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1); + Obj->getGeoVertexIndex(VtId2,GeoId2,PosId2); + + if (checkBothExternal(GeoId1, GeoId2)) + return; + + const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + if ((PosId1 != Sketcher::start && PosId1 != Sketcher::end) || + (PosId2 != Sketcher::start && PosId2 != Sketcher::end) || + (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && + geo1->getTypeId() != Part::GeomArcOfCircle::getClassTypeId()) || + (geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId())) { + + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected points should be end points of arcs and lines.")); + return; + } + + openCommand("add perpendicular constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2,PosId2); + commitCommand(); + updateActive(); + getSelection().clearSelection(); return; } + else if ((VtId1 >= 0 && GeoId2 != Constraint::GeoUndef) || + (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef)) { // VtId1 is a connecting point + if (VtId2 >= 0 && GeoId1 != Constraint::GeoUndef) { + VtId1 = VtId2; + VtId2 = -1; + GeoId2 = GeoId1; + GeoId1 = -1; + } + Obj->getGeoVertexIndex(VtId1,GeoId1,PosId1); - const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); - const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + if (checkBothExternal(GeoId1, GeoId2)) + return; - if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() || - geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { + const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + if ((PosId1 != Sketcher::start && PosId1 != Sketcher::end) || + (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && + geo1->getTypeId() != Part::GeomArcOfCircle::getClassTypeId())) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected point should be an end point of an arc or line.")); + return; + } + else if (geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() != Part::GeomArcOfCircle::getClassTypeId() && + geo2->getTypeId() != Part::GeomCircle::getClassTypeId()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("The selected edge should be an arc, line or circle.")); + return; + } - QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select exactly two lines from the sketch.")); + openCommand("add perpendicularity constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d,%d)) ", + selection[0].getFeatName(),GeoId1,PosId1,GeoId2); + commitCommand(); + updateActive(); + getSelection().clearSelection(); return; } + else if (GeoId1 != Constraint::GeoUndef && GeoId2 != Constraint::GeoUndef) { // simple perpendicularity between GeoId1 and GeoId2 - // undo command open - openCommand("add perpendicular constraint"); - Gui::Command::doCommand( - Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d)) ", - selection[0].getFeatName(),GeoId1,GeoId2); + if (checkBothExternal(GeoId1, GeoId2)) + return; - // finish the transaction and update - commitCommand(); - updateActive(); + const Part::Geometry *geo1 = Obj->getGeometry(GeoId1); + const Part::Geometry *geo2 = Obj->getGeometry(GeoId2); + if (geo1->getTypeId() != Part::GeomLineSegment::getClassTypeId() && + geo2->getTypeId() != Part::GeomLineSegment::getClassTypeId()) { + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("One of the selected edges should be a line.")); + return; + } - // clear the selection (convenience) - getSelection().clearSelection(); + openCommand("add perpendicular constraint"); + Gui::Command::doCommand( + Doc,"App.ActiveDocument.%s.addConstraint(Sketcher.Constraint('Perpendicular',%d,%d)) ", + selection[0].getFeatName(),GeoId1,GeoId2); + commitCommand(); + updateActive(); + getSelection().clearSelection(); + return; + } + QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), + QObject::tr("Select exactly two entities from the sketch.")); + return; } bool CmdSketcherConstrainPerpendicular::isActive(void) @@ -1674,7 +1739,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) circSel = true; else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select two or more edges of similar type")); + QObject::tr("Select two or more edges of similar type")); return; } @@ -1683,7 +1748,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) if (lineSel && (arcSel || circSel)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Select two or more edges of similar type")); + QObject::tr("Select two or more edges of similar type")); return; } @@ -1766,7 +1831,7 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg) if ((GeoId1 < 0 && GeoId2 < 0) || (GeoId1 < 0 && GeoId3 < 0) || (GeoId2 < 0 && GeoId3 < 0)) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("Cannot add a constraint between external geometries!")); + QObject::tr("Cannot add a constraint between external geometries!")); return; } diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 89685e99ab..02e508e761 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -621,7 +621,7 @@ public: if (geom->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { const Part::GeomLineSegment *lineSeg = dynamic_cast(geom); EditCurve[0] = Base::Vector2D(lineSeg->getEndPoint().x, lineSeg->getEndPoint().y); - } + } else EditCurve[0] = onSketchPos; @@ -1365,7 +1365,7 @@ CmdSketcherCreateFillet::CmdSketcherCreateFillet() sAppModule = "Sketcher"; sGroup = QT_TR_NOOP("Sketcher"); sMenuText = QT_TR_NOOP("Create fillet"); - sToolTipText = QT_TR_NOOP("Create a fillet between to lines or at a coincident point"); + sToolTipText = QT_TR_NOOP("Create a fillet between two lines or at a coincidental point"); sWhatsThis = sToolTipText; sStatusTip = sToolTipText; sPixmap = "Sketcher_CreateFillet"; diff --git a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp index 8fe503c376..58f1f027a6 100644 --- a/src/Mod/Sketcher/Gui/EditDatumDialog.cpp +++ b/src/Mod/Sketcher/Gui/EditDatumDialog.cpp @@ -103,7 +103,7 @@ void EditDatumDialog::exec(bool atCursor) if (dlg.exec()) { bool ok; - double newDatum = ui_ins_datum.lineEdit->text().toDouble(&ok); + double newDatum = QLocale::system().toDouble(ui_ins_datum.lineEdit->text(), &ok); if (ok) { if (Constr->Type == Sketcher::Angle) newDatum = Base::toRadians(newDatum); diff --git a/src/Mod/Sketcher/Gui/Resources/Makefile.am b/src/Mod/Sketcher/Gui/Resources/Makefile.am index 9f2fcbe477..1209d54ef4 100644 --- a/src/Mod/Sketcher/Gui/Resources/Makefile.am +++ b/src/Mod/Sketcher/Gui/Resources/Makefile.am @@ -92,6 +92,8 @@ icons/Constraint_PointOnObject.svg \ translations/Sketcher_nl.ts \ translations/Sketcher_no.qm \ translations/Sketcher_no.ts \ + translations/Sketcher_pl.qm \ + translations/Sketcher_pl.ts \ translations/Sketcher_pt.qm \ translations/Sketcher_pt.ts \ translations/Sketcher_ru.qm \ diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index 8a3fe93244..bdc5ad8050 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -74,6 +74,7 @@ translations/Sketcher_it.qm translations/Sketcher_nl.qm translations/Sketcher_no.qm + translations/Sketcher_pl.qm translations/Sketcher_pt.qm translations/Sketcher_ru.qm translations/Sketcher_se.qm diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.qm index e951bcde3b..60bdf874fa 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.ts index 9d1dc6ea38..25b2ec95df 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_af.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.qm index 2903e1faf0..0138326acd 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.ts index 15d7ca84a1..406f8292e9 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_de.ts @@ -284,7 +284,7 @@ Create fillet - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Create a fillet between to lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.qm index ecd25e2026..2f767e40b4 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.ts index a5801ab21d..08aca70c66 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_es.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.qm index 598c02aeb4..d7c3475553 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.ts index 2998c7de85..1711218dd0 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fi.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fr.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fr.ts index b743b9cb2b..fd6df2110c 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fr.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_fr.ts @@ -284,7 +284,7 @@ Créer un congé - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Créer un congé entre deux lignes ou sur un point coïncident diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.qm index 46138127b1..948b43d074 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.ts index 078496fa42..003063f072 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hr.ts @@ -284,7 +284,7 @@ Napravi obrub - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Napravi obrub između linija ili u podudarnoj točki diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.qm index 21e616c61a..558347ff97 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.ts index 6b4c1ea845..aba7fea162 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_hu.ts @@ -284,7 +284,7 @@ Lekerekítés létrehozása - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Hozzon létre egy kitöltést vonalak közt, vagy egy egybeeső ponttal diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.qm index 63b7939818..0c990e4b98 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.ts index ec6899b748..08cddc6684 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_it.ts @@ -284,7 +284,7 @@ Crea raccordo - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Creare un raccordo tra due linee o in un punto coincidente diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.qm index 27a92c786e..0412e80b0f 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.ts index 787553d0c8..8f01f74a9b 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ja.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.qm index 8f8d55ea4a..88b2deba76 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.ts index 8c861ef2f2..899c8cfe99 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_nl.ts @@ -284,7 +284,7 @@ Maak afronding - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Maak een afronding tussen twee lijnen of op een samenvallend punt diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.qm index fe283e2db7..2829c65d8e 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.ts index 6ca70856ae..fce70f0779 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_no.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.qm index 17d7235941..569c6b2e9d 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.ts index c695288a81..13039ef4e5 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pl.ts @@ -284,8 +284,8 @@ Utwórz zaokrąglenie - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.qm index e450c8be7a..e810e9742f 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.ts index 2634758f1b..65e4a2c099 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_pt.ts @@ -284,7 +284,7 @@ Criar filete - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Criar um filete entre duas linhas ou em um ponto coincidente diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.qm index ebf0961ae5..0a41970bba 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.ts index 8880737414..25c26d12fe 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_ru.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.qm index 4ff817a6e4..fb32131ed9 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.ts index 1d9b806179..f55fc45b2f 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_se.ts @@ -284,7 +284,7 @@ Skapa avrundning - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point Skapa en avrundning mellan två linjer eller vid en sammanfallande punkt diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.qm index 457ca29127..c35f768c36 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.ts index 0a07be3c40..bcd6db3f6f 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_uk.ts @@ -284,8 +284,8 @@ Create fillet - Create a fillet between to lines or at a coincident point - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point + Create a fillet between two lines or at a coincident point diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.qm b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.qm index 590e19d02c..5707960222 100644 Binary files a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.qm and b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.qm differ diff --git a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.ts b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.ts index eaff1e01c6..a91a6adc99 100644 --- a/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.ts +++ b/src/Mod/Sketcher/Gui/Resources/translations/Sketcher_zh.ts @@ -284,7 +284,7 @@ 创建圆角 - Create a fillet between to lines or at a coincident point + Create a fillet between two lines or at a coincident point 两直线或重合点处创建圆角 diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp index eef1b6cf2e..e8e2451d81 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.cpp @@ -42,6 +42,7 @@ TaskDlgEditSketch::TaskDlgEditSketch(ViewProviderSketch *sketchView) : TaskDialog(),sketchView(sketchView) { assert(sketchView); + documentName = sketchView->getObject()->getDocument()->getName(); Constraints = new TaskSketcherConstrains(sketchView); General = new TaskSketcherGeneral(sketchView); Messages = new TaskSketcherMessages(sketchView); @@ -76,10 +77,9 @@ bool TaskDlgEditSketch::accept() bool TaskDlgEditSketch::reject() { -// Gui::Command::openCommand("Sketch changed"); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.activeDocument().resetEdit()"); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); -// Gui::Command::commitCommand(); + std::string document = documentName; // needed because resetEdit() deletes this instance + Gui::Command::doCommand(Gui::Command::Gui,"Gui.getDocument('%s').resetEdit()", document.c_str()); + Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').recompute()", document.c_str()); return true; } diff --git a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h index 6dd199704a..506bf98d2e 100644 --- a/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h +++ b/src/Mod/Sketcher/Gui/TaskDlgEditSketch.h @@ -65,6 +65,7 @@ public: protected: ViewProviderSketch *sketchView; + std::string documentName; TaskSketcherConstrains *Constraints; TaskSketcherGeneral *General; diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp index 7061f3a97c..dc006117a7 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.cpp @@ -54,8 +54,8 @@ TaskSketcherMessages::TaskSketcherMessages(ViewProviderSketch *sketchView) this->groupLayout()->addWidget(proxy); - connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1,_2,_3)); - connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1,_2)); + connectionSetUp = sketchView->signalSetUp.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSetUp, this,_1)); + connectionSolved = sketchView->signalSolved.connect(boost::bind(&SketcherGui::TaskSketcherMessages::slotSolved, this,_1)); } TaskSketcherMessages::~TaskSketcherMessages() @@ -65,43 +65,14 @@ TaskSketcherMessages::~TaskSketcherMessages() delete ui; } -void TaskSketcherMessages::slotSetUp(int type, int dofs, const std::string &msg) +void TaskSketcherMessages::slotSetUp(QString msg) { - switch(type){ - case -1: - ui->labelConstrainStatus->setText(QString::fromLatin1("Empty sketch")); - break; - case 0: - ui->labelConstrainStatus->setText(QString::fromLatin1("Fully constrained sketch ")); - break; - case 1: - if (dofs==1) - ui->labelConstrainStatus->setText(QString::fromLatin1("Under-constrained sketch with 1 degree of freedom")); - else - ui->labelConstrainStatus->setText(QString::fromLatin1("Under-constrained sketch with %1 degrees of freedom").arg(dofs)); - break; - case 2: - ui->labelConstrainStatus->setText(QString::fromLatin1("Sketch contains conflicting constraints
%1
").arg(QString::fromStdString(msg))); - break; - case 3: - ui->labelConstrainStatus->setText(QString::fromLatin1("Over-constrained sketch
%1
").arg(QString::fromStdString(msg))); - break; - } + ui->labelConstrainStatus->setText(msg); } -void TaskSketcherMessages::slotSolved(int type, float time) +void TaskSketcherMessages::slotSolved(QString msg) { - switch(type){ - case -1: - ui->labelSolverStatus->setText(QString()); - break; - case 0: - ui->labelSolverStatus->setText(QString::fromLatin1("Solved in %1 sec").arg(time)); - break; - case 1: - ui->labelSolverStatus->setText(QString::fromLatin1("Unsolved (%1)").arg(time)); - break; - } + ui->labelSolverStatus->setText(msg); } #include "moc_TaskSketcherMessages.cpp" diff --git a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h index 7cdc104a7a..cdf5f907bd 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherMessages.h +++ b/src/Mod/Sketcher/Gui/TaskSketcherMessages.h @@ -47,8 +47,8 @@ public: TaskSketcherMessages(ViewProviderSketch *sketchView); ~TaskSketcherMessages(); - void slotSetUp(int type, int dofs, const std::string &msg); - void slotSolved(int type, float time); + void slotSetUp(QString msg); + void slotSolved(QString msg); private Q_SLOTS: diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 8699b4a1d3..4b6cc1988e 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -768,7 +768,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, int GeoId; Sketcher::PointPos PosId; getSketchObject()->getGeoVertexIndex(edit->DragPoint, GeoId, PosId); - edit->ActSketch.initMove(GeoId, PosId); + edit->ActSketch.initMove(GeoId, PosId, false); relative = false; xInit = 0; yInit = 0; @@ -785,7 +785,7 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, edit->PreselectCurve != -1 && edit->DragCurve != edit->PreselectCurve) { Mode = STATUS_SKETCH_DragCurve; edit->DragCurve = edit->PreselectCurve; - edit->ActSketch.initMove(edit->DragCurve, Sketcher::none); + edit->ActSketch.initMove(edit->DragCurve, Sketcher::none, false); const Part::Geometry *geo = getSketchObject()->getGeometry(edit->DragCurve); if (geo->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { relative = true; @@ -822,9 +822,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, if (edit->ActSketch.movePoint(GeoId, PosId, vec, relative) == 0) { setPositionText(Base::Vector2D(x,y)); draw(true); - signalSolved(0, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); } else { - signalSolved(1, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); //Base::Console().Log("Error solving:%d\n",ret); } } @@ -835,9 +835,9 @@ bool ViewProviderSketch::mouseMove(const SbVec3f &point, const SbVec3f &normal, if (edit->ActSketch.movePoint(edit->DragCurve, Sketcher::none, vec, relative) == 0) { setPositionText(Base::Vector2D(x,y)); draw(true); - signalSolved(0, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); } else { - signalSolved(1, edit->ActSketch.SolveTime); + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); } } return true; @@ -1497,7 +1497,9 @@ void ViewProviderSketch::drawConstraintIcons() break; case Perpendicular: icoType = QString::fromAscii("small/Constraint_Perpendicular_sm"); - index2 = 4; + // second icon is available only when there is no common point + if ((*it)->FirstPos == Sketcher::none) + index2 = 4; break; case Equal: icoType = QString::fromAscii("small/Constraint_EqualLength_sm"); @@ -1824,8 +1826,93 @@ Restart: } break; - case Parallel: case Perpendicular: + { + assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); + assert(Constr->Second >= -extGeoCount && Constr->Second < intGeoCount); + // get the geometry + const Part::Geometry *geo1 = GeoById(*geomlist, Constr->First); + const Part::Geometry *geo2 = GeoById(*geomlist, Constr->Second); + + Base::Vector3d midpos1, dir1, norm1; + Base::Vector3d midpos2, dir2, norm2; + + if (Constr->FirstPos == Sketcher::none) { + if (geo1->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg1 = dynamic_cast(geo1); + midpos1 = ((lineSeg1->getEndPoint()+lineSeg1->getStartPoint())/2); + dir1 = (lineSeg1->getEndPoint()-lineSeg1->getStartPoint()).Normalize(); + norm1 = Base::Vector3d(-dir1.y,dir1.x,0.); + } else if (geo1->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *arc = dynamic_cast(geo1); + double startangle, endangle, midangle; + arc->getRange(startangle, endangle); + midangle = (startangle + endangle)/2; + norm1 = Base::Vector3d(cos(midangle),sin(midangle),0); + dir1 = Base::Vector3d(-norm1.y,norm1.x,0); + midpos1 = arc->getCenter() + arc->getRadius() * norm1; + } else if (geo1->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle *circle = dynamic_cast(geo1); + norm1 = Base::Vector3d(cos(M_PI/4),sin(M_PI/4),0); + dir1 = Base::Vector3d(-norm1.y,norm1.x,0); + midpos1 = circle->getCenter() + circle->getRadius() * norm1; + } else + break; + + if (geo2->getTypeId() == Part::GeomLineSegment::getClassTypeId()) { + const Part::GeomLineSegment *lineSeg2 = dynamic_cast(geo2); + midpos2 = ((lineSeg2->getEndPoint()+lineSeg2->getStartPoint())/2); + dir2 = (lineSeg2->getEndPoint()-lineSeg2->getStartPoint()).Normalize(); + norm2 = Base::Vector3d(-dir2.y,dir2.x,0.); + } else if (geo2->getTypeId() == Part::GeomArcOfCircle::getClassTypeId()) { + const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); + double startangle, endangle, midangle; + arc->getRange(startangle, endangle); + midangle = (startangle + endangle)/2; + norm2 = Base::Vector3d(cos(midangle),sin(midangle),0); + dir2 = Base::Vector3d(-norm2.y,norm2.x,0); + midpos2 = arc->getCenter() + arc->getRadius() * norm2; + } else if (geo2->getTypeId() == Part::GeomCircle::getClassTypeId()) { + const Part::GeomCircle *circle = dynamic_cast(geo2); + norm2 = Base::Vector3d(cos(M_PI/4),sin(M_PI/4),0); + dir2 = Base::Vector3d(-norm2.y,norm2.x,0); + midpos2 = circle->getCenter() + circle->getRadius() * norm2; + } else + break; + + } else { + if (temp) + midpos1 = edit->ActSketch.getPoint(Constr->First, Constr->FirstPos); + else + midpos1 = getSketchObject()->getPoint(Constr->First, Constr->FirstPos); + norm1 = Base::Vector3d(0,1,0); + dir1 = Base::Vector3d(1,0,0); + } + + // Get Current Scale Factor + float scale = dynamic_cast(sep->getChild(1))->getScaleFactor(); + + Base::Vector3d constrPos1 = midpos1 + (norm1 * 2.5 * scale); + constrPos1 = seekConstraintPosition(constrPos1, dir1, scale * 2.5, edit->constrGroup->getChild(i)); + + // Translate the Icon based on calculated position + Base::Vector3d relPos1 = (constrPos1 - midpos1) / scale ; // Relative Position of Icons to Midpoint1 + dynamic_cast(sep->getChild(1))->abPos = SbVec3f(midpos1.x, midpos1.y, zConstr); + dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos1.x, relPos1.y, 0); + + if (Constr->FirstPos == Sketcher::none) { + Base::Vector3d constrPos2 = midpos2 + (norm2 * 2.5 * scale); + constrPos2 = seekConstraintPosition(constrPos2, dir2, 2.5 * scale, edit->constrGroup->getChild(i)); + + Base::Vector3d relPos2 = (constrPos2 - midpos2) / scale ; // Relative Position of Icons to Midpoint2 + Base::Vector3d secondPos = midpos2 - midpos1; + dynamic_cast(sep->getChild(3))->abPos = SbVec3f(secondPos.x, secondPos.y, zConstr); + dynamic_cast(sep->getChild(3))->translation = SbVec3f(relPos2.x -relPos1.x, relPos2.y -relPos1.y, 0); + } + + } + break; + case Parallel: case Equal: { assert(Constr->First >= -extGeoCount && Constr->First < intGeoCount); @@ -1877,7 +1964,7 @@ Restart: norm2 = Base::Vector3d(cos(angle2),sin(angle2),0); dir2 = Base::Vector3d(-norm2.y,norm2.x,0); midpos2 += r2*norm2; - } else // Parallel or Perpendicular can only apply to a GeomLineSegment + } else // Parallel can only apply to a GeomLineSegment break; } else { const Part::GeomLineSegment *lineSeg1 = dynamic_cast(geo1); @@ -2153,24 +2240,31 @@ Restart: const Part::GeomCircle *circle1 = dynamic_cast(geo1); const Part::GeomCircle *circle2 = dynamic_cast(geo2); // tangency between two cicles + Base::Vector3d dir = (circle2->getCenter() - circle1->getCenter()).Normalize(); + pos = circle1->getCenter() + dir * circle1->getRadius(); + relPos = dir * 1; } else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { std::swap(geo1,geo2); } - if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId()) { + if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() && + geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast(geo1); - if (geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { - const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); - // tangency between a circle and an arc - } + const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); + // tangency between a circle and an arc + Base::Vector3d dir = (arc->getCenter() - circle->getCenter()).Normalize(); + pos = circle->getCenter() + dir * circle->getRadius(); + relPos = dir * 1; } - - if (geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId() && - geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { + else if (geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId() && + geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc1 = dynamic_cast(geo1); const Part::GeomArcOfCircle *arc2 = dynamic_cast(geo2); // tangency between two arcs + Base::Vector3d dir = (arc2->getCenter() - arc1->getCenter()).Normalize(); + pos = arc1->getCenter() + dir * arc1->getRadius(); + relPos = dir * 1; } dynamic_cast(sep->getChild(1))->abPos = SbVec3f(pos.x, pos.y, zConstr); //Absolute Reference dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0); @@ -2600,42 +2694,7 @@ void ViewProviderSketch::updateData(const App::Property *prop) if (edit && (prop == &(getSketchObject()->Geometry) || &(getSketchObject()->Constraints))) { edit->FullyConstrained = false; - int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), - getSketchObject()->Constraints.getValues(), - true, getSketchObject()->getExternalGeometryCount()); - std::string msg; - if (getSketchObject()->Geometry.getSize() == 0) { - signalSetUp(-1, 0, msg); - signalSolved(-1, 0); - } - else if (dofs < 0) { // over-constrained sketch - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str()); - signalSetUp(3, 0, msg); - signalSolved(-1,0); - } - else if (edit->ActSketch.hasConflicts()) { // conflicting constraints - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str()); - signalSetUp(2, dofs, msg); - signalSolved(-1,0); - } - else if (edit->ActSketch.solve() == 0) { // solving the sketch - if (dofs == 0) { - // color the sketch as fully constrained - edit->FullyConstrained = true; - //Base::Console().Message("Fully constrained sketch\n"); - signalSetUp(0, 0, msg); - } - else { - //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs); - signalSetUp(1, dofs, msg); - } - signalSolved(0,edit->ActSketch.SolveTime); - } - else { - signalSolved(1,edit->ActSketch.SolveTime); - } + solveSketch(); draw(true); } if (edit && &(getSketchObject()->Constraints)) { @@ -2737,49 +2796,64 @@ bool ViewProviderSketch::setEdit(int ModNum) else Gui::Control().showDialog(new TaskDlgEditSketch(this)); - // set up the sketch and diagnose possible conflicts - int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), - getSketchObject()->Constraints.getValues(), - true, getSketchObject()->getExternalGeometryCount()); - std::string msg; - if (getSketchObject()->Geometry.getSize() == 0) { - signalSetUp(-1, 0, msg); - signalSolved(-1, 0); - } - else if (dofs < 0) { // over-constrained sketch - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Over-constrained sketch\n%s",msg.c_str()); - signalSetUp(3, 0, msg); - signalSolved(-1, 0); - } - else if (edit->ActSketch.hasConflicts()) { // conflicting constraints - SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); - //Base::Console().Warning("Sketch with conflicting constraints\n%s",msg.c_str()); - signalSetUp(2, dofs, msg); - signalSolved(-1, 0); - } - else if (edit->ActSketch.solve() == 0) { // solving the sketch - if (dofs == 0) { - // color the sketch as fully constrained - edit->FullyConstrained = true; - //Base::Console().Message("Fully constrained sketch\n"); - signalSetUp(0, 0, msg); - } - else { - //Base::Console().Message("Under-constrained sketch with %d degrees of freedom\n", dofs); - signalSetUp(1, dofs, msg); - } - signalSolved(0, edit->ActSketch.SolveTime); - } - else { - signalSolved(1, edit->ActSketch.SolveTime); - } - + solveSketch(); draw(); return true; } +void ViewProviderSketch::solveSketch(void) +{ + // set up the sketch and diagnose possible conflicts + int dofs = edit->ActSketch.setUpSketch(getSketchObject()->getCompleteGeometry(), + getSketchObject()->Constraints.getValues(), + getSketchObject()->getExternalGeometryCount()); + if (getSketchObject()->Geometry.getSize() == 0) { + signalSetUp(QString::fromLatin1("Empty sketch")); + signalSolved(QString()); + } + else if (dofs < 0) { // over-constrained sketch + std::string msg; + SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); + signalSetUp(QString::fromLatin1("Over-constrained sketch
%1
") + .arg(QString::fromStdString(msg))); + signalSolved(QString()); + } + else if (edit->ActSketch.hasConflicts()) { // conflicting constraints + std::string msg; + SketchObject::appendConflictMsg(edit->ActSketch.getConflicting(), msg); + signalSetUp(QString::fromLatin1("Sketch contains conflicting constraints
%1
") + .arg(QString::fromStdString(msg))); + signalSolved(QString()); + } + else { + if (edit->ActSketch.hasRedundancies()) { // redundant constraints + std::string msg; + SketchObject::appendRedundantMsg(edit->ActSketch.getRedundant(), msg); + signalSetUp(QString::fromLatin1("Sketch contains redundant constraints
%1
") + .arg(QString::fromStdString(msg))); + } + if (edit->ActSketch.solve() == 0) { // solving the sketch + if (dofs == 0) { + // color the sketch as fully constrained + edit->FullyConstrained = true; + if (!edit->ActSketch.hasRedundancies()) + signalSetUp(QString::fromLatin1("Fully constrained sketch ")); + } + else if (!edit->ActSketch.hasRedundancies()) { + if (dofs == 1) + signalSetUp(QString::fromLatin1("Under-constrained sketch with 1 degree of freedom")); + else + signalSetUp(QString::fromLatin1("Under-constrained sketch with %1 degrees of freedom").arg(dofs)); + } + signalSolved(QString::fromLatin1("Solved in %1 sec").arg(edit->ActSketch.SolveTime)); + } + else { + signalSolved(QString::fromLatin1("Unsolved (%1 sec)").arg(edit->ActSketch.SolveTime)); + } + } +} + void ViewProviderSketch::createEditInventorNodes(void) { assert(edit); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index 572547186a..2c98d71eb8 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -174,15 +174,17 @@ public: /// signals if the constraints list has changed boost::signal signalConstraintsChanged; /// signals if the sketch has been set up - boost::signal signalSetUp; + boost::signal signalSetUp; /// signals if the sketch has been solved - boost::signal signalSolved; + boost::signal signalSolved; protected: virtual bool setEdit(int ModNum); virtual void unsetEdit(int ModNum); virtual void setEditViewer(Gui::View3DInventorViewer*, int ModNum); virtual void unsetEditViewer(Gui::View3DInventorViewer*); + /// set up and solve the sketch + void solveSketch(void); /// helper to detect whether the picked point lies on the sketch bool isPointOnSketch(const SoPickedPoint *pp) const; /// get called by the container whenever a property has been changed diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index c196d63ce2..15a285f524 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -57,7 +57,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const Gui::MenuItem* sketch = new Gui::MenuItem; root->insertItem(item, sketch); - sketch->setCommand("Ske&tch"); + sketch->setCommand("S&ketch"); Gui::MenuItem* geom = new Gui::MenuItem(); geom->setCommand("Sketcher geometries"); *geom /*<< "Sketcher_CreatePoint"*/ diff --git a/src/Mod/Start/Gui/CMakeLists.txt b/src/Mod/Start/Gui/CMakeLists.txt index 54bdc5c5eb..339c9ad500 100644 --- a/src/Mod/Start/Gui/CMakeLists.txt +++ b/src/Mod/Start/Gui/CMakeLists.txt @@ -54,6 +54,8 @@ SET(StartPage_Resources StartPage/PartDesignExample.png StartPage/ArchExample.png StartPage/web.png + StartPage/blank.png + StartPage/complete.jpg ) add_library(StartGui SHARED ${StartGui_SRCS}) diff --git a/src/Mod/Start/Gui/Resources/Start.qrc b/src/Mod/Start/Gui/Resources/Start.qrc index c709e8da31..925ecd7f91 100644 --- a/src/Mod/Start/Gui/Resources/Start.qrc +++ b/src/Mod/Start/Gui/Resources/Start.qrc @@ -11,6 +11,7 @@ translations/StartPage_ru.qm translations/StartPage_se.qm translations/StartPage_uk.qm + translations/StartPage_pl.qm translations/StartPage_pt.qm translations/StartPage_hr.qm translations/StartPage_zh.qm diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage.ts b/src/Mod/Start/Gui/Resources/translations/StartPage.ts index 351391a346..f34c864d6e 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage.ts @@ -139,7 +139,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_af.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_af.qm index a62fcc758e..8f915edb5e 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_af.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_af.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_af.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_af.ts index 38c61e094c..85344f9082 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_af.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_af.ts @@ -140,8 +140,8 @@ - FreeCAD default workbench - FreeCAD default workbench + FreeCAD Complete workbench + FreeCAD Complete workbench diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_de.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_de.qm index 00eb940240..573d336fe8 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_de.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_de.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_de.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_de.ts index a394715b70..fb8eee8d9e 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_de.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_de.ts @@ -140,8 +140,8 @@ - FreeCAD default workbench - FreeCAD default workbench + FreeCAD Complete workbench + FreeCAD Complete workbench diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_es.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_es.qm index 1f1b3340ad..cb1ecc850c 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_es.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_es.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_es.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_es.ts index faf562b0f9..4778b7160d 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_es.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_es.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Entorno de trabajo predeterminado de FreeCAD diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_fi.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_fi.qm index 07b72ed6ac..6b18866b42 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_fi.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_fi.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_fi.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_fi.ts index df30593eed..2f651aafd0 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_fi.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_fi.ts @@ -140,8 +140,8 @@ - FreeCAD default workbench - FreeCAD default workbench + FreeCAD Complete workbench + FreeCAD Complete workbench diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_fr.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_fr.qm index b0deb5c621..1af3024590 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_fr.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_fr.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_fr.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_fr.ts index 36e72f5f0b..3598521433 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_fr.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_fr.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Atelier par défaut FreeCAD diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_hr.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_hr.qm index 42ee820c83..303541ace4 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_hr.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_hr.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_hr.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_hr.ts index 9fa39a6896..ede22f437a 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_hr.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_hr.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Inicijalno FreeCAD radno okruženje diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_hu.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_hu.qm index 84aedcf29e..d1c60b3b33 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_hu.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_hu.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_hu.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_hu.ts index 1e7bbc2f29..6e46c89d20 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_hu.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_hu.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench FreeCAD alapértelmezett munkafelület diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_it.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_it.qm index e696ad3807..08408c5306 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_it.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_it.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_it.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_it.ts index 04d4fa1893..b9aa0b60ff 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_it.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_it.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Ambiente di lavoro predefinito di FreeCAD diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_ja.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_ja.qm index 89fdd9e76e..ca9c3e5a88 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_ja.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_ja.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_ja.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_ja.ts index 1798e0ca1a..99f1e1fc30 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_ja.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_ja.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench FreeCADのデフォルトワークベンチ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_nl.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_nl.qm index 43d54648e9..abf2a7236f 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_nl.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_nl.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_nl.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_nl.ts index 1f37830bad..6ab92c4d3f 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_nl.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_nl.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench FreeCAD standaard werkbank diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_no.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_no.qm index 81164c1ea1..e920714c27 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_no.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_no.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_no.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_no.ts index c526fdc84b..9b24bb94ae 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_no.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_no.ts @@ -140,8 +140,8 @@ - FreeCAD default workbench - FreeCAD default workbench + FreeCAD Complete workbench + FreeCAD Complete workbench diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_pl.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_pl.qm index 9d2baeffa9..5e35f5b0ab 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_pl.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_pl.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_pl.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_pl.ts index 922ec55976..00d0e9e4ce 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_pl.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_pl.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Domyślne środowisko FreeCADa diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_pt.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_pt.qm index 7edfbb4cd7..3f1299c580 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_pt.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_pt.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_pt.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_pt.ts index 767755c562..120f704820 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_pt.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_pt.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Bancada padrão do FreeCAD diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_ru.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_ru.qm index f13fc55c4d..fc8b49b01a 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_ru.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_ru.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_ru.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_ru.ts index 90d45ed33a..dda7c4891f 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_ru.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_ru.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench Инструментарий FreeCAD по умолчанию diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_se.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_se.qm index 05cb07df74..af6a58a2b1 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_se.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_se.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_se.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_se.ts index 7310ccd02a..32a4cc2a89 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_se.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_se.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench FreeCAD standard arbetsbänk diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_uk.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_uk.qm index b49021a9ea..5ac3d9b66d 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_uk.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_uk.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_uk.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_uk.ts index 38a2e414a8..7ae42e6e1a 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_uk.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_uk.ts @@ -140,8 +140,8 @@ - FreeCAD default workbench - FreeCAD default workbench + FreeCAD Complete workbench + FreeCAD Complete workbench diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_zh.qm b/src/Mod/Start/Gui/Resources/translations/StartPage_zh.qm index 04c3229e0a..05b637001a 100644 Binary files a/src/Mod/Start/Gui/Resources/translations/StartPage_zh.qm and b/src/Mod/Start/Gui/Resources/translations/StartPage_zh.qm differ diff --git a/src/Mod/Start/Gui/Resources/translations/StartPage_zh.ts b/src/Mod/Start/Gui/Resources/translations/StartPage_zh.ts index ccf91a0f56..b740960fc1 100644 --- a/src/Mod/Start/Gui/Resources/translations/StartPage_zh.ts +++ b/src/Mod/Start/Gui/Resources/translations/StartPage_zh.ts @@ -140,7 +140,7 @@ - FreeCAD default workbench + FreeCAD Complete workbench FreeCAD默认工作台 diff --git a/src/Mod/Start/StartPage/CMakeLists.txt b/src/Mod/Start/StartPage/CMakeLists.txt index 19c59fcf32..7a798c98e4 100644 --- a/src/Mod/Start/StartPage/CMakeLists.txt +++ b/src/Mod/Start/StartPage/CMakeLists.txt @@ -24,6 +24,8 @@ SET(StartPage_DATA PartDesignExample.png ArchExample.png web.png + blank.png + complete.jpg ) INSTALL(FILES ${StartPage_SRCS} diff --git a/src/Mod/Start/StartPage/LoadDrawingExample.py b/src/Mod/Start/StartPage/LoadDrawingExample.py index 654a71f820..5067e60cf2 100644 --- a/src/Mod/Start/StartPage/LoadDrawingExample.py +++ b/src/Mod/Start/StartPage/LoadDrawingExample.py @@ -1,5 +1,5 @@ import FreeCAD,FreeCADGui FreeCADGui.activateWorkbench("DrawingWorkbench") FreeCAD.open(FreeCAD.getResourceDir()+"examples/DrawingExample.FCStd") -FreeCADGui.SendMsgToActiveView("ViewFit") -FreeCADGui.activeDocument().activeView().viewAxometric() +FreeCADGui.activeDocument().sendMsgToViews("ViewFit") +FreeCADGui.activeDocument().sendMsgToViews("ViewAxo") diff --git a/src/Mod/Start/StartPage/LoadPartDesignExample.py b/src/Mod/Start/StartPage/LoadPartDesignExample.py index 9d90f49699..cab24874f4 100644 --- a/src/Mod/Start/StartPage/LoadPartDesignExample.py +++ b/src/Mod/Start/StartPage/LoadPartDesignExample.py @@ -1,4 +1,4 @@ import FreeCAD,FreeCADGui FreeCAD.open(FreeCAD.getResourceDir()+"examples/PartDesignExample.FCStd") -FreeCADGui.SendMsgToActiveView("ViewFit") -FreeCADGui.activeDocument().activeView().viewAxometric() +FreeCADGui.activeDocument().sendMsgToViews("ViewFit") +FreeCADGui.activeDocument().sendMsgToViews("ViewAxo") diff --git a/src/Mod/Start/StartPage/LoadRobotExample.py b/src/Mod/Start/StartPage/LoadRobotExample.py index 229552b789..309298c7f5 100644 --- a/src/Mod/Start/StartPage/LoadRobotExample.py +++ b/src/Mod/Start/StartPage/LoadRobotExample.py @@ -1,4 +1,4 @@ import FreeCAD,FreeCADGui FreeCAD.open(FreeCAD.getResourceDir()+"examples/RobotExample.FCStd") -FreeCADGui.SendMsgToActiveView("ViewFit") -FreeCADGui.activeDocument().activeView().viewAxometric() +FreeCADGui.activeDocument().sendMsgToViews("ViewFit") +FreeCADGui.activeDocument().sendMsgToViews("ViewAxo") diff --git a/src/Mod/Start/StartPage/LoadSchenkel.py b/src/Mod/Start/StartPage/LoadSchenkel.py index 84aa61276e..c79973d010 100644 --- a/src/Mod/Start/StartPage/LoadSchenkel.py +++ b/src/Mod/Start/StartPage/LoadSchenkel.py @@ -1,4 +1,4 @@ import FreeCAD,FreeCADGui,Part Part.open(FreeCAD.getResourceDir()+"examples/Schenkel.stp") -FreeCADGui.SendMsgToActiveView("ViewFit") -Gui.activeDocument().activeView().viewAxometric() +FreeCADGui.activeDocument().sendMsgToViews("ViewFit") +FreeCADGui.activeDocument().sendMsgToViews("ViewAxo") diff --git a/src/Mod/Start/StartPage/Makefile.am b/src/Mod/Start/StartPage/Makefile.am index de35b6d452..57ffd74ee3 100644 --- a/src/Mod/Start/StartPage/Makefile.am +++ b/src/Mod/Start/StartPage/Makefile.am @@ -28,7 +28,9 @@ data_DATA = \ Complete.png \ PartDesignExample.png \ ArchExample.png \ - web.png + web.png \ + blank.png \ + complete.jpg EXTRA_DIST = \ $(data_DATA) $(python_DATA) diff --git a/src/Mod/Start/StartPage/StartPage.py b/src/Mod/Start/StartPage/StartPage.py index 26a573ba3d..978cae6b7b 100644 --- a/src/Mod/Start/StartPage/StartPage.py +++ b/src/Mod/Start/StartPage/StartPage.py @@ -1,4 +1,4 @@ -import os,FreeCAD,FreeCADGui,tempfile,time,zipfile,urllib,re +import os,FreeCAD,FreeCADGui,tempfile,time,zipfile,urllib,re,cStringIO from PyQt4 import QtGui from xml.etree.ElementTree import parse @@ -6,8 +6,19 @@ FreeCADGui.addLanguagePath(":/translations") FreeCADGui.updateLocale() def translate(context,text): - "convenience function for the Qt translator" - return str(QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).toUtf8()) + "convenience function for the Qt translator" + # return str(QtGui.QApplication.translate(context, text, None, QtGui.QApplication.UnicodeUTF8).toUtf8()) + u = QtGui.QApplication.translate(context, text, None, + QtGui.QApplication.UnicodeUTF8).toUtf8() + s = cStringIO.StringIO() + for i in u: + if ord(i) == 39: + s.write("\\'") + else: + s.write(i) + t = s.getvalue() + s.close() + return t # texts to be translated @@ -41,7 +52,7 @@ text27 = translate("StartPage","The Mesh Workbench is used to work with M text28 = translate("StartPage","FreeCAD offers you several tools to convert between Mesh and Part objects.") text29 = translate("StartPage","Work with Meshes") text30 = translate("StartPage","The complete workbench") -text31 = translate("StartPage","FreeCAD default workbench") +text31 = translate("StartPage","FreeCAD Complete workbench") text32 = translate("StartPage","populated with some of the most commonly used tools.") text33 = translate("StartPage","file size:") text34 = translate("StartPage","creation time:") @@ -66,144 +77,164 @@ page = """ FreeCAD - Start page + + + @@ -269,204 +300,207 @@ page = """ """ def getWebExamples(): - return """ - """ + return """ + """ def getExamples(): - return """ - """ + return """ + """ def getLinks(): - return """ - """ + return """ + """ def getWorkbenches(): - return """ - -""" + return """ + """ def getInfo(filename): - "returns available file information" + "returns available file information" - def getLocalTime(timestamp): - "returns a local time from a timestamp" - - return time.strftime("%m/%d/%Y %H:%M:%S",time.localtime(timestamp)) + def getLocalTime(timestamp): + "returns a local time from a timestamp" + return time.strftime("%m/%d/%Y %H:%M:%S",time.localtime(timestamp)) - def getSize(size): - "returns a human-readable size" - - if size > 1024*1024: - hsize = str(size/(1024*1024)) + "Mb" - elif size > 1024: - hsize = str(size/1024) + "Kb" - else: - hsize = str(size) + "b" - return hsize - - html = '

'+os.path.basename(filename)+'

' - - if os.path.exists(filename): - # get normal file info - s = os.stat(filename) - html += "

" + text33 + " " + getSize(s.st_size) + "
" - html += text34 + " " + getLocalTime(s.st_ctime) + "
" - html += text35 + " " + getLocalTime(s.st_mtime) + "
" - html += "" + text36 + " " + filename + "

" - # get additional info from fcstd files - if os.path.splitext(filename)[1] in [".fcstd",".FcStd"]: - zfile=zipfile.ZipFile(filename) - files=zfile.namelist() - # check for meta-file if it's really a FreeCAD document - if files[0] == "Document.xml": - html += "

FreeCAD Standard File

" - image="thumbnails/Thumbnail.png" - if image in files: - image=zfile.read(image) - thumbfile = tempfile.mkstemp(suffix='.png')[1] - thumb = open(thumbfile,"wb") - thumb.write(image) - thumb.close() - html += '
' + def getSize(size): + "returns a human-readable size" + if size > 1024*1024: + hsize = str(size/(1024*1024)) + "Mb" + elif size > 1024: + hsize = str(size/1024) + "Kb" else: - html += "

" + text41 + "

" - - return html + hsize = str(size) + "b" + return hsize + + html = '

'+os.path.basename(filename)+'

' + + if os.path.exists(filename): + # get normal file info + s = os.stat(filename) + html += "

" + text33 + " " + getSize(s.st_size) + "
" + html += text34 + " " + getLocalTime(s.st_ctime) + "
" + html += text35 + " " + getLocalTime(s.st_mtime) + "
" + html += "" + text36 + " " + filename + "

" + # get additional info from fcstd files + if os.path.splitext(filename)[1].upper() in [".FCSTD"]: + zfile=zipfile.ZipFile(filename) + files=zfile.namelist() + # check for meta-file if it's really a FreeCAD document + if files[0] == "Document.xml": + html += "

FreeCAD Standard File

" + image="thumbnails/Thumbnail.png" + if image in files: + image=zfile.read(image) + thumbfile = tempfile.mkstemp(suffix='.png')[1] + thumb = open(thumbfile,"wb") + thumb.write(image) + thumb.close() + html += '
' + else: + html += "

" + text41 + "

" + + return html def getRecentFiles(): - "returns a list of 3 latest recent files" - - rf=FreeCAD.ParamGet("User parameter:BaseApp/Preferences/RecentFiles") - ct=rf.GetInt("RecentFiles") - html = '
    ' - for i in range(3): - if i < ct: - mr = rf.GetString("MRU%d" % (i)) - fn = os.path.basename(mr) - html += '
  • ' - html += fn - html += '
  • ' - html += '
' - return html + "returns a list of 3 latest recent files" + rf = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/RecentFiles") + ct = rf.GetInt("RecentFiles") + html = '
    ' + for i in range(3): + if i < ct: + mr = rf.GetString("MRU%d" % (i)) + fn = os.path.basename(mr) + html += '
  • ' + if mr[-5:].upper() == "FCSTD": + html += ' ' + else: + html += ' ' + html += '' + html += fn + html += '
  • ' + html += '
' + return html def getFeed(url,numitems=3): - "returns a html list with links from the given RSS feed url" - xml = parse(urllib.urlopen(url)).getroot() - items = [] - channel = xml.find('channel') - for element in channel.findall('item'): - items.append({ - 'title': element.find('title').text, - 'description': element.find('description').text, - 'link': element.find('link').text, - }) - if len(items) > numitems: - items = items[:numitems] - resp = '
    ' - for item in items: - descr = re.compile("style=\".*?\"").sub('',item['description']) - descr = re.compile("alt=\".*?\"").sub('',descr) - descr = re.compile("\"").sub('',descr) - d1 = re.findall("",descr)[0] - d2 = re.findall(".*?",descr)[0] - descr = "

    " + item['title'] + "

    " - descr += d1 + "
    " - descr += d2 - resp += '
  • ' - resp += item['title'] - resp += '
  • ' - resp += '
' - print resp - return resp + "returns a html list with links from the given RSS feed url" + xml = parse(urllib.urlopen(url)).getroot() + items = [] + channel = xml.find('channel') + for element in channel.findall('item'): + items.append({'title': element.find('title').text, + 'description': element.find('description').text, + 'link': element.find('link').text}) + if len(items) > numitems: + items = items[:numitems] + resp = '
    ' + for item in items: + descr = re.compile("style=\".*?\"").sub('',item['description']) + descr = re.compile("alt=\".*?\"").sub('',descr) + descr = re.compile("\"").sub('',descr) + d1 = re.findall("",descr)[0] + d2 = re.findall(".*?",descr)[0] + descr = "

    " + item['title'] + "

    " + descr += d1 + "
    " + descr += d2 + resp += '
  • ' + resp += item['title'] + resp += '
  • ' + resp += '
' + print resp + return resp def getCustomBlocks(): - "fetches custom html files in FreeCAD user dir" - output = "" - return output + "fetches custom html files in FreeCAD user dir" + output = "" + return output def handle(): - "returns the complete html startpage" - - # add recent files - recentfiles = getRecentFiles() - html = page.replace("recentfiles",recentfiles) + "returns the complete html startpage" + + # add recent files + recentfiles = getRecentFiles() + html = page.replace("recentfiles",recentfiles) - # add default workbenches - html = html.replace("defaultworkbenches",getWorkbenches()) + # add default workbenches + html = html.replace("defaultworkbenches",getWorkbenches()) - # add default web links - html = html.replace("defaultlinks",getLinks()) + # add default web links + html = html.replace("defaultlinks",getLinks()) - # add default examples - html = html.replace("defaultexamples",getExamples()) + # add default examples + html = html.replace("defaultexamples",getExamples()) - # add web examples - #html = html.replace("webexamples",getWebExamples()) + # add web examples + #html = html.replace("webexamples",getWebExamples()) + + # add custom blocks + html = html.replace("customblocks",getCustomBlocks()) + + return html - # add custom blocks - html = html.replace("customblocks",getCustomBlocks()) - - return html - diff --git a/src/Mod/Start/StartPage/blank.png b/src/Mod/Start/StartPage/blank.png new file mode 100755 index 0000000000..4b79404484 Binary files /dev/null and b/src/Mod/Start/StartPage/blank.png differ diff --git a/src/Mod/Start/StartPage/complete.jpg b/src/Mod/Start/StartPage/complete.jpg new file mode 100644 index 0000000000..68c82d0304 Binary files /dev/null and b/src/Mod/Start/StartPage/complete.jpg differ diff --git a/src/Mod/Test/Gui/Makefile.am b/src/Mod/Test/Gui/Makefile.am index 8a3ead943e..35ce4cd52d 100644 --- a/src/Mod/Test/Gui/Makefile.am +++ b/src/Mod/Test/Gui/Makefile.am @@ -77,14 +77,38 @@ EXTRA_DIST = \ CMakeLists.txt \ UnitTest.ui \ Resources/Test.qrc \ + Resources/translations/Test_af.qm \ + Resources/translations/Test_af.ts \ Resources/translations/Test_de.qm \ - Resources/translations/Test_es.qm \ - Resources/translations/Test_fr.qm \ - Resources/translations/Test_it.qm \ - Resources/translations/Test_se.qm \ Resources/translations/Test_de.ts \ + Resources/translations/Test_es.qm \ Resources/translations/Test_es.ts \ + Resources/translations/Test_fi.qm \ + Resources/translations/Test_fi.ts \ + Resources/translations/Test_fr.qm \ Resources/translations/Test_fr.ts \ + Resources/translations/Test_hr.qm \ + Resources/translations/Test_hr.ts \ + Resources/translations/Test_hu.qm \ + Resources/translations/Test_hu.ts \ + Resources/translations/Test_it.qm \ Resources/translations/Test_it.ts \ + Resources/translations/Test_ja.qm \ + Resources/translations/Test_ja.ts \ + Resources/translations/Test_nl.qm \ + Resources/translations/Test_nl.ts \ + Resources/translations/Test_no.qm \ + Resources/translations/Test_no.ts \ + Resources/translations/Test_pl.qm \ + Resources/translations/Test_pl.ts \ + Resources/translations/Test_pt.qm \ + Resources/translations/Test_pt.ts \ + Resources/translations/Test_ru.qm \ + Resources/translations/Test_ru.ts \ + Resources/translations/Test_se.qm \ Resources/translations/Test_se.ts \ + Resources/translations/Test_uk.qm \ + Resources/translations/Test_uk.ts \ + Resources/translations/Test_zh.qm \ + Resources/translations/Test_zh.ts \ qtunittest.py diff --git a/src/Mod/Test/Gui/Resources/Test.qrc b/src/Mod/Test/Gui/Resources/Test.qrc index ef40be4f04..a494fcc5bc 100644 --- a/src/Mod/Test/Gui/Resources/Test.qrc +++ b/src/Mod/Test/Gui/Resources/Test.qrc @@ -1,9 +1,21 @@ + translations/Test_af.qm translations/Test_de.qm translations/Test_es.qm + translations/Test_fi.qm translations/Test_fr.qm + translations/Test_hr.qm + translations/Test_hu.qm translations/Test_it.qm + translations/Test_ja.qm + translations/Test_nl.qm + translations/Test_no.qm + translations/Test_pl.qm + translations/Test_pt.qm + translations/Test_ru.qm translations/Test_se.qm + translations/Test_uk.qm + translations/Test_zh.qm diff --git a/src/Tools/SubWCRev.py b/src/Tools/SubWCRev.py index 843f0796be..53b8a2eb66 100644 --- a/src/Tools/SubWCRev.py +++ b/src/Tools/SubWCRev.py @@ -153,7 +153,10 @@ class GitControl(VersionControl): self.url = r.groups()[0] break self.hash=os.popen("git log -1 --pretty=format:%H").read() - self.branch=os.popen("git branch").read().split('\n')[0][2:] + for self.branch in os.popen("git branch").read().split('\n'): + if re.match( "\*", self.branch ) != None: + break + self.branch=self.branch[2:] return True def printInfo(self): diff --git a/src/Tools/_TEMPLATE_/App/CMakeLists.txt b/src/Tools/_TEMPLATE_/App/CMakeLists.txt index adec71c683..a06ef307c5 100644 --- a/src/Tools/_TEMPLATE_/App/CMakeLists.txt +++ b/src/Tools/_TEMPLATE_/App/CMakeLists.txt @@ -20,7 +20,12 @@ SET(_TEMPLATE__SRCS add_library(_TEMPLATE_ SHARED ${_TEMPLATE__SRCS}) target_link_libraries(_TEMPLATE_ ${_TEMPLATE__LIBS}) -fc_copy_script("Mod/_TEMPLATE_" "_TEMPLATE_" Init.py) + + +fc_target_copy_resource(_TEMPLATE_ + ${CMAKE_SOURCE_DIR}/src/Tools/_TEMPLATE_ + ${CMAKE_BINARY_DIR}/Mod/_TEMPLATE_ + Init.py) if(MSVC) set_target_properties(_TEMPLATE_ PROPERTIES SUFFIX ".pyd") @@ -35,6 +40,7 @@ elseif(MINGW) else(MSVC) set_target_properties(_TEMPLATE_ PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/_TEMPLATE_) set_target_properties(_TEMPLATE_ PROPERTIES PREFIX "") + set_target_properties(Fem PROPERTIES INSTALL_RPATH ${INSTALL_RPATH}) endif(MSVC) install(TARGETS _TEMPLATE_ DESTINATION lib) diff --git a/src/Tools/_TEMPLATE_/Gui/CMakeLists.txt b/src/Tools/_TEMPLATE_/Gui/CMakeLists.txt index f995219db7..1924dd310e 100644 --- a/src/Tools/_TEMPLATE_/Gui/CMakeLists.txt +++ b/src/Tools/_TEMPLATE_/Gui/CMakeLists.txt @@ -1,3 +1,4 @@ + include_directories( ${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_BINARY_DIR} @@ -30,7 +31,11 @@ SET(_TEMPLATE_Gui_SRCS add_library(_TEMPLATE_Gui SHARED ${_TEMPLATE_Gui_SRCS}) target_link_libraries(_TEMPLATE_Gui ${_TEMPLATE_Gui_LIBS}) -fc_copy_script("Mod/_TEMPLATE_" "_TEMPLATE_Gui" InitGui.py) + +fc_target_copy_resource(_TEMPLATE_Gui + ${CMAKE_SOURCE_DIR}/src/Tools/_TEMPLATE_ + ${CMAKE_BINARY_DIR}/Mod/_TEMPLATE_ + InitGui.py) if(MSVC) set_target_properties(_TEMPLATE_Gui PROPERTIES SUFFIX ".pyd") @@ -45,6 +50,7 @@ elseif(MINGW) else(MSVC) set_target_properties(_TEMPLATE_Gui PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Mod/_TEMPLATE_) set_target_properties(_TEMPLATE_Gui PROPERTIES PREFIX "") + set_target_properties(Fem PROPERTIES INSTALL_RPATH ${INSTALL_RPATH}) endif(MSVC) install(TARGETS _TEMPLATE_Gui DESTINATION lib) diff --git a/src/Tools/_TEMPLATE_/Gui/Command.cpp b/src/Tools/_TEMPLATE_/Gui/Command.cpp index c2c66f6e81..feb5cd7fe7 100644 --- a/src/Tools/_TEMPLATE_/Gui/Command.cpp +++ b/src/Tools/_TEMPLATE_/Gui/Command.cpp @@ -48,7 +48,7 @@ Cmd_TEMPLATE_Test::Cmd_TEMPLATE_Test() sWhatsThis = QT_TR_NOOP("_TEMPLATE_ Test function"); sStatusTip = QT_TR_NOOP("_TEMPLATE_ Test function"); sPixmap = "Test1"; - iAccel = Qt::CTRL+Qt::Key_H; + sAccel = "CTRL+H"; } void Cmd_TEMPLATE_Test::activated(int iMsg) diff --git a/src/Tools/offlinedoc/buildpdf.py b/src/Tools/offlinedoc/buildpdf.py index ff9f53a15d..c6dbf246fd 100755 --- a/src/Tools/offlinedoc/buildpdf.py +++ b/src/Tools/offlinedoc/buildpdf.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/offlinedoc/buildqhelp.py b/src/Tools/offlinedoc/buildqhelp.py index 4325ed9152..77fa1bcaef 100755 --- a/src/Tools/offlinedoc/buildqhelp.py +++ b/src/Tools/offlinedoc/buildqhelp.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * diff --git a/src/Tools/offlinedoc/buildwikiindex.py b/src/Tools/offlinedoc/buildwikiindex.py index 581ef0d3e5..e685aed48a 100755 --- a/src/Tools/offlinedoc/buildwikiindex.py +++ b/src/Tools/offlinedoc/buildwikiindex.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -42,6 +42,7 @@ NORETRIEVE = ['Manual','Developer_hub','Power_users_hub','Users_hub','Source_doc GETTRANSLATIONS = False # Set true if you want to get the translations too. MAXFAIL = 3 # max number of retries if download fails VERBOSE = True # to display what's going on. Otherwise, runs totally silent. +WRITETHROUGH = True # if true, fetched files are constantly written to disk, in case of failure. # END CONFIGURATION ############################################## @@ -52,8 +53,24 @@ def crawl(): todolist = [] processed = [] count = 1 - indexpages,imgs = get(INDEX) - todolist.extend(indexpages) + if os.path.exists("wikifiles.txt"): + f = open("wikifiles.txt","r") + if VERBOSE: print "Reading existing list..." + for l in f.readlines(): + if l.strip() != "": + if VERBOSE: print "Adding ",l + processed.append(l.strip()) + f.close() + if os.path.exists("todolist.txt"): + f = open("todolist.txt","r") + if VERBOSE: print "Reading existing todo list..." + for l in f.readlines(): + if l.strip() != "": + todolist.append(l.strip()) + f.close() + else: + indexpages,imgs = get(INDEX) + todolist.extend(indexpages) while todolist: targetpage = todolist.pop() if not targetpage in NORETRIEVE: @@ -66,8 +83,12 @@ def crawl(): for p in pages: if (not (p in todolist)) and (not (p in processed)): todolist.append(p) + if WRITETHROUGH: + writeList(processed) + writeList(todolist,"todolist.txt") if VERBOSE: print "Fetched ", count, " pages" - writeList(processed) + if not WRITETHROUGH: + writeList(processed) return 0 def get(page): @@ -136,12 +157,22 @@ def fetchpage(page): failcount += 1 print 'Error: unable to fetch page ' + page -def writeList(pages): - f = open("wikifiles.txt","wb") +def cleanList(pagelist): + "cleans the list" + npages = [] + for p in pagelist: + if not p in npages: + if not "redlink" in p: + npages.append(p) + return npages + +def writeList(pages,filename="wikifiles.txt"): + pages = cleanList(pages) + f = open(filename,"wb") for p in pages: f.write(p+"\n") f.close() - if VERBOSE: print "written wikifiles.txt" + if VERBOSE: print "written ",filename if __name__ == "__main__": crawl() diff --git a/src/Tools/offlinedoc/downloadwiki.py b/src/Tools/offlinedoc/downloadwiki.py index 7589107664..4fc0bdadf9 100755 --- a/src/Tools/offlinedoc/downloadwiki.py +++ b/src/Tools/offlinedoc/downloadwiki.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Lesser General Public License (LGPL) * @@ -236,6 +236,9 @@ def fetchpage(page): def fetchimage(imagelink): "retrieves given image from the wiki and saves it" + if imagelink[0:5] == "File:": + print "Skipping file page link" + return filename = re.findall('.*/(.*)',imagelink)[0] print "saving",filename if not exists(filename,image=True): @@ -263,7 +266,7 @@ def local(page,image=False): def exists(page,image=False): "checks if given page/image already exists" - path = local(page,image) + path = local(page.replace("/","-"),image) if os.path.exists(path): return True return False diff --git a/src/Tools/plugins/widget/FreeCAD_widgets.sln b/src/Tools/plugins/widget/FreeCAD_widgets.sln deleted file mode 100644 index 98489c937f..0000000000 --- a/src/Tools/plugins/widget/FreeCAD_widgets.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual C++ Express 2005 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeCAD_widgets", "FreeCAD_widgets.vcproj", "{50CDC58F-0FF6-3CFA-BF66-E79DA98E7DF0}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {50CDC58F-0FF6-3CFA-BF66-E79DA98E7DF0}.Debug|Win32.ActiveCfg = Debug|Win32 - {50CDC58F-0FF6-3CFA-BF66-E79DA98E7DF0}.Debug|Win32.Build.0 = Debug|Win32 - {50CDC58F-0FF6-3CFA-BF66-E79DA98E7DF0}.Release|Win32.ActiveCfg = Release|Win32 - {50CDC58F-0FF6-3CFA-BF66-E79DA98E7DF0}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/Tools/plugins/widget/customwidgets.cpp b/src/Tools/plugins/widget/customwidgets.cpp index 6a2280377e..9de8c0f823 100644 --- a/src/Tools/plugins/widget/customwidgets.cpp +++ b/src/Tools/plugins/widget/customwidgets.cpp @@ -330,6 +330,94 @@ void AccelLineEdit::keyPressEvent ( QKeyEvent * e) // ------------------------------------------------------------------------------ +ActionSelector::ActionSelector(QWidget* parent) + : QWidget(parent) +{ + addButton = new QPushButton(this); + addButton->setMinimumSize(QSize(30, 30)); + QIcon icon; + icon.addFile(QString::fromUtf8(":/icons/button_right.xpm"), QSize(), QIcon::Normal, QIcon::Off); + addButton->setIcon(icon); + gridLayout = new QGridLayout(this); + gridLayout->addWidget(addButton, 1, 1, 1, 1); + + spacerItem = new QSpacerItem(33, 57, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacerItem, 5, 1, 1, 1); + spacerItem1 = new QSpacerItem(33, 58, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacerItem1, 0, 1, 1, 1); + + removeButton = new QPushButton(this); + removeButton->setMinimumSize(QSize(30, 30)); + QIcon icon1; + icon1.addFile(QString::fromUtf8(":/icons/button_left.xpm"), QSize(), QIcon::Normal, QIcon::Off); + removeButton->setIcon(icon1); + removeButton->setAutoDefault(true); + removeButton->setDefault(false); + + gridLayout->addWidget(removeButton, 2, 1, 1, 1); + + upButton = new QPushButton(this); + upButton->setMinimumSize(QSize(30, 30)); + QIcon icon3; + icon3.addFile(QString::fromUtf8(":/icons/button_up.xpm"), QSize(), QIcon::Normal, QIcon::Off); + upButton->setIcon(icon3); + + gridLayout->addWidget(upButton, 3, 1, 1, 1); + + downButton = new QPushButton(this); + downButton->setMinimumSize(QSize(30, 30)); + QIcon icon2; + icon2.addFile(QString::fromUtf8(":/icons/button_down.xpm"), QSize(), QIcon::Normal, QIcon::Off); + downButton->setIcon(icon2); + downButton->setAutoDefault(true); + + gridLayout->addWidget(downButton, 4, 1, 1, 1); + + vboxLayout = new QVBoxLayout(); + vboxLayout->setContentsMargins(0, 0, 0, 0); + labelAvailable = new QLabel(this); + vboxLayout->addWidget(labelAvailable); + + availableWidget = new QTreeWidget(this); + availableWidget->setRootIsDecorated(false); + availableWidget->setHeaderLabels(QStringList() << QString()); + availableWidget->header()->hide(); + vboxLayout->addWidget(availableWidget); + + gridLayout->addLayout(vboxLayout, 0, 0, 6, 1); + + vboxLayout1 = new QVBoxLayout(); + vboxLayout1->setContentsMargins(0, 0, 0, 0); + labelSelected = new QLabel(this); + vboxLayout1->addWidget(labelSelected); + + selectedWidget = new QTreeWidget(this); + selectedWidget->setRootIsDecorated(false); + selectedWidget->setHeaderLabels(QStringList() << QString()); + selectedWidget->header()->hide(); + vboxLayout1->addWidget(selectedWidget); + + gridLayout->addLayout(vboxLayout1, 0, 2, 6, 1); + + addButton->setText(QString()); + removeButton->setText(QString()); + upButton->setText(QString()); + downButton->setText(QString()); + + labelAvailable->setText(QApplication::translate("Gui::ActionSelector", "Available:", 0, QApplication::UnicodeUTF8)); + labelSelected->setText(QApplication::translate("Gui::ActionSelector", "Selected:", 0, QApplication::UnicodeUTF8)); + addButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Add", 0, QApplication::UnicodeUTF8)); + removeButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Remove", 0, QApplication::UnicodeUTF8)); + upButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Move up", 0, QApplication::UnicodeUTF8)); + downButton->setToolTip(QApplication::translate("Gui::ActionSelector", "Move down", 0, QApplication::UnicodeUTF8)); +} + +ActionSelector::~ActionSelector() +{ +} + +// -------------------------------------------------------------------- + CommandIconView::CommandIconView ( QWidget * parent ) : QListWidget(parent) { diff --git a/src/Tools/plugins/widget/customwidgets.h b/src/Tools/plugins/widget/customwidgets.h index 2543a119ef..013f6ba4ad 100644 --- a/src/Tools/plugins/widget/customwidgets.h +++ b/src/Tools/plugins/widget/customwidgets.h @@ -37,6 +37,7 @@ #include #include #include +#include namespace Gui { @@ -176,6 +177,32 @@ protected: // ------------------------------------------------------------------------------ +class ActionSelector : public QWidget +{ + Q_OBJECT + +public: + ActionSelector(QWidget* parent=0); + ~ActionSelector(); + +private: + QGridLayout *gridLayout; + QVBoxLayout *vboxLayout; + QVBoxLayout *vboxLayout1; + QPushButton *addButton; + QPushButton *removeButton; + QPushButton *upButton; + QPushButton *downButton; + QLabel *labelAvailable; + QLabel *labelSelected; + QTreeWidget *availableWidget; + QTreeWidget *selectedWidget; + QSpacerItem *spacerItem; + QSpacerItem *spacerItem1; +}; + +// ------------------------------------------------------------------------------ + class CommandIconView : public QListWidget { Q_OBJECT diff --git a/src/Tools/plugins/widget/plugin.cpp b/src/Tools/plugins/widget/plugin.cpp index d0a2aca923..3769f37d48 100644 --- a/src/Tools/plugins/widget/plugin.cpp +++ b/src/Tools/plugins/widget/plugin.cpp @@ -340,6 +340,79 @@ public: } }; +/* XPM */ +static const char *actionselector_pixmap[]={ +"22 22 6 1", +"a c #000000", +"# c #000080", +"b c #008080", +"c c #808080", +"d c #c0c0c0", +". c #ffffff", +"......................", +"......................", +"......................", +"...#aaaaaaaaaaaaaa#...", +".baccccccccccccccccab.", +".acccddddddddddddddca.", +"#ccd................d#", +"acc.................da", +"acd.......d....ca.ac.a", +"acd......db......a...a", +"acd.dbbb.dbbbd...a...a", +"acd.ccdbddb.db...a...a", +"acd.dbbbddb..b...a...a", +"acd.bd.bddb..b...a...a", +"acd.bbbbddbbbc...a...a", +"acd..d.....dd..ca.acda", +"#cd.................d#", +".ac................da.", +".badd............dda#.", +"...#aaaaaaaaaaaaaa#...", +"......................", +"......................"}; + +class ActionSelectorPlugin : public QDesignerCustomWidgetInterface +{ + Q_INTERFACES(QDesignerCustomWidgetInterface) +public: + ActionSelectorPlugin() + { + } + QWidget *createWidget(QWidget *parent) + { + return new Gui::ActionSelector(parent); + } + QString group() const + { + return QLatin1String("Input Widgets"); + } + QIcon icon() const + { + return QIcon( QPixmap( actionselector_pixmap ) ); + } + QString includeFile() const + { + return QLatin1String("Gui/Widgets.h"); + } + QString toolTip() const + { + return QLatin1String("Action Selector"); + } + QString whatsThis() const + { + return QLatin1String("A widget to select actions."); + } + bool isContainer() const + { + return false; + } + QString name() const + { + return QLatin1String("Gui::ActionSelector"); + } +}; + /* XPM */ static const char *iconview_pixmap[]={ "22 22 10 1", @@ -1061,6 +1134,7 @@ QList CustomWidgetPlugin::customWidgets () con cw.append(new LocationWidgetPlugin); cw.append(new FileChooserPlugin); cw.append(new AccelLineEditPlugin); + cw.append(new ActionSelectorPlugin); cw.append(new CommandIconViewPlugin); cw.append(new UIntSpinBoxPlugin); cw.append(new ColorButtonPlugin); diff --git a/src/Tools/updateTranslations.py b/src/Tools/updateTranslations.py index 5e3e991beb..695a2f6335 100755 --- a/src/Tools/updateTranslations.py +++ b/src/Tools/updateTranslations.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Library General Public License (LGPL) * diff --git a/src/Tools/wiki2qhelp.py b/src/Tools/wiki2qhelp.py index 09c47139aa..dc52f38152 100755 --- a/src/Tools/wiki2qhelp.py +++ b/src/Tools/wiki2qhelp.py @@ -2,7 +2,7 @@ #*************************************************************************** #* * -#* Copyright (c) 2009 Yorik van Havre * +#* Copyright (c) 2009 Yorik van Havre * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU Library General Public License (LGPL) * diff --git a/src/WindowsInstaller/LibPack.wxs b/src/WindowsInstaller/LibPack.wxs index cbe94cdc66..6121468927 100644 --- a/src/WindowsInstaller/LibPack.wxs +++ b/src/WindowsInstaller/LibPack.wxs @@ -71,6 +71,10 @@ + + + +